|
| 1 | +--- |
| 2 | +layout: news_post |
| 3 | +title: "Ruby 2.7.0 veröffentlicht" |
| 4 | +author: "naruse" |
| 5 | +translator: "Marvin Gülker" |
| 6 | +date: 2019-12-25 00:00:00 +0000 |
| 7 | +lang: de |
| 8 | +--- |
| 9 | + |
| 10 | +Wir freuen uns, die Veröffentlichung von Ruby 2.7.0 bekannt geben |
| 11 | +zu können. |
| 12 | + |
| 13 | +Sie enthält eine Anzahl neuer Funktionalitäten und |
| 14 | +Performanzverbesserungen, namentlich: |
| 15 | + |
| 16 | +* Musterabgleiche |
| 17 | +* Verbesserungen der interaktiven Kommandozeile _(REPL)_ |
| 18 | +* Defragmentierung für den GC _(Campaction GC)_ |
| 19 | +* Trennung der Positions- und der Schlüsselwortargumente |
| 20 | + |
| 21 | +## Musterabgleiche [Experimentell] |
| 22 | + |
| 23 | +Musterabgleiche sind eine häufig genutzte Funktion funktionaler |
| 24 | +Programmiersprachen. Mit 2.7.0 werden sie als experimentell in die |
| 25 | +Programmiersprache Ruby eingeführt. [#14912](https://bugs.ruby-lang.org/issues/14912) |
| 26 | + |
| 27 | +Ein Musterabgleich untersucht das übergebene Objekt und weist seinen |
| 28 | +Wert dann zu, wenn er auf ein bestimmtes Muster passt. |
| 29 | + |
| 30 | +{% highlight ruby %} |
| 31 | +require "json" |
| 32 | + |
| 33 | +json = <<END |
| 34 | +{ |
| 35 | + "name": "Alice", |
| 36 | + "age": 30, |
| 37 | + "children": [{ "name": "Bob", "age": 2 }] |
| 38 | +} |
| 39 | +END |
| 40 | + |
| 41 | +case JSON.parse(json, symbolize_names: true) |
| 42 | +in {name: "Alice", children: [{name: "Bob", age: age}]} |
| 43 | + p age #=> 2 |
| 44 | +end |
| 45 | +{% endhighlight %} |
| 46 | + |
| 47 | +Weitere Details können Sie der Präsentation [Musterabgleiche - Neue Funktion in Ruby 2.7](https://speakerdeck.com/k_tsj/pattern-matching-new-feature-in-ruby-2-dot-7) |
| 48 | +entnehmen. |
| 49 | + |
| 50 | +## Verbesserung der interaktiven Kommandozeile |
| 51 | + |
| 52 | +Die mitgelieferte interaktive Kommandozeile `irb` _(REPL: Read-Eval-Print-Loop)_ |
| 53 | +wird mehrzeiliges Editieren unterstützen. Dies wird mithilfe von |
| 54 | +`reline`, einer `readline`-kompatiblen nur mit Ruby implementierten Bibliothek, |
| 55 | +umgesetzt. Darüber hinaus wird `irb` besser mit RDoc integriert: es |
| 56 | +wird möglich, die Referenzdokumentation für eine bestimmte Klasse, |
| 57 | +ein bestimmtes Modul oder auch eine bestimmte Methode nachzuschlagen. |
| 58 | +[[Feature #14683]](https://bugs.ruby-lang.org/issues/14683), |
| 59 | +[[Feature #14787]](https://bugs.ruby-lang.org/issues/14787), |
| 60 | +[[Feature #14918]](https://bugs.ruby-lang.org/issues/14918) |
| 61 | + |
| 62 | +Schließlich werden von `Binding.irb` angezeigte Quellcode-Zeilen und |
| 63 | +Ergebnisse von `inspect` farblich hevorgehoben werden. |
| 64 | + |
| 65 | +<video autoplay="autoplay" controls="controls" muted="muted" width="576" height="259" poster="https://cache.ruby-lang.org/pub/media/irb-reline-screenshot.png"> |
| 66 | + <source src="https://cache.ruby-lang.org/pub/media/irb_improved_with_key_take3.mp4" type="video/mp4"> |
| 67 | +</video> |
| 68 | + |
| 69 | +## Defragmentierender GC |
| 70 | + |
| 71 | +Die neue Version wird einen defragmentierenden GC _(Compaction GC)_ |
| 72 | +einführen, der fragmentierten Arbeitsspeicherplatz defragmentieren |
| 73 | +kann. |
| 74 | + |
| 75 | +Einige Ruby-Programme, die mit mehreren Threads arbeiten, leiden |
| 76 | +derzeit unter Speicherfragmentierung. Dies verursacht einen hohen |
| 77 | +Speicherverbrauch und eine reduzierte Ausführungsgeschwindigkeit. |
| 78 | + |
| 79 | +Zur Behebung des Problems wird die neue Methode `GC.compact` |
| 80 | +eingeführt. Sie defragmentiert den Freispeicher _(Heap)_, indem sie |
| 81 | +noch aktive Objekte näher zusammenrückt, sodass weniger Speicherseiten |
| 82 | +benötigt werden und der Freispeicher insgesamt besser für |
| 83 | +Copy-on-Write (CoW) geeignet ist. [#15626](https://bugs.ruby-lang.org/issues/15626) |
| 84 | + |
| 85 | +## Trennung von Positions- und Schlüsselwortargumenten |
| 86 | + |
| 87 | +Die automatische Konvertierung zwischen Schlüsselwort- und |
| 88 | +Positionsargumenten gilt nun als veraltet und wird mit Ruby 3 entfernt |
| 89 | +werden. [[Feature #14183]](https://bugs.ruby-lang.org/issues/14183) |
| 90 | + |
| 91 | +Siehe den Artikel "[Trennung von Positions- und Schlüsselwortargumenten in Ruby 3.0](https://www.ruby-lang.org/de/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/)" |
| 92 | +für Details. Die Änderungen stellen sich wie folgt dar: |
| 93 | + |
| 94 | +* Wenn bei einem Methodenaufruf ein Hash als letztes Argument |
| 95 | + übergeben wird, wenn sonstige Argumente fehlen und wenn die |
| 96 | + aufgerufene Methode Schlüsselwortargumente annimmt, dann gibt Ruby |
| 97 | + eine Warnung aus. Um das Hash weiterhin als Schlüsselwortargument zu |
| 98 | + verwenden, ist es notwendig, den doppelten Auflösungsoperator |
| 99 | + _(double splat operator)_ zu benutzen. Nur so kann die Warnung |
| 100 | + vermieden und das korrekte Verhalten in Ruby 3 sichergestellt |
| 101 | + werden. |
| 102 | + |
| 103 | + ```ruby |
| 104 | + def foo(key: 42); end; foo({key: 42}) # Warnung |
| 105 | + def foo(**kw); end; foo({key: 42}) # Warnung |
| 106 | + def foo(key: 42); end; foo(**{key: 42}) # OK |
| 107 | + def foo(**kw); end; foo(**{key: 42}) # OK |
| 108 | + ``` |
| 109 | +
|
| 110 | +* Wenn bei einem Methodenaufruf Schlüsselwortargumente an eine |
| 111 | + Methode, die auch Schlüsselwortargumente akzeptiert, übergeben |
| 112 | + werden, jedoch nicht genügend Schlüsselwortargumente bereitgestellt |
| 113 | + werden, dann werden die übergebenen Schlüsselwortargumente als |
| 114 | + finales erforderliches Positionsargument gewertet und eine Warnung |
| 115 | + wird ausgegeben. Übergeben Sie das Argument als Hash statt als |
| 116 | + Schlüsselwortargumentliste, um die Warnung zu vermeiden und |
| 117 | + korrektes Verhalten in Ruby 3 sicherzustellen. |
| 118 | +
|
| 119 | + ```ruby |
| 120 | + def foo(h, **kw); end; foo(key: 42) # Warnung |
| 121 | + def foo(h, key: 42); end; foo(key: 42) # Warnung |
| 122 | + def foo(h, **kw); end; foo({key: 42}) # OK |
| 123 | + def foo(h, key: 42); end; foo({key: 42}) # OK |
| 124 | + ``` |
| 125 | +
|
| 126 | +* Wenn eine Methode bestimmte Schlüsselwortargumente, nicht aber den |
| 127 | + doppelten Auflösungsoperator verwendet, und ein Hash oder eine |
| 128 | + Schlüsselwortargumenteliste mit einer Mischung aus Strings und |
| 129 | + Symbolen übergeben wird, dann wird das Hash weiterhin aufgespalten. |
| 130 | + Zudem wird eine Warnung ausgegeben. Sie müssen für das korrekte |
| 131 | + Verhalten in Ruby 3 den aufrufenden Code so ändern, dass zwei |
| 132 | + einzelne Hashes übergeben werden. |
| 133 | +
|
| 134 | + ```ruby |
| 135 | + def foo(h={}, key: 42); end; foo("key" => 43, key: 42) # Warnung |
| 136 | + def foo(h={}, key: 42); end; foo({"key" => 43, key: 42}) # Warnung |
| 137 | + def foo(h={}, key: 42); end; foo({"key" => 43}, key: 42) # OK |
| 138 | + ``` |
| 139 | +
|
| 140 | +* Wenn eine Methode keine Schlüsselwortargumente akzeptiert, aber mit |
| 141 | + solchen aufgerufen wird, werden solche Schlüsselwortargumente |
| 142 | + weiterhin ohne Warnung als Hash für ein Positionsargument |
| 143 | + interpretiert. Dieses Verhalten wird auch in Ruby 3 weiterhin |
| 144 | + beibehalten. |
| 145 | +
|
| 146 | + ```ruby |
| 147 | + def foo(opt={}); end; foo( key: 42 ) # OK |
| 148 | + ``` |
| 149 | +
|
| 150 | +* Schlüsselwortargumente mit anderen Schlüsseln als Symbolen sind |
| 151 | + zulässig, wenn die Methode beliebige Schlüsselwortargumente |
| 152 | + akzeptiert. [[Feature #14183]](https://bugs.ruby-lang.org/issues/14183) |
| 153 | +
|
| 154 | + ```ruby |
| 155 | + def foo(**kw); p kw; end; foo("str" => 1) #=> {"str"=>1} |
| 156 | + ``` |
| 157 | +
|
| 158 | +* `**nil` kann genutzt werden, um in einer |
| 159 | + Methodendefinition ausdrücklich festzulegen, dass die Methode keine |
| 160 | + Schlüsselwörter akzeptiert. Der Aufruf einer solchen Methode mit |
| 161 | + Schlüsselwortargumenten erzeugt einen ArgumentError. [[Feature #14183]](https://bugs.ruby-lang.org/issues/14183) |
| 162 | +
|
| 163 | + ```ruby |
| 164 | + def foo(h, **nil); end; foo(key: 1) # ArgumentError |
| 165 | + def foo(h, **nil); end; foo(**{key: 1}) # ArgumentError |
| 166 | + def foo(h, **nil); end; foo("str" => 1) # ArgumentError |
| 167 | + def foo(h, **nil); end; foo({key: 1}) # OK |
| 168 | + def foo(h, **nil); end; foo({"str" => 1}) # OK |
| 169 | + ``` |
| 170 | +
|
| 171 | +* Die Übergabe einess leeren doppelten Auflösungsoperators an eine |
| 172 | + Methode, die keine Schlüsselwortargumente akzeptiert, führt nicht |
| 173 | + länger zur impliziten Übergabe eines leeren Hashes, es sei denn, das |
| 174 | + Hash ist wegen eines erforderlichen Parameters notwendig. |
| 175 | + In diesem Fall wird eine Warnung ausgegeben. Entfernen Sie den |
| 176 | + doppelten Auflösungsoperator, um ein Hash als Positionsargument zu |
| 177 | + übergeben. [[Feature #14183]](https://bugs.ruby-lang.org/issues/14183) |
| 178 | +
|
| 179 | + ```ruby |
| 180 | + h = {}; def foo(*a) a end; foo(**h) # [] |
| 181 | + h = {}; def foo(a) a end; foo(**h) # {} und Warnung |
| 182 | + h = {}; def foo(*a) a end; foo(h) # [{}] |
| 183 | + h = {}; def foo(a) a end; foo(h) # {} |
| 184 | + ``` |
| 185 | +
|
| 186 | +Wenn Sie die Veraltungswarnungen unterdrücken wollen, verwenden Sie |
| 187 | +bitte den Kommandozeilenschalter `-W:no-deprecated` oder fügen Ihrem |
| 188 | +Code den Befehl `Warning[:deprecated] = false` hinzu. |
| 189 | +
|
| 190 | +## Sonstige bemerkenswerte neue Funktionen |
| 191 | +
|
| 192 | +* Blockparameter werden für abgekürzten Zugriff automatisch nummeriert. |
| 193 | + [#4475](https://bugs.ruby-lang.org/issues/4475) |
| 194 | +
|
| 195 | +* Es werden anfangslose Range-Objekte eingeführt. Diese sind vielleicht nicht so |
| 196 | + nützlich wie endlose Range-Objekte, könnten aber für |
| 197 | + domänenspezifische Sprachen praktisch sein. |
| 198 | + [#14799](https://bugs.ruby-lang.org/issues/14799) |
| 199 | +
|
| 200 | + ```ruby |
| 201 | + ary[..3] # identical to ary[0..3] |
| 202 | + rel.where(sales: ..100) |
| 203 | + ``` |
| 204 | +
|
| 205 | +* `Enumerable#tally` wird hinzugefügt. Die Methode zählt das Vorkommen |
| 206 | + jedes Elements. |
| 207 | + |
| 208 | + ```ruby |
| 209 | + ["a", "b", "c", "b"].tally |
| 210 | + #=> {"a"=>1, "b"=>2, "c"=>1} |
| 211 | + ``` |
| 212 | + |
| 213 | +* Es ist jetzt zulässig, eine private Methode auf dem Schlüsselwort `self` aufzurufen. |
| 214 | + [[Feature #11297]](https://bugs.ruby-lang.org/issues/11297) |
| 215 | + [[Feature #16123]](https://bugs.ruby-lang.org/issues/16123) |
| 216 | + |
| 217 | + ```ruby |
| 218 | + def foo |
| 219 | + end |
| 220 | + private :foo |
| 221 | + self.foo |
| 222 | + ``` |
| 223 | + |
| 224 | +* `Enumerator::Lazy#eager` wird hinzugefügt. Diese Methode generiert |
| 225 | + einen nicht verzögertern Enumerator (_non-lazy enumerator_) aus |
| 226 | + einem verzögerten Enumerator (_lazy enumerator_). [[Feature #15901]](https://bugs.ruby-lang.org/issues/15901) |
| 227 | + |
| 228 | + ```ruby |
| 229 | + a = %w(foo bar baz) |
| 230 | + e = a.lazy.map {|x| x.upcase }.map {|x| x + "!" }.eager |
| 231 | + p e.class #=> Enumerator |
| 232 | + p e.map {|x| x + "?" } #=> ["FOO!?", "BAR!?", "BAZ!?"] |
| 233 | + ``` |
| 234 | + |
| 235 | +## Performanzverbesserungen |
| 236 | + |
| 237 | +* JIT [Experimentell] |
| 238 | + |
| 239 | + * JIT-kompilierter Code wird neu zu weniger optimiertem Code |
| 240 | + kompiliert, wenn eine Optimierungsannahme sich als falsch |
| 241 | + herausstellt. |
| 242 | + |
| 243 | + * Method-Inlining wird durchgeführt, wenn eine Methode als rein |
| 244 | + _(pure)_ gilt. Diese Optimierung ist noch experimentell und |
| 245 | + zahlreiche Methoden gelten noch nicht als rein. |
| 246 | + |
| 247 | + * Der Standardwert von `--jit-min-calls` wird von 5 auf 10.000 |
| 248 | + geändert. |
| 249 | + |
| 250 | + * Der Standardwert von `--jit-max-cache` wird von 1.000 auf 100 |
| 251 | + geändert. |
| 252 | + |
| 253 | +* Die Cache-Strategie von Fiber wurde verändert und die Erstellung von |
| 254 | + Fibers beschleunigt. |
| 255 | + [GH-2224](https://github.com/ruby/ruby/pull/2224) |
| 256 | + |
| 257 | +* `Module#name`, `true.to_s`, `false.to_s`, |
| 258 | + und `nil.to_s` geben jetzt immer einen eingefrorenen String zurück. Der |
| 259 | + zurückgegebene String ist für das jeweilige Objekt immer derselbe. |
| 260 | + [Experimenell] [[Feature #16150]](https://bugs.ruby-lang.org/issues/16150) |
| 261 | + |
| 262 | +* Die Performanz von `CGI.escapeHTML` wurde verbessert. [GH-2226](https://github.com/ruby/ruby/pull/2226) |
| 263 | + |
| 264 | +* Die Performanz von Monitor und MonitorMixin wurde verbessert. |
| 265 | + [[Feature #16255]](https://bugs.ruby-lang.org/issues/16255) |
| 266 | + |
| 267 | +* Der aufruferspezifische Methoden-Cache, den es seit etwa 1.9 gibt, |
| 268 | + wurde verbessert: die Rückgriffsrate auf den Cache konnte von |
| 269 | + 89% auf 94% erhöht werden. Siehe [GH-2583](https://github.com/ruby/ruby/pull/2583) |
| 270 | + |
| 271 | +* Die Methode RubyVM::InstructionSequence#to_binary generiert |
| 272 | + kompilierten Binärcode. Die Größe des Binärcodes wurde reduziert. |
| 273 | + [Feature #16163] |
| 274 | + |
| 275 | + |
| 276 | +## Sonstige bemerkenswerte Änderungen seit 2.6 |
| 277 | + |
| 278 | +* Einige Standardbibliotheken werden aktualisiert. |
| 279 | + * Bundler 2.1.2 |
| 280 | + ([Veröffentlichungshinweise](https://github.com/bundler/bundler/releases/tag/v2.1.2)) |
| 281 | + * RubyGems 3.1.2 |
| 282 | + * ([Veröffentlichungshinweise für 3.1.0](https://github.com/rubygems/rubygems/releases/tag/v3.1.0)) |
| 283 | + * ([Veröffentlichungshinweise für 3.1.1](https://github.com/rubygems/rubygems/releases/tag/v3.1.1)) |
| 284 | + * ([Veröffentlichungshinweise für 3.1.2](https://github.com/rubygems/rubygems/releases/tag/v3.1.2)) |
| 285 | + * Racc 1.4.15 |
| 286 | + * CSV 3.1.2 |
| 287 | + ([Neuigkeiten](https://github.com/ruby/csv/blob/v3.1.2/NEWS.md)) |
| 288 | + * REXML 3.2.3 |
| 289 | + ([Neuigkeiten](https://github.com/ruby/rexml/blob/v3.2.3/NEWS.md)) |
| 290 | + * RSS 0.2.8 |
| 291 | + ([Neuigkeiten](https://github.com/ruby/rss/blob/v0.2.8/NEWS.md)) |
| 292 | + * StringScanner 1.0.3 |
| 293 | + * Es werden auch einige Bibliotheken aktualisiert, die nicht über |
| 294 | + eine eigenständige Versionsnummer verfügen. |
| 295 | + |
| 296 | +* Die folgenden Programmbibliotheken sind nicht länger als mitgelieferte |
| 297 | + Gems enthalten. Installieren Sie die entsprechenden Gems, um diese |
| 298 | + Features zu verwenden. |
| 299 | + |
| 300 | + * CMath (Gem cmath) |
| 301 | + * Scanf (Gem scanf) |
| 302 | + * Shell (Gem shell) |
| 303 | + * Synchronizer (Gem sync) |
| 304 | + * ThreadsWait (Gem thwait) |
| 305 | + * E2MM (Gem e2mmap) |
| 306 | + |
| 307 | +* `profile.rb` wurde aus der Standardbibliothek entfernt. |
| 308 | + |
| 309 | +* Änderung von stdlib-Bibliotheken in Standard-Gems: |
| 310 | + * Die folgenden Standard-Gems wurden auf rubygems.org veröffentlicht: |
| 311 | + * benchmark |
| 312 | + * cgi |
| 313 | + * delegate |
| 314 | + * getoptlong |
| 315 | + * net-pop |
| 316 | + * net-smtp |
| 317 | + * open3 |
| 318 | + * pstore |
| 319 | + * singleton |
| 320 | + * Die folgenden Standard-Gems werden nur mit Rubys Kern, aber noch |
| 321 | + nicht auf rubygems.org veröffentlicht: |
| 322 | + * monitor |
| 323 | + * observer |
| 324 | + * timeout |
| 325 | + * tracer |
| 326 | + * uri |
| 327 | + * yaml |
| 328 | + |
| 329 | +* Die Nutzung von `Proc.new` und `proc` ohne Block in einer Methode, |
| 330 | + die einen Block erwartet, führt nun zu einer Warnung. |
| 331 | + |
| 332 | +* Die Nutzung von `lambda` ohne block in einer Methode, die einen |
| 333 | + Block erwartet, erzeugt einen Fehler. |
| 334 | + |
| 335 | +* Die Unicode- und Emoji-Version werden von 11.0.0 auf 12.0.0 angehoben. |
| 336 | + [[Feature #15321]](https://bugs.ruby-lang.org/issues/15321) |
| 337 | + |
| 338 | +* Die Unicode-Version wird auf 12.1.0 angehoben, um Unterstützung für |
| 339 | + U+32FF SQUARE ERA NAME REIWA zu erhalten. [[Feature #15195]](https://bugs.ruby-lang.org/issues/15195) |
| 340 | + |
| 341 | +* `Date.jisx0301`, `Date#jisx0301`, and `Date.parse` unterstützen die |
| 342 | + neue japanische Ära. |
| 343 | + [[Feature #15742]](https://bugs.ruby-lang.org/issues/15742) |
| 344 | + |
| 345 | +* Compiler müssen jetzt C99 unterstützen. |
| 346 | + [[Misc #15347]](https://bugs.ruby-lang.org/issues/15347) |
| 347 | + * Details zum genutzten Dialekt: |
| 348 | + <https://bugs.ruby-lang.org/projects/ruby-master/wiki/C99> |
| 349 | + |
| 350 | +Siehe die [NEWS](https://github.com/ruby/ruby/blob/v2_7_0/NEWS) |
| 351 | +oder die [Commit-Logs](https://github.com/ruby/ruby/compare/v2_6_0...v2_7_0) |
| 352 | +für weitere Details. |
| 353 | + |
| 354 | +{% assign release = site.data.releases | where: "version", "2.7.0" | first %} |
| 355 | +
|
| 356 | +Mit diesen Änderungen wurden [{{ release.stats.files_changed }} |
| 357 | +Dateien geändert, {{ release.stats.insertions }} Einfügungen(+), {{ release.stats.deletions }} Löschungen(-)](https://github.com/ruby/ruby/compare/v2_6_0...v2_7_0) |
| 358 | +seit Ruby 2.6.0! |
| 359 | + |
| 360 | +Frohe Weihnachten, schöne Ferien, und viel Spaß bei der Programmierung mit Ruby 2.7! |
| 361 | + |
| 362 | +## Download |
| 363 | + |
| 364 | +* <{{ release.url.bz2 }}> |
| 365 | + |
| 366 | + SIZE: {{ release.size.bz2 }} |
| 367 | + SHA1: {{ release.sha1.bz2 }} |
| 368 | + SHA256: {{ release.sha256.bz2 }} |
| 369 | + SHA512: {{ release.sha512.bz2 }} |
| 370 | + |
| 371 | +* <{{ release.url.gz }}> |
| 372 | + |
| 373 | + SIZE: {{ release.size.gz }} |
| 374 | + SHA1: {{ release.sha1.gz }} |
| 375 | + SHA256: {{ release.sha256.gz }} |
| 376 | + SHA512: {{ release.sha512.gz }} |
| 377 | + |
| 378 | +* <{{ release.url.xz }}> |
| 379 | + |
| 380 | + SIZE: {{ release.size.xz }} |
| 381 | + SHA1: {{ release.sha1.xz }} |
| 382 | + SHA256: {{ release.sha256.xz }} |
| 383 | + SHA512: {{ release.sha512.xz }} |
| 384 | + |
| 385 | +* <{{ release.url.zip }}> |
| 386 | + |
| 387 | + SIZE: {{ release.size.zip }} |
| 388 | + SHA1: {{ release.sha1.zip }} |
| 389 | + SHA256: {{ release.sha256.zip }} |
| 390 | + SHA512: {{ release.sha512.zip }} |
| 391 | + |
| 392 | +## Was ist Ruby |
| 393 | + |
| 394 | +Die Programmiersprache Ruby wurde 1993 von Yukihiro „Matz“ Matsumoto |
| 395 | +erfunden und wird heute als quelloffene Software entwickelt. Sie läuft |
| 396 | +auf verschiedenen Plattformen und wird überall auf der Welt namentlich |
| 397 | +für die Webentwicklung genutzt. |
0 commit comments