NetNewsWire/Parser/Tests/ParserTests/Resources/3960.json

642 lines
150 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"version": "https://jsonfeed.org/version/1.1",
"title": "fboës - Der Blog | Startseite",
"home_page_url": "https://journal.3960.org/",
"feed_url": "https://journal.3960.org/feed.json",
"description": "Programmierung, Luft- & Raumfahrt, Kurioses: Der Blog von und mit Frank Boës.",
"icon": "https://cdn.3960.org/favicon-192x192.png",
"favicon": "https://cdn.3960.org/images/tile-128x128.png",
"author": {
"name": "Frank Boës",
"url": "mailto:info@3960.org"
},
"authors": [
{
"name": "Frank Boës",
"url": "mailto:info@3960.org"
}
],
"language": "de-DE",
"_rss": {
"about": "http://cyber.harvard.edu/rss/rss.html",
"copyright": "© 2008-2020 Creative Commons BY"
},
"items": [
{
"id": "user/posts/2020-02-21-lecker-lecker/index.md",
"url": "https://journal.3960.org/posts/2020-02-21-lecker-lecker/",
"title": "Lecker, lecker",
"content_html": "<blockquote><p>Da ist es zwar nicht ganz billig,<br />dafür schmeckt&#39;s aber auch nicht.</p></blockquote><img src=\"https://stats.3960.org/p.php?idsite=8amp;action_name=Lecker%2C%20lecker&amp;url=https%3A%2F%2Fjournal.3960.org%2Fposts%2F2020-02-21-lecker-lecker%2F%3Futm_source%3Dnewsfeed_view\" style=\"border:0;\" alt=\"\" />",
"summary": "Da ist es zwar nicht ganz billig, dafür schmeckt's aber auch nicht.",
"date_published": "2020-02-21T18:08:06+01:00",
"date_modified": "2020-02-21T18:08:06+01:00",
"author": {
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
},
"authors": [
{
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
}
],
"banner_image": "https://cdn.3960.org/favicon-192x192.png",
"language": "de-DE",
"image": "https://cdn.3960.org/favicon-192x192.png",
"tags": [
"Lustiges"
]
},
{
"id": "user/posts/2020-02-10-sabine-flughafen-amsterdam/index.md",
"url": "https://journal.3960.org/posts/2020-02-10-sabine-flughafen-amsterdam/",
"title": "„Sabine“ am Flughafen Amsterdam",
"content_html": "<p><a href=\"https://en.wikipedia.org/wiki/METAR\" rel=\"nomention\">METAR</a>-Informationen sind nicht nur für die Fliegerei praktische und kompakte Möglichkeiten, Wetterbedingungen zusammenzufassen. Hier braust zum Beispiel am 09. Januar 2020 das Sturmtief „Sabine“ mit Windgeschwindigkeiten bis zu 51 Knoten über den Flughafen Amsterdam-Schiphol:</p>\n<pre><code class=\"language-metar\"><i title=\"Location\">EHAM</i> <span title=\"Day of month\">09</span><b title=\"Time\">1725Z</b> <span title=\"Wind direction\">200</span><b title=\"Wind speed\">37G51KT</b> 170V230 9999 <var title=\"Cloud\">FEW011</var> <var title=\"Cloud\">BKN014</var> <var title=\"Cloud\">BKN025</var> <b title=\"Temperature\">11</b>/<span title=\"Dewpoint\">11</span> <span title=\"Pressure\">Q0986</span> RE/RA TEMPO 7000</code></pre>\n<p>Solch einen METAR-Code kann z.B. mit dem <a href=\"https://journal.3960.org/posts/2019-03-27-wettergeraet-fuer-aerofly-fs2/\">Aerofly FS2 Wettergerät</a> verwendet werden.</p><img src=\"https://stats.3960.org/p.php?idsite=8amp;action_name=%E2%80%9ESabine%E2%80%9C%20am%20Flughafen%20Amsterdam&amp;url=https%3A%2F%2Fjournal.3960.org%2Fposts%2F2020-02-10-sabine-flughafen-amsterdam%2F%3Futm_source%3Dnewsfeed_view\" style=\"border:0;\" alt=\"\" />",
"summary": "METAR-Informationen sind nicht nur für die Fliegerei praktische und kompakte Möglichkeiten, Wetterbedingungen zusammenzufassen. Hier braust zum Beispiel am 09…",
"date_published": "2020-02-10T18:40:04+01:00",
"date_modified": "2020-02-11T08:51:21+01:00",
"author": {
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
},
"authors": [
{
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
}
],
"banner_image": "https://cdn.3960.org/favicon-192x192.png",
"language": "de-DE",
"image": "https://cdn.3960.org/favicon-192x192.png",
"tags": [
"Fliegerei",
"Simulation"
]
},
{
"id": "user/posts/2020-01-19-migrants/index.md",
"url": "https://journal.3960.org/posts/2020-01-19-migrants/",
"title": "Migrants",
"content_html": "<div class=\"video-player video-player--youtube\"><iframe allowfullscreen=\"allowfullscreen\" title=\"https://www.youtube.com/watch?v=G2dGWH90aew\" src=\"https://www.youtube-nocookie.com/embed/G2dGWH90aew?enablejsapi=1\" srcdoc=\"&lt;style&gt;*{padding:0;margin:0;overflow:hidden}html,body{height:100%}img,span{position:absolute;width:100%;top:0;bottom:0;margin:auto}span{height:1.5em;text-align:center;font:48px/1.5 sans-serif;color:white;text-shadow:0 0 0.5em black}&lt;/style&gt;&lt;a href=&quot;https://www.youtube.com/embed/G2dGWH90aew?autoplay=1&quot;&gt;&lt;img src=&quot;https://img.youtube.com/vi/G2dGWH90aew/hqdefault.jpg&quot; alt=&quot;&quot;&gt;&lt;span&gt;▶&lt;/span&gt;&lt;/a&gt;\"></iframe><!-- img src=\"https://img.youtube.com/vi/G2dGWH90aew/hqdefault.jpg\" --></div><img src=\"https://stats.3960.org/p.php?idsite=8amp;action_name=Migrants&amp;url=https%3A%2F%2Fjournal.3960.org%2Fposts%2F2020-01-19-migrants%2F%3Futm_source%3Dnewsfeed_view\" style=\"border:0;\" alt=\"\" />",
"summary": "",
"date_published": "2020-01-19T18:09:37+01:00",
"date_modified": "2020-01-19T18:09:37+01:00",
"author": {
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
},
"authors": [
{
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
}
],
"banner_image": "https://img.youtube.com/vi/G2dGWH90aew/hqdefault.jpg",
"language": "de-DE",
"image": "https://img.youtube.com/vi/G2dGWH90aew/hqdefault.jpg",
"tags": [
"Geckobar",
"Raumfahrt",
"The Cool"
]
},
{
"id": "user/posts/2019-12-30-ssh-schluessel-unter-windows-komplett/index.md",
"url": "https://journal.3960.org/posts/2019-12-30-ssh-schluessel-unter-windows-komplett/",
"title": "SSH-Schlüssel unter Windows das komplette Programm",
"content_html": "<p><img src=\"https://journal.3960.org/posts/2019-12-30-ssh-schluessel-unter-windows-komplett/puttygen-240x240.png\" class=\"quad\" width=\"240\" height=\"240\" style=\"--aspect-ratio: 240/240;\" alt=\"\" /> SSH-Schlüssel sind die Eintrittskarte für SSH, Git, und viele andere darauf aufbauende, nützliche Dienste, die ein Programmierer nutzen möchte. Während unter Linux und Mac OSX das Erzeugen eines SSH-Schlüssels eine schmerzlose Sache ist, sind unter Windows mehr Handgriffe gefragt, um <em>alle</em> Anwendungsfälle eines SSH-Schlüssels abbilden zu können unter anderem für die Verwendung des selben Schlüssels aus einer Virtualisierung wie zum Beispiel VirtualBox oder Docker.</p>\n<!-- more -->\n<p id=\"more\">Generell gibt es zwei Arten, unter Windows einen SSH-Schlüssel zu speichern:</p>\n<ul>\n<li>Das <i>PuTTY Private Key</i>-Format (<code>ppk</code>)</li>\n<li>Das unter UNIX bekannte OpenSSH-Format mit zwei Dateien für den privaten und öffentlichen Teil des Schlüssels</li>\n</ul>\n<p>Viele Anleitungen beschränken sich auf <a href=\"https://www.ssh.com/ssh/putty/windows/puttygen\" rel=\"nomention\">die eine</a> oder <a href=\"https://help.github.com/en/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent\" rel=\"nomention\">andere Methode zum Anlegen von SSH-Schlüsseln</a>. Tatsächlich macht es aber unter Windows sehr viel Sinn, den eigenen Schlüssel in <em>beiden</em> Formate verfügbar zu haben. Das geht deutlich schmerzloser, wenn beide Schlüsselformate in einem Aufwasch angelegt werden.</p>\n<ol>\n<li>Zuallererst werden die <a href=\"https://putty.org/\" rel=\"nomention\">PuTTY Utilities</a> installiert diese beinhalten neben PuTTY auch den <code>puttygen</code> Schlüsselgenerator, <code>pageant</code> Schlüsselagenten und das <code>plink</code> SSH-Verbindungstool.</li>\n<li>Ebenfalls wird <a href=\"https://git-scm.com/\" rel=\"nomention\">Git für Windows</a> benötigt hier ist wiederum Git Bash enthalten, einen Linux-Bash-Emulator.</li>\n<li>Im nächsten Schritt muss Git Bash geöffnet werden und im eigenen Benutzerverzeichnis das SSH-Schlüsselverzeichnis mittels <code>mkdir -p ~/.ssh</code> angelegt werden.</li>\n<li>Jetzt wird PuTTYGen gestartet, um in dem just angelegten Verzeichnis (unter <code>C:\\Users\\USERNAME\\.ssh</code>) die insgesamt drei Dateien anzulegen, die zusammen alle Schlüssel-Komponenten darstellen.</li>\n</ol>\n<h2 id=\"puttygen\">PuTTYGen</h2>\n<p>In PuttyGen selber wird es nun etwas trickreich:</p>\n<ol>\n<li>Als „Key comment“ gibt wird die eigene E-Mail-Adresse verwendet. Das hilft später bei der Identifikation des Schlüssels.</li>\n<li>Außerdem sollte eine Passphrase vergeben werden, die den Schlüssel schützt, falls die Schlüsseldateien abhanden kommen sollten.</li>\n<li>Nicht zuletzt sollte bei der Bitlänge des Schlüssel entweder 2048 oder aber gleich 4096 verwendet werden.</li>\n<li>Nun drückt ihr den Knopf „Generate“ und wischt mit der Maus über dem PuTTYGen-Fenster hin und her, um ein Zufallsmuster zu erzeugen. Im Anschluss hat das Programm einen Schlüssel generiert, den ihr wie folgt speichern müsst:</li>\n<li>Die PPK-Datei mittels „File → Save private key“ in <code>C:\\Users\\USERNAME\\.ssh\\id_rsa.ppk</code> speichern.</li>\n<li>Aus der oberen Textbox von PuTTYGen den „OpenSSH Public Key“ kopieren und in eine neue Datei in <code>C:\\Users\\USERNAME\\.ssh\\id_rsa.pub</code> einfügen (mit der Funktion „Save public key“ wird der Public Key nicht im korrekten Format exportiert).</li>\n<li>Mit „Conversions → Export OpenSSH key“ den Private Key unter <code>C:\\Users\\USERNAME\\.ssh\\id_rsa</code> speichern. Wichtig ist hierbei, dass keine Dateiendung verwendet wird.</li>\n</ol>\n<p>In eurem SSH-Verzeichnis <code>C:\\Users\\USERNAME\\.ssh</code> sollten nun mindestens drei Dateien liegen:</p>\n<pre><code class=\"language-bash\">id_rsa.ppk <u># Privater / öffentlicher Schlüssel für PuTTY</u>\nid_rsa.pub <u># Öffentlicher Schlüssel für OpenSSH</u>\nid_rsa <u># Privater Schlüssel für OpenSSH</u></code></pre>\n<p>Später werden in diesem Verzeichnis ggf. noch mehr Dateien auftauchen, wie z.B. <code>known_hosts</code>, <code>authorized_keys</code> und <a href=\"https://journal.3960.org/posts/2017-11-18-bookmark-manager-fuer-ssh-zugangsdaten/\"><code>config</code></a>.</p>\n<p>Übrigens solltet ihr mit der Git Bash mittels <code>chmod 644 ~/.ssh/* &amp;&amp; chmod 600 ~/.ssh/id_rsa</code> allen Dateien die korrekten Zugriffsrechte (<code>-rw-r--r--</code> bzw. <code>-rw-------</code>) geben, falls dies nicht schon geschehen ist.</p>\n<h2 id=\"verbindung-bitte\">Verbindung, bitte</h2>\n<p>Den öffentlichen Schlüssel könnt ihr nun auf allen Servern und Diensten bekannt machen, mit denen ihr euch später verbinden wollt. Auf eurem Rechner wiederum wird die Git Bash automatisch den privaten OpenSSH-Schlüssel verwenden, während andere Programme den privaten Schlüssel aus der <code>id_rsa.ppk</code> entweder in den Einstellungen übergeben bekommen müssen, oder aber aus einem vorher zu startenden <code>pageant</code> Schlüsselagenten übernehmen können. Falls ihr SSH-Schlüssel für eure tägliche Arbeit benutzt, könnt ihr den <a href=\"https://blog.shvetsov.com/2010/03/making-pageant-automatically-load-keys.html\">Pageant auch automatisch starten und den Schlüssel laden lassen</a>.</p>\n<p>Viele Windows-Programme können so euren SSH-Schlüssel nutzen, u.a.:</p>\n<ul>\n<li>PuTTY</li>\n<li>PhpStorm</li>\n<li>WinSCP</li>\n<li>HeidiSQL (für SSH-Tunnel)</li>\n<li>Sourcetree (via „Tools → Options → General → SSH-Client Configuration“)</li>\n<li>Visual Studio Code (wenn auch die <a href=\"https://journal.3960.org/posts/2018-09-19-umstieg-auf-microsoft-visual-studio-code/\">Einrichtung der SSH-Schlüssel in <i>Visual Studio Code</i> ein bisschen umständlich ist</a>)</li>\n</ul>\n<p>So oder so seid ihr nun mit beiden Schlüsselformaten ausgestattet, so dass z.B. auch der Wechsel des Betriebssystems oder die Verwendung von Virtualisierung euch die Weiterbenutzung eures SSH-Schlüssels erlaubt.</p>\n<p>Unter Linux und Mac OSX ist der Vorgang übrigens etwas kürzer:</p>\n<pre><code class=\"language-bash\">ssh-keygen <em>-t</em> rsa <em>-b</em> 4096 <em>-C</em> <kbd>&quot;YOUR@EMAIL&quot;</kbd></code></pre><img src=\"https://stats.3960.org/p.php?idsite=8amp;action_name=SSH-Schl%C3%BCssel%20unter%20Windows%20%E2%80%93%20das%20komplette%20Programm&amp;url=https%3A%2F%2Fjournal.3960.org%2Fposts%2F2019-12-30-ssh-schluessel-unter-windows-komplett%2F%3Futm_source%3Dnewsfeed_view\" style=\"border:0;\" alt=\"\" />",
"summary": "SSH-Schlüssel sind die Eintrittskarte für SSH, Git, und viele andere darauf aufbauende, nützliche Dienste, die ein Programmierer nutzen möchte. Während unter…",
"date_published": "2019-12-30T18:52:10+01:00",
"date_modified": "2020-01-11T10:00:49+01:00",
"author": {
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
},
"authors": [
{
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
}
],
"banner_image": "https://journal.3960.org/posts/2019-12-30-ssh-schluessel-unter-windows-komplett/puttygen.png",
"language": "de-DE",
"image": "https://journal.3960.org/posts/2019-12-30-ssh-schluessel-unter-windows-komplett/puttygen.png",
"tags": [
"Für Tumblr",
"Programmierung",
"Webdevelop",
"Git",
"Bash",
"Anleitung"
]
},
{
"id": "user/posts/2019-12-22-firefox-weniger-werbung-mehr-speed-unter-android/index.md",
"url": "https://journal.3960.org/posts/2019-12-22-firefox-weniger-werbung-mehr-speed-unter-android/",
"title": "Firefox Weniger Werbung, mehr Speed unter Android",
"content_html": "<p><img src=\"https://journal.3960.org/posts/2019-12-22-firefox-weniger-werbung-mehr-speed-unter-android/firefox-240x240.png\" class=\"quad\" width=\"240\" height=\"240\" style=\"--aspect-ratio: 240/240;\" alt=\"\" /> Werbung nervt. Tracking nervt. Nerven nervt. Und gerade mobil habe ich eigentlich keine Zeit, meine geringe Download-Rate mit dem Herunterladen von hässlichen Werbemitteln zu verbringen. Aber welche Optionen hat man schon auf einem Smartphone?</p>\n<!-- more -->\n<p id=\"more\">Schon vor einiger Zeit war ich auf <a href=\"https://journal.3960.org/posts/2017-10-31-mobiles-surfen-ohne-werbung/\">Firefox für Android</a> gestoßen. Da ich schon immer ein Herz für Mozilla hatte und Firefox einer der wenigen Browser unter Android war, in dem ein AdBlocker funktionierte, war ich von Chrome für Android auf Firefox für Android umgestiegen.</p>\n<blockquote><p>Oh, ein Nerd-Telefon! Android, Firefox und DuckDuckGo.</p></blockquote>\n<p>Ein <a href=\"https://www.duden.de/rechtschreibung/Wermutstropfen\">Wermutstropfen</a> hatte Firefox für Android aber: Im Vergleich zu Android-Chrome war er nicht wirklich schnell. Das fiel augenscheinlich auch Mozilla auf, so dass sich in der stetig vergrößernden Palette an <a href=\"https://play.google.com/store/apps/dev?id=7083182635971239206\">Mozillas Android-Apps</a> eine neue Version von Firefox für Android findet: <a href=\"https://play.google.com/store/apps/details?id=org.mozilla.fenix\">Mozilla Firefox Preview</a>.</p>\n<p>Von seinem Vorgänger unterscheidet <i>Firefox Preview</i> neben einer etwas kompakteren Oberfläche vor allen Dingen seine rasante Geschwindigkeit. Und das man (aktuell) keine Plugins installieren kann ist sofort vergessen, denn der eingebaute AdBlocker (Enhanced Tracking Protection bzw. <i>ETP</i> genannt) funktioniert einfach fantastisch (so das meine Bastelei für <a href=\"https://journal.3960.org/posts/2015-07-02-fritz-box-als-adblocker/\">den FritzBox-AdBlocker</a> für <em>diesen</em> Browser überflüssig wird).</p>\n<p><span class=\"figure quad\"><img src=\"https://journal.3960.org/posts/2019-12-22-firefox-weniger-werbung-mehr-speed-unter-android/firefox-blocked-240x240.png\" class=\"quad\" width=\"240\" height=\"240\" style=\"--aspect-ratio: 240/240;\" alt=\"Neulich auf einer ganz normalen Nachrichtenseite.\" /><span class=\"figcaption\" aria-hidden=\"true\">Neulich auf einer ganz normalen Nachrichtenseite.<br /></span></span> Nebenbei kann der Firefox Preview auch den Webview auf Android ersetzen. Damit sind <em>alle</em> Apps auf dem Telefon, die Webview verwenden, nicht nur mit der Rendering-Engine sondern auch mit dem AdBlocker von Firefox Preview ausgestattet.</p>\n<p>Nicht zuletzt ist in Firefox Preview der Dienst „Firefox Sync“ eingebaut. Sobald man sich einen kostenlosen <a href=\"https://www.mozilla.org/de/firefox/accounts/\">Firefox Account</a> zugelegt hat, können alle anderen mit diesem Account registrierten Firefox-Browser Historie und Lesezeichen teilen. Damit ist das Erlebnis wie bei Google Chrome mit aktivierten Google Account.</p>\n<p>Übrigens: Mozillas Bemühen um neue Privatsphären-Services hat <a href=\"https://monitor.firefox.com/\">Firefox Monitor</a> hervorgebracht. Mit einem Firefox-Account kann man sich so informieren lassen, ob die eigene E-Mail-Adresse von einem Datenleck betroffen ist. Ein sinnvoller Service, der mich zum Beispiel darauf gebracht hat, dass einige von mir benutzte Dienste meine E-Mail-Adresse nebst Passwort-Hash verloren hatten und merkwürdigerweise ein <em>nicht</em> von mir benutzter Dienst, womit sich hier möglicherweise der Kreis zum Trackingschutz von Mozilla Firefox schließt. <span class=\"emoji emoji--1f609\" title=\";)\">&#x1F609;</span></p><img src=\"https://stats.3960.org/p.php?idsite=8amp;action_name=Firefox%20%E2%80%93%20Weniger%20Werbung%2C%20mehr%20Speed%20unter%20Android&amp;url=https%3A%2F%2Fjournal.3960.org%2Fposts%2F2019-12-22-firefox-weniger-werbung-mehr-speed-unter-android%2F%3Futm_source%3Dnewsfeed_view\" style=\"border:0;\" alt=\"\" />",
"summary": "Werbung nervt. Tracking nervt. Nerven nervt. Und gerade mobil habe ich eigentlich keine Zeit, meine geringe Download-Rate mit dem Herunterladen von hässlichen…",
"date_published": "2019-12-22T18:33:43+01:00",
"date_modified": "2020-01-07T10:31:04+01:00",
"author": {
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
},
"authors": [
{
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
}
],
"banner_image": "https://journal.3960.org/posts/2019-12-22-firefox-weniger-werbung-mehr-speed-unter-android/firefox.png",
"language": "de-DE",
"image": "https://journal.3960.org/posts/2019-12-22-firefox-weniger-werbung-mehr-speed-unter-android/firefox.png",
"tags": [
"Für Tumblr",
"Geckobar",
"Review",
"Technologie",
"Webdevelop",
"Adblocker"
]
},
{
"id": "user/posts/2019-10-27-event-handling-mit-javascript-ohne-jquery/index.md",
"url": "https://journal.3960.org/posts/2019-10-27-event-handling-mit-javascript-ohne-jquery/",
"title": "Event-Handling mit JavaScript und ohne jQuery",
"content_html": "<p><img src=\"https://journal.3960.org/posts/2019-10-27-event-handling-mit-javascript-ohne-jquery/event-240x240.png\" class=\"quad\" width=\"240\" height=\"240\" style=\"--aspect-ratio: 240/240;\" alt=\"\" /> Als Web-Entwickler fügen wir im Laufe eines Projektes einer Website eine zumeist nicht unerhebliche Anzahl an JavaScript-Event-Handlern hinzu sei es mit jQuery oder regulärem JavaScript (<a href=\"http://youmightnotneedjquery.com/\">You Might Not Need jQuery</a>). Abhängig von der gewählten Methode lässt sich damit… die Performance einer Website gründlich ruinieren.</p>\n<p>Aber das muss nicht sein wie dieser Überblick über die Montage von Event-Handlern in JavaScript / jQuery zeigt.</p>\n<!-- more -->\n<p id=\"more\">Ganz grundsätzlich muss jeder Prozessschritt beim Hinzufügen eines Event-Handlers richtig angewendet werden. Der ganze Vorgang besteht aus drei Schritten:</p>\n<ol>\n<li>Die DOM-Elemente <strong>selektieren</strong>,</li>\n<li>auf dem selektierten DOM-Elementen einen <strong>Event-Typ</strong> beobachten,</li>\n<li>und schließlich bei Auslösen des Events einen <strong>Event-Listener</strong> ausführen.</li>\n</ol>\n<p>In jedem dieser Schritte lässt sich zum Teil massiv optimieren.</p>\n<h2 id=\"kenne-deine-selektoren\">Kenne deine Selektoren</h2>\n<p>Um einen Event-Handler montieren zu können, muss dieser an ein Element angekoppelt werden in der Regel ist dies ein DOM-Element. Dazu gibt es verschiedene Methoden, DOM-Elemente zu selektieren. Je nach gewählter Methode ist dies mehr oder weniger performant.</p>\n<blockquote><p>Faustformel: Je eindeutiger das Suchmerkmal und je kleiner die Menge der zu durchsuchenden Elemente, desto schneller ist die Suche.</p></blockquote>\n<p>Die <a href=\"https://jsperf.com/getelementbyid-vs-queryselector/304\">schnellste Methode ist dabei die Selektion über ein <code>id</code>-Attribut</a> die langsamste dagegen die Suche nach einem beliebigen Attribut, im schlimmsten Fall mit der Prüfung, ob dieses Attribut einen bestimmten Wert beinhaltet.</p>\n<div class=\"table-wrapper\"><table>\n<caption id=\"dom-selektions-methoden-sortiert-nach-performance\">DOM-Selektions-Methoden, sortiert nach Performance</caption>\n<thead>\n<tr>\n<th>Methode</th>\n<th>jQuery</th>\n<th>JavaScript</th>\n<th>Neues JavaScript</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>ID</td>\n<td><code>$(&#39;#x&#39;)</code></td>\n<td><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById\"><code>document.getElementById(&#39;x&#39;)</code></a></td>\n<td><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector\"><code>document.querySelector(&#39;#x&#39;)</code></a></td>\n</tr>\n<tr>\n<td>Klasse</td>\n<td><code>$(&#39;.x&#39;)</code></td>\n<td><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName\"><code>document.getElementsByClassName(&#39;x&#39;)</code></a></td>\n<td><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll\"><code>document.querySelectorAll(&#39;.x&#39;)</code></a></td>\n</tr>\n<tr>\n<td>Tag</td>\n<td><code>$(&#39;x&#39;)</code></td>\n<td><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByTagName\"><code>document.getElementsByTagName(&#39;x&#39;)</code></a></td>\n<td><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll\"><code>document.querySelectorAll(&#39;x&#39;)</code></a></td>\n</tr>\n<tr>\n<td>Attribut</td>\n<td><code>$(&#39;[x]&#39;)</code></td>\n<td>n/a</td>\n<td><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll\"><code>document.querySelectorAll(&#39;[x]&#39;)</code></a></td>\n</tr>\n<tr>\n<td>CSS (s.u.)</td>\n<td><code>$(&#39;x y&#39;)</code></td>\n<td>n/a</td>\n<td><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll\"><code>document.querySelectorAll(&#39;x y&#39;)</code></a></td>\n</tr>\n</tbody></table></div>\n<p>Sowohl die jQuery-Methode <code>$(…)</code> als auch die JavaScript-Methoden <code>.querySelector()</code> / <code>.querySelectorAll()</code> unterstützen die Auswahl per CSS-Selektor. Damit können auch kompliziertere Suchen im DOM durchgeführt werden, wie z.B. mit <code>nav a</code> das Auffinden aller <code>&lt;a&gt;</code> in einem <code>&lt;nav&gt;</code>. Zum Glück ist die <a href=\"https://caniuse.com/#search=queryselector\">Browser-Unterstützung für <code>.querySelector()</code> / <code>.querySelectorAll()</code></a> inzwischen sehr gut. </p>\n<p>Zu beachten ist, dass die JavaScript-Methoden <code>.querySelector()</code> / <code>.querySelectorAll()</code> je nach Browser <a href=\"https://jsperf.com/getelementbyid-vs-queryselector/304\" title=\"Vergleich der verschiedenen JavaScript-Selektor-Methoden\">um ein Mehrfaches langsamer sind</a> als ihre „einfachen“ Geschwister <code>.getElementById</code>, <code>.getElementsByClassName</code> und <code>.getElementsByTagName</code>. </p>\n<h3 id=\"mengenlehre-selektieren-in-der-selektion\">Mengenlehre: Selektieren in der Selektion</h3>\n<p>Interessanterweise kann jede Methode nicht nur auf das gesamte Dokument angewendet werden, sondern auf eine bereits bestehende Selektion. Damit kann die Suche stark beschleunigt werden.</p>\n<p>In jQuery existiert dafür die <code>.find()</code>-Methode, die analog zu <code>.on()</code> funktioniert…</p>\n<pre><code class=\"language-javascript\"><b>var</b> navigation = $(<kbd>'nav'</kbd>);\n<b>var</b> navLinks = navigation.find(<kbd>'a'</kbd>);\n<b>var</b> navBolds = navigation.find(<kbd>'b'</kbd>);</code></pre>\n<p>…in regulärem JavaScript bleiben die Methoden identisch zu den für die Suche im Dokument verfügbaren Methoden:</p>\n<pre><code class=\"language-javascript\"><b>var</b> navigation = document.querySelector(<kbd>'nav'</kbd>);\n<b>var</b> navLinks = navigation.querySelectorAll(<kbd>'a'</kbd>);\n<b>var</b> navBolds = navigation.querySelectorAll(<kbd>'b'</kbd>);</code></pre>\n<p>Diese Methode kann sehr hilfreich sein, wenn später sowieso DOM-Manipulation an übergeordneten DOM-Elementen notwendig werden.</p>\n<p>Zu beachten ist bei regulärem JavaScript, dass die Methoden <code>.getElementById()</code> und <code>.querySelector()</code> ein einzelnes <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Element\"><code>Element</code></a> bzw. einen einzelnen <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Node\"><code>Node</code></a> (d.h. <em>ein</em> DOM-Element) zurückgeben, während alle anderen Selektions-Methoden eine <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection\"><code>HTMLCollection</code></a> bzw. <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/NodeList\"><code>NodeList</code></a> zurückgeben, die vereinfacht gesagt Arrays von <code>Node</code>s sind.</p>\n<h2 id=\"event-handler-hinzufügen\">Event-Handler hinzufügen</h2>\n<p>Für das Hinzufügen von Event-Listenern bietet <a href=\"https://api.jquery.com/on/\">jQuery die Methode <code>.on()</code></a>, und <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener\">JavaScript die Methode <code>.addEventListener()</code></a> an. (Wir ignorieren die Methoden zum Hinzufügen von Event-Handlern direkt via HTML-Attribut, da dadurch eine unglückliche Verkettung von Content (HTML) und Verhalten (JavaScript) entsteht.)</p>\n<p>In beiden Fällen verfügt die Selektion über eine Methode, der man nur den <strong>Event-Typ</strong> und den eigentlichen <strong>Event-Listener</strong> übergeben muss.</p>\n<pre><code class=\"language-javascript\">$(<kbd>'nav'</kbd>).on(<kbd>'click'</kbd>, <b>function</b>() {\n $(<i>this</i>).addClass(<kbd>'active'</kbd>);\n})</code></pre>\n<p>Der selbe Aufruf ist in Vanilla-JavaScript etwas mehr Schreibarbeit, aber ansonsten identisch:</p>\n<pre><code class=\"language-javascript\">document.querySelector(<kbd>'nav'</kbd>).addEventListener(<kbd>'click'</kbd>, <b>function</b>(event) {\n event.target.classList.add(<kbd>'active'</kbd>);\n});</code></pre>\n<p>Zu beachten in JavaScript: Event-Listener können nur einem <em>einzelnen</em> DOM-Element hinzugefügt werden jQuery erlaubt es, am Stück <em>mehreren</em> DOM-Elementen ein und denselben Event-Listener hinzuzufügen.</p>\n<p>In beiden Fällen steht im Event-Listener mit <code>$(this)</code> bzw. <code>event.target</code> das DOM-Element direkt zur Verfügung, auf dem das Event ausgelöst wurde. Voraussetzung ist bei JavaScript, dass der Event-Listener als ersten Parameter eine Variable namens <code>event</code> gesetzt bekommen hat.</p>\n<h3 id=\"sieben-event-typen-auf-einen-streich\">Sieben Event-Typen auf einen Streich…</h3>\n<p>Ein nicht unwahrscheinlicher Anwendungsfall ist, verschiedene Event-Typen mit dem selben Event-Handler bedienen zu wollen. In jQuery kann man an die <code>.on()</code>-Methode eine Liste an verschiedenen Event-Typen übergeben:</p>\n<pre><code class=\"language-javascript\"><u>// Fires on `click` `keyup` `blur`</u>\n$(<kbd>'nav'</kbd>).on(<kbd>'click keyup blur'</kbd>, <b>function</b>() {\n $(<i>this</i>).addClass(<kbd>'active'</kbd>);\n})</code></pre>\n<p>In JavaScript ist ein bisschen mehr Gehirnschmalz notwendig, denn hier müssen wir jeden Event-Listener mit einem einzelnen Aufruf hinzufügen. Das könnte man in einer Schleife tun…</p>\n<pre><code class=\"language-javascript\"><u>// Bad example: Fires on `click` `keyup` `blur`</u>\n[<kbd>'click'</kbd>, <kbd>'keyup'</kbd>, <kbd>'blur'</kbd>].<i>forEach</i>(<b>function</b>(eventType) {\n document.querySelector(<kbd>'nav'</kbd>).addEventListener(eventType, <b>function</b>(event) {\n event.target.classList.add(<kbd>'active'</kbd>);\n });\n});</code></pre>\n<p>…und handelt sich auf diese Weise zwei Performance-Killer ein: Einerseits wird in jedem Schleifendurchlauf <code>document.querySelector</code> neu ausgewertet, andererseits wird jedes Mal Speicher für eine neue, anonyme Funktion reserviert. Glücklicherweise kann man beide Konstruktionen aus dem Schleifenkörper herausziehen:</p>\n<pre><code class=\"language-javascript\"><u>// Better example: Fires on `click` `keyup` `blur`</u>\n<b>var</b> eventTarget = document.querySelector(<kbd>'nav'</kbd>);\n<b>var</b> eventListener = <b>function</b>(event) {\n event.target.classList.add(<kbd>'active'</kbd>);\n};\n\n[<kbd>'click'</kbd>, <kbd>'keyup'</kbd>, <kbd>'blur'</kbd>].<i>forEach</i>(<b>function</b>(eventType) {\n eventTarget.addEventListener(eventType, eventListener);\n});</code></pre>\n<p>Das Array abgerollt sieht dann sogar noch übersichtlicher aus, und zeigt plastisch den Vorteil der vorherigen Deklaration von Event-Ziel und -Listener:</p>\n<pre><code class=\"language-javascript\"><u>// Best example for readability: Fires on `click` `keyup` `blur`</u>\n<b>var</b> eventTarget = document.querySelector(<kbd>'nav'</kbd>);\n<b>var</b> eventListener = <b>function</b>(event) {\n event.target.classList.add(<kbd>'active'</kbd>);\n};\n\neventTarget.addEventListener(<kbd>'click'</kbd>, eventListener);\neventTarget.addEventListener(<kbd>'keyup'</kbd>, eventListener);\neventTarget.addEventListener(<kbd>'blur'</kbd>, eventListener);</code></pre>\n<h3 id=\"weniger-ist-weniger\">Weniger ist… weniger</h3>\n<p>Wenn sich auf einer Seite <em>mehrere</em> DOM-Objekte befinden, die wir mit einem identischen Event-Handler ausstatten wollen, so gibt es in jQuery die folgende Methode.</p>\n<pre><code class=\"language-javascript\"><u>// Add Event Handler to all `.btn`</u>\n$(<kbd>'.btn'</kbd>).on(<kbd>'click'</kbd>, <b>function</b>() {\n $(<i>this</i>).addClass(<kbd>'active'</kbd>);\n})</code></pre>\n<p>Besonders spannend: Bei <code>.on()</code> und <code>.querySelectorAll()</code> können auch <em>mehrere</em> CSS-Selektoren, durch Kommata getrennt, gleichzeitig abgefragt werden. Mit <code>header a, footer a</code> kriegt man eine Liste aller <code>&lt;a&gt;</code> in <code>&lt;header&gt;</code> und <code>&lt;footer&gt;</code> zurück.</p>\n<p>In Vanilla-JavaScript wird das Hinzufügen zu Event-Listenern zu mehreren DOM-Elementen etwas umständlicher, weil ein Event-Handler immer nur <em>einem</em> DOM-Objekt hinzugefügt werden kann. Wenn wir also eine Liste von DOM-Objekten haben, müssen wir jedem DOM-Objekt beim Durchlaufen einer Schleife einen Handler verpassen:</p>\n<pre><code class=\"language-javascript\"><u>// Add Event Handler to all `.btn`</u>\ndocument.querySelectorAll(<kbd>'.btn'</kbd>).<i>forEach</i>(<b>function</b>(btn) {\n btn.addEventListener(<kbd>'click'</kbd>, <b>function</b>(event) {\n event.target.classList.add(<kbd>'active'</kbd>);\n });\n});</code></pre>\n<p>Warum ist das in JavaScript eigentlich so deutlich weniger bequem? Der Grund ist ganz einfach: Diese Konstruktion hat massive Performance-Auswirkungen. Wir fügen damit eine größere Anzahl von Event-Handlern hinzu, die alle das Gleiche tun, aber unterschiedliche DOM-Objekte beobachten müssen. Damit muss der Browser mehr Dinge beobachten. Bei einer 10×10 Zellen umfassenden Tabelle kann <em>ein</em> Event-Listener für eine Tabellenzelle also auf insgesamt 100 Events verteilt werden.</p>\n<p>Für diesen Fall bietet jQuery eine performante Alternative: Statt jedes Element einzeln mit einem Event-Handler auszustatten, wird einfach ein DOM-Objekt ausgewählt, dass im DOM <em>oberhalb</em> der zu beobachtenden DOM-Objekte liegt. Dieses übergeordnete Objekt wird über alle Events informiert, die <em>unterhalb</em> von ihm stattfinden das sogenannte „Event Bubbling“.</p>\n<p>In jQuery wird der Filter für das eigentliche Event-Ziel als zusätzlicher Parameter von <code>.on()</code> übergeben.</p>\n<pre><code class=\"language-javascript\"><u>// Add Event Handler to `nav`, fire if `.btn` was clicked</u>\n$(<kbd>'nav'</kbd>).on(<kbd>'click'</kbd>, <kbd>'.btn'</kbd>, <b>function</b>() {\n $(<i>this</i>).addClass(<kbd>'active'</kbd>);\n})</code></pre>\n<p>In Vanilla-JavaScript wird das Event-Ziel innerhalb des Event-Listeners gefiltert:</p>\n<pre><code class=\"language-javascript\"><u>// Add Event Handler to `nav`, fire if `.btn` was clicked</u>\ndocument.querySelector(<kbd>'nav'</kbd>).addEventListener(<kbd>'click'</kbd>, <b>function</b>(event) {\n <i>if</i> (event.target.matches(<kbd>'.btn'</kbd>)) {\n event.target.classList.add(<kbd>'active'</kbd>);\n }\n});</code></pre>\n<p>Bezogen auf unser Beispiel mit den 100 Tabellenzellen haben wir gerade aus 100 Event-Handlern einen einzigen Event-Handler gemacht. Das spart nicht nur Speicher, sondern erlaubt es auch, auf DOM-Elemente zu reagieren, die beim Hinzufügen des Event-Handlers noch gar nicht im DOM existierten. Wenn zum Beispiel zu unserem <code>&lt;nav&gt;</code>-Element erst nach dem Hinzufügen des Event-Handlers neue <code>&lt;… class=„btn“&gt;</code> zum Beispiel via AJAX hinzugefügt werden, wird unser Event-Handler auf dem <code>&lt;nav&gt;</code> auch diese Elemente mit verarbeiten, da er ja auf <em>alle</em> Elemente unterhalb von ihm reagiert.</p><img src=\"https://stats.3960.org/p.php?idsite=8amp;action_name=Event-Handling%20mit%20JavaScript%20%E2%80%93%20und%20ohne%20jQuery&amp;url=https%3A%2F%2Fjournal.3960.org%2Fposts%2F2019-10-27-event-handling-mit-javascript-ohne-jquery%2F%3Futm_source%3Dnewsfeed_view\" style=\"border:0;\" alt=\"\" />",
"summary": "Als Web-Entwickler fügen wir im Laufe eines Projektes einer Website eine zumeist nicht unerhebliche Anzahl an JavaScript-Event-Handlern hinzu sei es mit…",
"date_published": "2019-10-27T17:01:02+01:00",
"date_modified": "2020-02-09T17:01:08+01:00",
"author": {
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
},
"authors": [
{
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
}
],
"banner_image": "https://journal.3960.org/posts/2019-10-27-event-handling-mit-javascript-ohne-jquery/event.png",
"language": "de-DE",
"image": "https://journal.3960.org/posts/2019-10-27-event-handling-mit-javascript-ohne-jquery/event.png",
"tags": [
"Javascript",
"Programmierung",
"Webdevelop"
]
},
{
"id": "user/posts/2019-10-18-kalorien-sind-auch-option-stipp-isch/index.md",
"url": "https://journal.3960.org/posts/2019-10-18-kalorien-sind-auch-option-stipp-isch/",
"title": "Kalorien sind auch eine Option: Stipp(isch)",
"content_html": "<p itemprop=\"description\">Es gibt Gerichte, die trotz allem schlechten Gewissen oder entgegen ärztlichen Ratschlägen immer wieder gerne auf den Tisch kommen. Eines davon ist Stipp(isch) ein Gericht, das in jüngster Zeit wieder neue Fans gefunden hat. Höchste Zeit also, das Rezept zu verraten.</p>\n<!-- more -->\n<p id=\"more\">Stipp(isch) ist eigentlich nur eine äußerst leckere Sauce, die aus Alibi-Gründen über ein paar Kartoffeln gekippt wird. Die Einkaufsliste für diese Operation ist relativ handlich. Ihr benötigt, um 23 Personen glücklich zu machen:</p>\n<ul>\n<li itemprop=\"recipeIngredient\">300g gewürfelter <strong>Schinkenspeck</strong>,</li>\n<li itemprop=\"recipeIngredient\">3 große <strong>Zwiebeln</strong>,</li>\n<li itemprop=\"recipeIngredient\">400ml <strong>Sahne</strong> (ihr habt einen Eindruck, wohin die Reise geht)</li>\n<li itemprop=\"recipeIngredient\">etwas <strong>Milch</strong> nach Gefühl</li>\n<li itemprop=\"recipeIngredient\">sowie <strong>Pfeffer, Salz</strong></li>\n<li itemprop=\"recipeIngredient\">und bei Bedarf <strong>Fondor</strong>.</li>\n<li itemprop=\"recipeIngredient\">Dazu passen gut <strong>Pellkartoffeln</strong>.</li>\n</ul>\n<p>Kurz zusammengefasst besteht die Sauce also aus Speck, Zwiebeln und Sahne.</p>\n<p>Die Zubereitung ist fast genau so einfach:</p>\n<ol itemprop=\"recipeInstructions\" itemscope itemtype=\"http://schema.org/ItemList\">\n<li itemprop=\"itemListElement\">In einer großen Pfanne die Schinkenwürfel anbraten.</li>\n<li itemprop=\"itemListElement\">Die gewürfelten Zwiebeln hinzugeben und anbraten, bis sie glasig werden.</li>\n<li itemprop=\"itemListElement\">In der Zwischenzeit kann man bereits die Kartoffeln in einem separaten Topf auf den Herd stellen.</li>\n<li itemprop=\"itemListElement\">Darüber Sahne und ggf. Milch geben die Konsistenz der Sauce sollte dabei leicht zähflüssig bleiben.</li>\n<li itemprop=\"itemListElement\">Anständig würzen, gut verrühren kurz vor dem Aufkochen ist die Sauce dann fertig.</li>\n</ol>\n<p>Die Sauce kann durch harte körperliche (oder seelische Arbeit) verlorene Kalorie relativ flott wiederherstellen. <span class=\"emoji emoji--1f609\" title=\";)\">&#x1F609;</span> <meta itemprop=\"prepTime\" content=\"PT10M\" /><meta itemprop=\"cookTime\" content=\"PT20M\"></p><img src=\"https://stats.3960.org/p.php?idsite=8amp;action_name=Kalorien%20sind%20auch%20eine%20Option%3A%20Stipp(isch)&amp;url=https%3A%2F%2Fjournal.3960.org%2Fposts%2F2019-10-18-kalorien-sind-auch-option-stipp-isch%2F%3Futm_source%3Dnewsfeed_view\" style=\"border:0;\" alt=\"\" />",
"summary": "Es gibt Gerichte, die trotz allem schlechten Gewissen oder entgegen ärztlichen Ratschlägen immer wieder gerne auf den Tisch kommen. Eines davon ist Stipp(isch…",
"date_published": "2019-10-18T18:55:49+02:00",
"date_modified": "2019-12-04T12:40:29+01:00",
"author": {
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
},
"authors": [
{
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
}
],
"banner_image": "https://cdn.3960.org/favicon-192x192.png",
"language": "de-DE",
"image": "https://cdn.3960.org/favicon-192x192.png",
"tags": [
"Rezept"
]
},
{
"id": "user/posts/2019-10-14-kalaschnikow-programmierung/index.md",
"url": "https://journal.3960.org/posts/2019-10-14-kalaschnikow-programmierung/",
"title": "Kalaschnikow-Programmierung",
"content_html": "<blockquote><p>Dies ist meine Philosophie über Programmierung. Es gibt viele davon, aber diese hier ist meine. </p></blockquote>\n<!-- more -->\n<p id=\"more\">Jeder Programmierer entscheidet mit jeder Zeile, die er oder sie schreibt, wie er oder sie ein Problem lösen möchte. Verwirrenderweise gibt es dabei oft keinen „richtigen“ oder „falschen“ Weg (ausgenommen natürlich von handwerklichen Fehler, die absolut betrachtet falsch sind). Viel mehr entwickelt jeder Programmierer eine Meinung, warum bestimmte Wege besser sind als andere. Diese Meinung wiederum basiert auf Attributen, die einem wichtig erscheinen.</p>\n<h2 id=\"kalaschnikow\">Kalaschnikow?</h2>\n<p>Die Sturmgewehr-Familie, die mit der <a href=\"https://de.wikipedia.org/wiki/Kalaschnikow\">Kalaschnikow AK-47</a> begründet wurde, erfreut sich auch nach über siebzig Jahren Produktion immer noch einer überragenden Verbreitung. Im Gegensatz zu deutlich moderneren, fortschrittlicheren Konkurrenzmodellen überrascht die Langlebigkeit dieses Produktlinie und die Anzahl der Kopien und Derivate, die seitdem entwickelt wurden.</p>\n<p>Der AK-47 werden viele Dinge nachgesagt: Sie sei günstig, einfach zu produzieren, robust, geht tolerant mit Fehlbehandlung um und kann trotzdem gute Ergebnisse erzielen. Sie kann auch von wenig versierten Personen benutzt und repariert werden. Wie viele Konstruktionen aus sowjet-russischer Produktion ist die AK-47 unverwüstlich.</p>\n<p>Unabhängig davon, wofür eine Waffe also solche und diese im Speziellen steht, kann man von diesem Gewehr eine Menge für die Programmierung lernen.</p>\n<h2 id=\"kalaschnikow-programmierung-1\">Kalaschnikow-Programmierung</h2>\n<p>Für gute Programmierung existieren Unmengen an ausformulierten <i>best practices</i>, Coding-Standards oder Anleitungen. Diese im Detail zu kennen ist aber gar nicht so notwendig, wenn hinter jeder Entscheidung bei der Programmierung eine konsistente Philosophie steckt wie zum Beispiel die <strong>Kalaschnikow-Programmierung</strong>.</p>\n<p>Im Detail sind diese Ideen einfach zu erklären, wenn wir uns als Programmierer folgende Dinge vor Augen führen:</p>\n<ul>\n<li>Unser Code wird auf Situationen treffen, die wir nicht vorhergesehen haben. Falsche Werte, zu viele Werte, zu wenig Werte, abbrechende Verbindungen, Fehlbenutzung… als dies sind Dinge, die <em>wir</em> abfangen müssen. Als Programmierer können wir uns nicht auf schlechte Umstände berufen, sondern müssen wie ein Anschnallgurt in einem Auto oder die Displayfolie auf einem Smartphone davon ausgehen, das früher oder später etwas Schlimmes passieren kann.</li>\n<li>Unsere Programmierung kann nicht alle Fehlerfälle vorhersehen und abfangen. Deswegen muss sie auch nachträglich verbessert werden können durch uns, oder einen anderen Programmierer.</li>\n<li>Wir arbeiten fast immer in Teams. Unser Code wird von Programmierern gewartet oder verändert werden müssen, die nicht das selbe Wissen wie wir haben oder nicht die selben Tools. Ironischerweise können wir selber dieser Programmierer sein: Schmökert doch mal in Programmierung, die ihr vor zwei Jahren produziert habt, und versucht die für die Entwicklung notwendigen Tools aufzusetzen.</li>\n</ul>\n<p>Deshalb muss für mich persönlich Programmierung die folgende Attribute besitzen die den Attributen der Kalaschnikow-Gewehr-Familie ähneln:</p>\n<ol>\n<li>Sie muss eine <strong>Aufgabe präzise und möglichst wenig komplex</strong> lösen. Nicht weniger… aber auch nicht mehr.</li>\n<li>Sie muss <strong>tolerant mit Fehlern umgehen</strong> und sinnigerweise im Falle eines Fehlers dem Benutzer oder zumindest einem Programmierer mitteilen können, was der Fehler war.</li>\n<li>Sie muss <strong>verständlich</strong> sein, damit sie auch von anderen Programmierern mit anderem technischen Verständnis oder Tools über einen längeren Zeitraum hinaus gewartet werden kann.</li>\n</ol>\n<p>Diese drei Kernideen, einmal verinnerlicht, erlauben eine ganze Menge Entscheidungen zu fällen, ohne jeden Handgriff vorher explizit durchdenken bzw. erforschen zu müssen. Deswegen nenne ich diese Philosophie <strong>Kalaschnikow-Programmierung</strong>.</p>\n<h3 id=\"einfachheit-und-verständlichkeit-in-der-programmierung\">Einfachheit und Verständlichkeit in der Programmierung…</h3>\n<figure class=\"blockquote\"><blockquote><p>Die Genialität einer Konstruktion liegt in ihrer Einfachheit. Kompliziert bauen kann jeder.</p></blockquote>\n<figcaption>Sergej P. Koroljow</figcaption></figure>\n<p>Als Programmierer lieben wir Abkürzungen, die uns schneller und produktiver machen. Und außerdem mögen wir es auch, unsere Genialität und Professionalität in unserer Arbeit zu beweisen. Das Problem entsteht, wenn wir unsere Arbeit von zu vielen, zu komplexen Ideen abhängig machen.</p>\n<p>In diesem Sinne sollten wir nicht nur bei der <strong>Benennung von Komponenten</strong> daran denken, dass auch andere Programmierer diese verstehen können müssen. Auch übermäßig <strong>komplexe Sprach-Konstrukte</strong> oder <strong>wenig bekannte Mechanismen bzw. Funktionen</strong> müssen vermieden werden. Viele Programmiersprachen bieten für einige Problem wenig bekannte, sehr elegante Lösungen an die aber leider dann kaum jemand versteht. Das Wort „obskur“ sollte niemals den Zustand von Programmierung beschreiben dürfen.</p>\n<p>Wenn also eine solche Lösung verwendet wird, sollte diese zumindest <strong>dokumentiert</strong> werden besser ist es aber gegebenenfalls, diese Lösung durch ein wenig komplexes, dafür gerne auch längeres Stück Programmierung zu ersetzen.</p>\n<blockquote><p>Wer keine Dokumentation für seine Programmierung hinterlässt, möchte in seinem Urlaub telefonisch Fragen dazu beantworten.</p></blockquote>\n<p>Vor geraumer Zeit war ich noch der Meinung, dass Programmierung ohne Inline-Dokumentation eine schlechte Angewohnheit ist. Inzwischen glaube ich das Gegenteil: Wenn eine Programmierung einer Erklärung für den nächsten Programmierer bedarf, ist sie möglicherweise einfach nur zu komplex und sollte unbedingt umgeschrieben werden.</p>\n<p>Wir neigen dazu, Over-Engineering zu betreiben, wenn wir uns hinlänglich bekannte Probleme lösen. Um mögliche zukünftige Probleme vorweg zu nehmen, erzeugen wir oft erheblichen Aufwand nur um später festzustellen, dass wir einerseits dieses angenommene Problem nie hatten, und andererseits die von uns entwickelte Lösung niemals weiter verwendet worden war. Hier sollte <strong>Pragmatismus</strong> und Augenmaß unser Leitbild sein.</p>\n<p>Nicht zuletzt müssen wir uns bei überbordender Komplexität fragen, <em>warum</em> wir diesen Aufwand betreiben. Gemäß dem <a href=\"https://de.wikipedia.org/wiki/Paretoprinzip\"><strong>Pareto-Prinzip</strong></a> kann eine einfache, stabile Lösung kurz- wie auch langfristig weniger Aufwand verursachen und ist damit in der Herstellung nicht nur einfacher, sondern auch günstiger.</p>\n<h3 id=\"und-einfachheit-bei-den-werkzeugen\">…und Einfachheit bei den Werkzeugen</h3>\n<figure class=\"blockquote\"><blockquote><p>Alles sollte so einfach wie möglich gemacht werden, aber nicht einfacher.</p></blockquote>\n<figcaption>Albert Einstein</figcaption></figure>\n<p>Vor geraumer Zeit benötigte ein Webentwickler nur einen Webserver mit einem Scriptinterpreter, einen Datenbankserver, und einen Code-Editor. Diese Zeiten sind längst passé, und wir erweitern die notwendige Technologie immer wieder um neue Komponenten, die unsere Arbeit angenehmer und schneller macht solange diese Technologie funktioniert. So kann es heute notwendig sein, für die Entwicklungsarbeit an einem Web-Projekt Docker und die passenden Docker-Images, Gulp oder Grunt, dazu NodeJS, vielleicht noch SASS, Git, lokale Linter (um nicht mit dem automatischen Linter im Continuous Integration zu kollidieren), Editorconfig für den richtigen Code-Style und Unmengen an weiterer Tools zu benötigen.</p>\n<p>Wir, die wir diese Tools in jahrelanger Arbeit zusammengetragen, eingerichtet und später dann auch verstanden zu haben, haben damit für andere Entwickler in unserem Projekt eine <strong>Einstiegshürde</strong> geschaffen. Schlimmer noch können wir Teile in unsere Toolchain eingeführt haben, die ein <strong>Verfallsdatum</strong> haben und nach einer gewissen Zeit ein Projekt nur noch schwer wartbar machen. Und nicht zuletzt kann ein Defekt in <em>einem</em> Teil unserer Toolchain die sorgsam aufeinander gestapelten Abhängigkeiten zum Einsturz bringen. Wenn z.B. NodeJS nicht funktioniert, funktioniert Gulp nicht, funktioniert unser SASS-Compiler nicht, gibt es kein CSS.</p>\n<p>Wenn wir schon für unseren Entwicklungsprozess eine komplexe Toolchain erfordern, <em>müssen</em> wir (z.B. in der <code>README.md</code> des Projekts) die grundsätzlichen Anforderung und die Installation dieser Tools erläutern. Im Idealfall liefern wir ein <strong>Installations-Skript</strong> mit, dass alle notwendigen Abhängigkeiten und Tools installiert. Wenn man ein paar mal solche Anleitungen oder Skripte geschrieben hat, wird man vielleicht verstehen, welches Erbe man zukünftigen Programmierern hinterlassen hat.</p>\n<blockquote><p>Welches Problem löst das und welches Problem verursacht das?</p></blockquote>\n<p>Weitere Ideen und Inspiration zu diesem Thema finden sich in dem Artikel <a href=\"https://journal.3960.org/posts/2019-09-13-programmierung-zurueck-zur-werkbank/\">„Zurück zur Werkbank“</a>.</p>\n<h3 id=\"unser-verhältnis-zu-code-und-anderen-menschen\">Unser Verhältnis zu Code… und anderen Menschen</h3>\n<p>Gerade wenn wir an großen Projekten oder in einem Team arbeiten, sind wir als Programmierer einerseits gefordert, unsere fundierte Meinung einzubringen. Andererseits ist aber für das Gelingen unserer Programmierung notwendig, dass alle Beteiligten <strong>das selbe Verständnis</strong> für die Anforderung an die Umsetzung eines solchen Projektes haben.</p>\n<p>Als Programmierer können und sollen wir eine eigene Meinung zu Tools, Coding-Styles, Dokumentations-Standards oder Testing haben. Diese persönliche Meinung wird aber in Teams bzw. in Projekten immer nachrangig zu beschlossenen Standards sein. Wenn wir persönlich der Meinung sind, dass Tabs besser geeignet sind zum Einrücken, im Projekt bisher aber immer vier Leerzeichen verwendet wurden, <em>müssen</em> wir aus Gründen der Konsistenz und <strong>Erwartbarkeit von Code</strong> uns an diese Vorgaben halten. Das macht unsere eigene Meinung nicht schlecht oder überflüssig. Aber eine Abweichung von der Norm ist in einem komplexen Umfeld immer eine Quelle für Fehler. Das Prinzip des <a href=\"https://de.wikipedia.org/wiki/Clean_Code\">Clean Code</a> ist hier eine äußerst gute Grundlage.</p>\n<p>Wenn uns geschlossene Beschlüsse nicht gefallen, sollten wir auf eine Änderung hinwirken. Wenn eine Änderung beschlossen wurde, müssen wir diese aber auch <strong>konsequent und ggf. rückwirkend umsetzen</strong>. Mitten in einem Projekt einzelne Teile in einem anderen Zeichensatz oder mit einem neuen Datenbank-Adapter zu betreiben löst an der Stelle, an der wir den Code verwenden, vielleicht einiges an Problemen aber der nächste Programmierer steht auf einmal vor zwei verschiedenen Wegen, wie ein Problem gelöst werden kann. Dies ist eine Quelle für Missverständnisse und Fehler, sowie für langsam vor sich hinrottenden Code.</p>\n<p>Einsame Entscheidungen können wir nur für Projekte treffen, bei denen nur wir betroffen sind. Sobald Kunden, Nutzer oder andere Programmierer involviert sind, müssen wir uns auch über ihre Bedürfnisse klar werden.</p>\n<h3 id=\"fehlertoleranz\">Fehlertoleranz</h3>\n<p>Wir sollten niemals erwarten, dass eine Variable den Wert enthält, den wir annehmen. Bei einer Nutzereingabe ist dies offensichtlich, bei einer Abfrage aus einer Datenbank oder einer Schnittstelle fällt uns diese Annahme schon deutlich schwerer.</p>\n<p>Dabei geht es gar nicht so sehr um <strong>korrektes Quoting</strong> wobei inkorrektes Quoting nicht nur Fehler, sondern gegebenenfalls auch <a href=\"https://xkcd.com/327/\">Sicherheitsprobleme</a> auslösen kann. Viel mehr geht es darum, Fehlerbehandlung als einen Weg zu begreifen, der auch die Performance steigert. Die Prüfung auf das <strong>Vorhandensein eines Werts</strong> kann es erlauben, frühzeitig aus einem komplexen Programmteil zurückzukehren, ohne mit falschen Grundannahmen eine aufwändige Berechnung durchzuführen. Auch im Bereich des Templatings kann die Prüfung auf eine leere Variable die Ausgabe ganzer Template-Teile überflüssig machen.</p>\n<p>Unsere Programmierung kann auch auf andere Art und Weise fehlertoleranter werden. In fast jeder Sprache erlauben Funktionen eine Bereinigung von Variablen, zum Beispiel in dem umschließende Leerzeichen mittels <code>trim</code> entfernt werden, oder ein String per Casting sicher in eine Zahl verwandelt werden kann. Die <strong>einfache Konvertierung in erwartbare Werte</strong> kostet uns als Programmierer und unser Programm meist deutlich weniger Aufwand als den Nutzer die Korrektur einer fehlerhaften Eingabe abnötigen würde und erspart möglicherweise die Programmierung eines Prozesses, der den Nutzer zur Fehlerkorrektur auffordert.</p>\n<p>Nicht zuletzt können wir mittels <strong>Mustererkennung bzw. -ersetzung</strong> Fehler erkennen und vielleicht sogar unbemerkt beheben. Wenn der Nutzer bei der Eingabe einer Telefonnummer oder Kreditkartennummer keine anderen Zeichen als Ziffern eingeben soll, können wir als Programmierer diese Nicht-Ziffern-Zeichen doch problemlos entfernen und müssen diese stupide Aufgabe nicht unseren Nutzern auferlegen.</p>\n<p>Wenn wir eine Fehlermeldung oder Exception-Message schreiben, muss diese <strong>Fehlermeldung außerhalb des lokalen Kontextes Sinn ergeben</strong>. Die Fehlermeldung „Ein Fehler trat auf, wenden Sie sich bitte an Ihren Administrator“ ist besonders dann frustrierend, wenn man selber der Administrator <em>ist</em>. Benutzen wir doch die von jedem Programmierer einforderbare Fähigkeit Dinge zu beschreiben auch für Fehlermeldungen, und verwandeln ein „Connection fail“ in ein „Der HTTP-Aufruf <a href=\"https://www.example.com\">https://www.example.com</a> scheitert mit Status-Code 503.“. Niemand beschwert sich über <em>zu</em> aussagekräftige Fehlermeldungen.</p>\n<p>Weitere Ideen und Inspiration zu diesem Thema finden sich in dem Artikel <a href=\"https://journal.3960.org/posts/2019-04-24-verantwortung-von-software/\">„Die Verantwortung von Software“</a>.</p>\n<h2 id=\"fazit\">Fazit</h2>\n<p>Die Menge an praktischen Handlungsempfehlungen aus den drei Kernideen der <i>Kalaschnikow-Programmierung</i> sind deutlich vielfältiger, als dieser Artikel auch nur im Ansatz beleuchten kann. Dementsprechend sind die hier aufgeführten Anekdoten eher Beispiele aber nur die Spitze des Eisbergs. Vielmehr ist bei der Kalaschnikow-Programmierung das Grundverständnis bzw. die Grundhaltung die entscheidende Konstante, von denen ausgehend Entscheidungen getroffen werden können.</p>\n<p>Ich persönlich schaffe es auch nicht immer, mich an diese Idee zu halten. Aber sie führt mich immer wieder zurück, und hilft mir bei der Entscheidungen zwischen ansonsten technisch gleichwertig korrekten Lösungen.</p><img src=\"https://stats.3960.org/p.php?idsite=8amp;action_name=Kalaschnikow-Programmierung&amp;url=https%3A%2F%2Fjournal.3960.org%2Fposts%2F2019-10-14-kalaschnikow-programmierung%2F%3Futm_source%3Dnewsfeed_view\" style=\"border:0;\" alt=\"\" />",
"summary": "Dies ist meine Philosophie über Programmierung. Es gibt viele davon, aber diese hier ist meine.",
"date_published": "2019-10-14T18:58:23+02:00",
"date_modified": "2019-12-12T15:55:06+01:00",
"author": {
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
},
"authors": [
{
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
}
],
"banner_image": "https://cdn.3960.org/favicon-192x192.png",
"language": "de-DE",
"image": "https://cdn.3960.org/favicon-192x192.png",
"tags": [
"Programmierung",
"Technologie",
"Webdevelop",
"Meinung"
]
},
{
"id": "user/posts/2019-10-12-microsoft-flight-simulator-2020-was-er-bewirken-wird/index.md",
"url": "https://journal.3960.org/posts/2019-10-12-microsoft-flight-simulator-2020-was-er-bewirken-wird/",
"title": "Der Microsoft Flight Simulator 2020 und was er bewirken wird",
"content_html": "<p>Microsoft hat vor Kurzem den neuesten Teil ihrer weltberühmten <i>Flight Simulator</i>-Serie angekündigt. Innerhalb kürzester Zeit war der <i><a href=\"https://www.flightsimulator.com/\">Microsoft Flight Simulator 2020</a></i> in aller Munde nicht zuletzt wegen seines spektakulären Trailers:</p>\n<div class=\"video-player video-player--youtube\"><iframe allowfullscreen=\"allowfullscreen\" title=\"Der Trailer zu MSFS2020 ist atemberaubend.\" src=\"https://www.youtube-nocookie.com/embed/ReDDgFfWlS4?enablejsapi=1\" srcdoc=\"&lt;style&gt;*{padding:0;margin:0;overflow:hidden}html,body{height:100%}img,span{position:absolute;width:100%;top:0;bottom:0;margin:auto}span{height:1.5em;text-align:center;font:48px/1.5 sans-serif;color:white;text-shadow:0 0 0.5em black}&lt;/style&gt;&lt;a href=&quot;https://www.youtube.com/embed/ReDDgFfWlS4?autoplay=1&quot;&gt;&lt;img src=&quot;https://img.youtube.com/vi/ReDDgFfWlS4/hqdefault.jpg&quot; alt=&quot;&quot;&gt;&lt;span&gt;▶&lt;/span&gt;&lt;/a&gt;\"></iframe><!-- img src=\"https://img.youtube.com/vi/ReDDgFfWlS4/hqdefault.jpg\" --></div>\n<p>Nachdem sich der Staub etwas gelegt hat und immer mehr Informationen über dieses (augenscheinlich seit fünf Jahren im Geheimen produzierte) Projekt an die Öffentlichkeit dringen, gibt es eine erste Ahnung, was <abbr title=\"Microsoft Flight Simulator 2020\">MSFS2020</abbr> für das Hobby der Flug-Simulation bedeuten kann.</p>\n<!-- more -->\n<h2 id=\"more\">Was bisher geschah</h2>\n<p>Der aus dem Jahre 2006 stammende letzte Simulator aus dem Hause Microsoft war der <i><a href=\"https://de.wikipedia.org/wiki/Microsoft_Flight_Simulator#Flight_Simulator_X\">Microsoft Flight Simulator X</a></i> ein in seiner Zeit bahnbrechendes Stück Software, dass für lange Zeit den Maßstab für private Flug-Simulation gesetzt hatte.</p>\n<p>Die Jahre gingen ins Land, und der <abbr title=\"Flight Simulator X\">FSX</abbr> verstaubte mehr und mehr: Die Grafik, das Flugmodell, alleine der Nachschub an Patches all dies machte FSX trotz einer treuen Fangemeinde langsam überholt. Alle warteten auf einen Nachfolger.</p>\n<p>2012 erschien das Flugspiel <i>Microsoft Flight</i>. Die Annahme, dass es eine Fortsetzung des FSX sein würde, wurden enttäuscht. Stattdessen handelte es sich um ein vereinfachtes <em>Spiel</em>, dass Simulationsfreunde nicht zufrieden stellen konnte.</p>\n<p>Als weitere Signale schloss Microsoft 2009 das für den FSX verantwortliche Studio, und lizensierte die Engine an andere Unternehmen, die <a href=\"https://de.wikipedia.org/wiki/Microsoft_Flight_Simulator#Nachfolgeprodukte\">mehr oder weniger würdige Nachfolger für den Flight Simulator</a> produzierten. Keines dieser Produkte konnte aber bahnbrechende Erfolge feiern. </p>\n<p>Simulationsfreunden wurde klar, dass von Microsoft nichts mehr zu erwarten sein würde. So zog die Herde weiter, unter anderem zu <a href=\"https://www.x-plane.com/\">X-Plane 11</a>, oder schwelgte mit <a href=\"https://www.prepar3d.com/\">Prepar3d</a> in Nostalgie.</p>\n<h2 id=\"götterdämmerung\">Götterdämmerung</h2>\n<p>Das alles änderte sich schlagartig mit den ersten Trailern für den <i>Microsoft Flight Simulator 2020</i>, die für alle überraschend nicht nur einen bereits sehr fertig wirkenden Simulator zeigte.</p>\n<p>Die Trailer zeigten ein Flugerlebnis, das vor allen Dingen <a href=\"https://www.thedrive.com/the-war-zone/29848/this-spin-recovery-clip-from-microsofts-upcoming-flight-sim-is-absolutely-insane\"><em>außerhalb</em> der Simulations-Gemeinde Interesse an MSFS2020 weckte</a>. In persönlichen Gesprächen mit <em>Gamern</em> zeigte sich, dass Microsoft einen Nerv getroffen hatte: Auch Spieler ohne Vorerfahrung mit Flugsimulatoren interessierten sich auf einmal <em>brennend</em> für den MSFS2020. Die ansprechende Grafik und die einsteigerfreundliche Präsentation machten Lust auf mehr.</p>\n<p>Und die alten Simulationshasen? Immer, wenn der Hype-Train durch den Ort brauste, saßen sie erstmal gemütlich auf der Veranda und beobachteten das Spektakel skeptisch vom Rand aus. So auch diesmal: Viele hatten Microsoft ihre vorherigen Fehler in Bezug auf Flugsimulatoren nie verziehen.</p>\n<h2 id=\"direkt-auf-diese-überholspur\">Direkt auf diese Überholspur</h2>\n<p>Microsoft war von vorne herein bewusst, dass ihr Verhalten der Vergangenheit viel Porzellan zerschlagen und bei Simulations-Enthusiasten Skepsis und Misstrauen hinterlassen hatte. Schon früh hatte Microsoft deswegen den <a href=\"https://www.avsim.com/forums/forum/863-microsoft-flight-simulator/\">Austausch mit der Community</a> gestartet, und ein offenes Ohr für Ideen und Wünsche gezeigt. Doch alleine damit ließen sich nicht alle Zweifel zerstreuen Fakten mussten her.</p>\n<p>In einem PR-Meisterstreich lud Microsoft darauf hin ausgesuchte Simfluencer, Flug-Blogger sowie Fachpresse zu einem Event ein, bei der sie nicht nur das frühe Produkt selber ausprobieren konnten, sondern auch mit den Entwicklern des <i>Microsoft Flight Simulator 2020</i> direkt ins Gespräch kommen konnten.</p>\n<div class=\"video-player video-player--youtube\"><iframe allowfullscreen=\"allowfullscreen\" title=\"Kurz und knackig sagt es flightdeck2sim\" src=\"https://www.youtube-nocookie.com/embed/RciDscnzJb8?enablejsapi=1\" srcdoc=\"&lt;style&gt;*{padding:0;margin:0;overflow:hidden}html,body{height:100%}img,span{position:absolute;width:100%;top:0;bottom:0;margin:auto}span{height:1.5em;text-align:center;font:48px/1.5 sans-serif;color:white;text-shadow:0 0 0.5em black}&lt;/style&gt;&lt;a href=&quot;https://www.youtube.com/embed/RciDscnzJb8?autoplay=1&quot;&gt;&lt;img src=&quot;https://img.youtube.com/vi/RciDscnzJb8/hqdefault.jpg&quot; alt=&quot;&quot;&gt;&lt;span&gt;▶&lt;/span&gt;&lt;/a&gt;\"></iframe><!-- img src=\"https://img.youtube.com/vi/RciDscnzJb8/hqdefault.jpg\" --></div>\n<p>Ob es in dem <a href=\"https://www.youtube.com/watch?v=HrJs0jK4a1g\">Youtube-Video von FlightChops</a>, <a href=\"https://www.youtube.com/watch?v=Fj8h6yibHHc\">dem Youtube-Video von Frooglesim</a> oder dem Artikel auf <a href=\"https://www.helisimmer.com/articles/hands-on-microsoft-flight-simulator-2020\">Helisimmer.com</a> ist: Alle Simfluencer konnten nicht verbergen, dass Microsoft ihre Skepsis in Begeisterung und Vorfreude verwandelt hatte.</p>\n<h2 id=\"die-situation-heute\">Die Situation heute</h2>\n<p>Da die ersten Erfahrungen mit dem MSFS2020 vorliegen, verdichtet sich ein Bild.</p>\n<ul>\n<li>Der <i>Microsoft Flight Simulator 2020</i> hat sowohl Neueinsteiger als auch Veteranen als Zielgruppe.</li>\n<li>Grafisch wird der Simulator alles bisher dagewesene in den Schatten stellen zumal der Simulator für die <em>gesamte</em> Welt hochauflösendes Material mit Vegetation und Bebauung anbieten wird.</li>\n<li>Das Flugmodell wird ebenfalls seinesgleichen suchen. Sowohl in Berichten als auch in Videos ist zu sehen, wie diffizil Fluggeräte reagieren.</li>\n<li>Auch beim Wettermodell ist eine Detailtiefe zu sehen, die bisherige Simulatoren alt aussehen lässt.</li>\n<li>Inwiefern Online-Spiel, Air Traffic Control und andere Prozeduren von vorne herein integriert sind, ist offen. Es ist aber erkennbar, dass auch hier der MSFS2020 nicht kleckern, sondern klotzen wird.</li>\n<li>Über den Bereich Performance (gerade für Virtual Reality) ist noch nicht viel bekannt hier besteht schon der Verdacht, dass für bahnbrechende Bilder bahnbrechende Hardware benötigt wird. Für Simulationsfreunde ist aber die Verwendung von High-End-Hardware kein Novum.</li>\n<li>Es steht zu erwarten, dass die Palette an Fluggeräten schon nach kurzer Zeit sich rapide füllen wird, da etliche Drittanbieter bereits mit der Produktion neuer Fluggeräte für den MSFS2020 begonnen haben.</li>\n<li>Nicht zuletzt wird aufgrund der anvisierten Zielgruppe wahrscheinlich das bisher im Simulatorgewerbe übliche Zusammenbasteln des Simulators ein Ende haben. Während heutige Simulatoren aus einzelnen Softwarekomponenten zusammengesetzt werden müssen, die auf unterschiedlichen Bezugswegen und mit beliebig komplexen Installationsmechanismen daher kommen, wird Microsoft wahrscheinlich bei Erwerb wie Installation einen integrierten Katalog anbieten, ähnlich wie Steam oder Origin.</li>\n</ul>\n<p>Alles in allem scheint der <i>Microsoft Flight Simulator 2020</i> aller Voraussicht nach einen neuen Standard für den Bereich der Heim-Flugsimulatoren setzen zu können.</p>\n<h2 id=\"wie-gehts-weiter-mit-den-anderen-flugsimulatoren\">Wie geht&#39;s weiter mit den <em>anderen</em> Flugsimulatoren?</h2>\n<p>Der MSFS2020 bedeutet für etablierten Flugsimulatoren eine ernsthafte Konkurrenz. Gerade die Simulatoren, die ebenfalls die hochgradig realistische Zivil-Fliegerei abbilden, müssen sich sehr warm anziehen:</p>\n<ul>\n<li>Für <strong>X-Plane 11</strong> wird in den ersten Jahren das große Angebot von Fluggeräten gegenüber MSFS2020 noch einen Vorteil darstellen. Aber sowohl in der Darstellung der Szenerie als auch beim Wettermodell scheint der Neuankömmling dem guten alten X-Plane 11 überlegen zu sein. In Sachen Performance scheinen beide Simulatoren gleich hungrig zu sein der MSFS2020 scheint aber mit der Hardware ein deutlich beeindruckenderes Erlebnis zu zaubern.</li>\n<li>Noch schlimmer sieht es für <strong>Prepar3d</strong> aus: Die angestaubte Engine wird augenscheinlich gegen den MSFS2020 keine Chance haben. Einzig die breite Palette an Fluggeräten kann anfangs noch helfen aber alleine bei dem Angebot an Szenerien wie auch bei dem Flugmodell wird die Luft sehr schnell sehr dünn.</li>\n</ul>\n<p>Eine Chance haben dagegen Simulations-Projekte, die leicht außerhalb des Fokus liegen wenn sie ihre Karten gut spielen:</p>\n<ul>\n<li>Der <strong>Digital Combat Simulator</strong> muss sich keine Sorgen machen: Obwohl sein Angebot an Szenerien geradezu winzig ist, ist die Konzentration auf Kampfflugzeuge bzw. -hubschrauber ein Feld, dass augenscheinlich nicht von MSFS2020 besetzt werden wird.</li>\n<li>Der <strong><a href=\"https://www.aerofly.com/de/\">Aerofly FS2</a></strong> ist im VR-Bereich bzw. auf kleiner Hardware grafisch ungeschlagen. Zwar verfügt der Simulator bis heute über kein realistisches Wetter, globale Szenerie-Abdeckung, Air Traffic Control, eine lebende Umwelt oder Multi-Player. Aber durch die Konzentration auf das Flugmodell, Performance und Einsteigerfreundlichkeit könnte Aerofly FS2 auch mittelfristig seine Bedeutung im Heim-Simulations-Markt behalten.</li>\n<li>Das bis heute nicht veröffentlichte <strong><a href=\"https://store.steampowered.com/app/771800/Deadstick__Bush_Flight_Simulator/\">Deadstick</a></strong> von REMEX Software dagegen könnte die Konzentration auf eine lebende Umwelt und ein Meta-Spiel die Zukunft sichern. Gerade dass <a href=\"https://journal.3960.org/posts/2017-11-24-flugsimulationen-besser-machen/\">Meta-Spiel, das der Fliegerei einen <em>Sinn</em> gibt</a>, und das kleine, heimatgefühlinduzierende Fluggebiet könnte eine langfristige Fan-Gemeinde aufbauen. Wenn <i>Deadstick</i> denn jemals erscheinen sollte.</li>\n</ul>\n<p>Für alle Simulatoren kann ein Weg sein, die Power des Internets zu nutzen:</p>\n<ul>\n<li>Die Kooperation mit einem Flug-/Satelliten-Bild-Anbieter, zusammen mit der Verwendung von Open Street Maps und einer Technologie zur Erzeugung von dreidimensionaler Vegetation und Bebauung, kann global die Abdeckung wie auch die Präsentation stark verbessern.</li>\n<li>Scheinbar unbelebte Umwelt können über Schnittstellen mit <a href=\"https://avwx.rest/\">echten Wetterdaten</a>, <a href=\"https://opensky-network.org/\">echten Flugverkehrsdaten</a> und z.B. auch <a href=\"https://www.aishub.net/\">echten Schiffsbewegungen</a> dynamischer erscheinen. Fahrzeuge dagegen können auf den durch Open Street Maps bekannten Straßen animiert werden.</li>\n<li>Simulatoren müssen selber offene, gut dokumentierte, stabile Schnittstellen anbieten, die dritten Parteien (z.B. auch Community-Entwicklern) die Erweiterung des Simulators erlauben.</li>\n<li>Darüber hinaus muss Nutzerfreundlichkeit mehr in den Fokus rücken; nicht nur innerhalb des eigentlichen Simulators, sondern auch bei der Installation und Aktualisierung von zusätzlichen Add-Ons und Plugins.</li>\n</ul>\n<p>Wie die einzelnen Simulatoren sich entwickeln hängt aber neben dem Produkt und dem Verhalten des Herstellers nicht zuletzt von der jeweiligen Community ab ein schwer einzuschätzender Faktor. Schon bei FSX konnte man beobachten, dass ein technisch und funktional schon lange abgehängtes Produkt immer noch erfolgreich sein kann.</p>\n<h2 id=\"fazit\">Fazit</h2>\n<p>Alles in allem wird 2020 ein spannendes Jahr für die Flugsimulationsgemeinde sei es für die Hersteller, sei es für die Schreibtisch-Flieger. Auf jeden Fall wird der MSFS2020 neue Impulse setzen, und das Hobby der virtuellen Fliegerei schlagartig einem vollkommen neuen Kreis von Nutzern eröffnen.</p>\n<p>Auch Simulationsfreunde, die nicht auf MSFS2020 setzen werden, werden seine Auswirkungen früher oder später auch in ihrem Lieblings-Simulator erleben.</p><img src=\"https://stats.3960.org/p.php?idsite=8amp;action_name=Der%20Microsoft%20Flight%20Simulator%202020%20%E2%80%93%20und%20was%20er%20bewirken%20wird&amp;url=https%3A%2F%2Fjournal.3960.org%2Fposts%2F2019-10-12-microsoft-flight-simulator-2020-was-er-bewirken-wird%2F%3Futm_source%3Dnewsfeed_view\" style=\"border:0;\" alt=\"\" />",
"summary": "Microsoft hat vor Kurzem den neuesten Teil ihrer weltberühmten Flight Simulator-Serie angekündigt. Innerhalb kürzester Zeit war der Microsoft Flight Simulator…",
"date_published": "2019-10-12T18:20:22+02:00",
"date_modified": "2020-02-07T14:31:15+01:00",
"author": {
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
},
"authors": [
{
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
}
],
"banner_image": "https://img.youtube.com/vi/ReDDgFfWlS4/hqdefault.jpg",
"language": "de-DE",
"image": "https://img.youtube.com/vi/ReDDgFfWlS4/hqdefault.jpg",
"tags": [
"MSFS2020",
"Fliegerei",
"Für Tumblr",
"Meinung",
"Simulation",
"Spiel",
"The Cool",
"Aerofly FS2",
"X-Plane",
"DCS"
]
},
{
"id": "user/posts/2019-10-01-redirects-fuer-apache-verstehen/index.md",
"url": "https://journal.3960.org/posts/2019-10-01-redirects-fuer-apache-verstehen/",
"title": "Redirects für den Apache verstehen",
"content_html": "<p>Nach größeren Änderungen an einem Internetauftritt gibt es oft den Wunsch, veraltete URLs auf neue URLs umzuleiten. Dazu kann man in Webservern sogenannte „Redirects“ anlegen Umleitungen für URLs. Sowohl Besucher mit Lesezeichen wie auch Suchmaschinen werden so eure neuen Inhalte umgeleitet, auch wenn sie eine alte URL aufrufen.</p>\n<p>Für den Apache Webserver gibt es 2½ Wege, wie man Redirects konfigurieren kann: <code>redirect</code>, <code>redirectmatch</code> sowie <code>RewriteRule</code>. Tatsächlich ist die korrekte und fehlerfreie Konfiguration von Redirects aber eine trickreiche Sache und ein genaues Studium der jeweiligen Anleitung notwendig, um <i>Redirect Loops</i> zu vermeiden.</p>\n<!-- more -->\n<p id=\"more\">Die 2½ verschiedenen Redirect-Direktiven funktionieren relativ ähnlich: Sie leiten eine <strong>Anfrage-URL</strong>, die einem bestimmten <strong>Muster</strong> entspricht, auf eine <strong>Ziel-URL</strong> um. Dazu können sie der Anfrage einen <strong><a href=\"https://de.wikipedia.org/wiki/HTTP-Statuscode\">HTTP-Statuscode</a></strong> mitgeben, der den ursprünglichen Aufrufer mitteilt, aus welchem Grund und wie lange die Umleitung existiert.</p>\n<h2 id=\"wo-kann-ich-für-den-apache-webserver-redirects-einrichten\"><em>Wo</em> kann ich für den Apache-Webserver Redirects einrichten?</h2>\n<p>Der Ort für die Konfiguration von Redirects ist entweder die Apache-Konfigurationsdatei, oder aber (wenn der Webserver dieses Feature eingeschaltet hat) die <code>.htaccess</code>-Konfigurationsdatei direkt im Hosting-Verzeichnis bzw. der Document Root des Webauftritts.</p>\n<p>Wenn kein Apache zum Einsatz kommt, funktioniert diese Methoden nicht in der Regel verfügt aber jeder Webserver über eine zumindest ähnliche Methode, wie Redirects eingerichtet werden können.</p>\n<h2 id=\"wie-sollte-ich-für-den-apache-redirects-einrichten\"><em>Wie</em> sollte ich für den Apache Redirects einrichten?</h2>\n<p>Bei der Einrichtung von Redirects sollte in der Konfigurationsdatei vermerkt werden, warum die Redirects eingerichtet wurden, oder wann sie gelöscht werden können. Nichts ist schlimmer, als in einem Wust von 6.500 Redirects nicht mehr durchzublicken und auch nicht zu wissen, ob nicht 6.000 Regeln schon lange hätten weggeworfen werden können. Hier bieten sich Kommentare an:</p>\n<pre><code class=\"language-apacheconf\"><u># Basic redirects START</u>\n<i>Redirect</i> permanent <kbd>&quot;/index&quot;</kbd> <kbd>&quot;/&quot;</kbd>\n<u># Basic redirects END</u>\n\n<u># SEO redirects DELETE AFTER 10/2020 START</u>\n<i>Redirect</i> permanent <kbd>&quot;/artikel&quot;</kbd> <kbd>&quot;/articles&quot;</kbd>\n<i>Redirect</i> permanent <kbd>&quot;/kontakt&quot;</kbd> <kbd>&quot;/contact&quot;</kbd>\n<u># SEO redirects DELETE AFTER 10/2020 END</u></code></pre>\n<p>Gerade bei Redirects, die Suchmaschinen von einer alten, nicht mehr im Einsatz befindlichen URL auf eine neue URL umleiten sollen, kann nach zwei Jahren spätestens davon ausgegangen werden, dass sie nicht mehr notwendig sind.</p>\n<p>Ein weiterer Vorschlag ist, die Direktiven für Redirects in Blöcke einzupacken, die testen, ob das für die Direktiven notwendige Modul überhaupt installiert ist:</p>\n<pre><code class=\"language-apacheconf\">&lt;IfModule mod_alias.c&gt;\n <i>Redirect</i> permanent <kbd>&quot;/index&quot;</kbd> <kbd>&quot;/&quot;</kbd>\n&lt;/IfModule&gt;\n\n&lt;IfModule mod_rewrite.c&gt;\n <i>RewriteRule</i> <kbd>&quot;^/source$&quot;</kbd> <kbd>&quot;/target&quot;</kbd> [R=301,L]\n&lt;/IfModule&gt;</code></pre>\n<p>Dies verhindert, dass der Webserver seinen Betrieb einstellt, falls das Modul deaktiviert wird. Andersherum kann man diese Blöcke natürlich weglassen, wenn man explizit möchte, dass das Deaktivieren von Modulen und der damit verbundenen Redirects auffällt. <span class=\"emoji emoji--1f609\" title=\";)\">&#x1F609;</span></p>\n<h2 id=\"fallstricke-bei-der-konfiguration-von-redirects-im-apache\">Fallstricke bei der Konfiguration von Redirects im Apache</h2>\n<p>Wenn man sich die <a href=\"https://httpd.apache.org/docs/current/mod/mod_alias.html#redirect\">Anleitung für <code>mod_alias</code> inklusive <code>redirect</code></a> und <a href=\"https://httpd.apache.org/docs/current/mod/mod_alias.html#redirectmatch\"><code>redirectmatch</code></a> sowie die <a href=\"https://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriterule\">Anleitung für <code>mod_rewrite</code> inklusive <code>RewriteRule</code></a> genau anschaut, wird man überraschenderweise darauf stoßen, dass <em>alle</em> Varianten bei der Anfrage-URL nicht eine <em>fixe</em> URL entgegen nehmen, sondern ein <em>Muster</em> (bzw. <i>Pattern</i>). Diese Muster erwischen meistens mehr Anfrage-URLs, als man auf den ersten Blick vermuten möchte.</p>\n<p>Selbst die harmlos wirkende <code>Redirect</code>-Direktive sucht nach einem Muster (und nicht nach einem festen Wert), und hängt alle überschüssigen URL-Teile <em>inklusive</em> <code>GET</code>-Parameter an die Ziel-URL an:</p>\n<pre><code class=\"language-apacheconf\"><i>Redirect</i> permanent <kbd>&quot;/source&quot;</kbd> <kbd>&quot;/target&quot;</kbd>\n<u># Redirects /source to /target</u>\n<u># Redirects /source123 to /target123</u>\n<u># Redirects /source/12 to /target/12</u>\n<u># Redirects /source/?a to /target/?a</u></code></pre>\n<p>Das stellt eine größere Quelle für Verwirrung dar, da ein unbedarfter Einrichter mit der obigen Direktive nicht eine einzige Anfrage-URL umleitet, sondern tatsächlich eine unüberschaubar große Menge. Zudem kann eine frühere Regel nachfolgende Regeln unbenutzbar machen, ohne dass dies auf den ersten Blick auffällt:</p>\n<pre><code class=\"language-apacheconf\"><i>Redirect</i> permanent <kbd>&quot;/source&quot;</kbd> <kbd>&quot;/target&quot;</kbd>\n<i>Redirect</i> permanent <kbd>&quot;/source/12&quot;</kbd> <kbd>&quot;/target/some-special-place&quot;</kbd>\n\n<u># Redirects /source to /target</u>\n<u># Redirects /source123 to /target123</u>\n<u># Redirects /source/12 to /target/12 (!)</u>\n<u># Redirects /source/?a to /target/?a</u></code></pre>\n<h3 id=\"reguläre-ausdrücke-werden-die-welt-retten\">Reguläre Ausdrücke werden die Welt retten</h3>\n<p>Verständlicher ist dort die <code>RedirectMatch</code>-Direktive, die von vorne herein mitteilt, dass sie mittels eines <a href=\"https://de.wikipedia.org/wiki/Regul%C3%A4rer_Ausdruck\">regulären Ausdrucks</a> die Anfrage-URL in eine Ziel-URL umformt. Bei einer Fehlbedienung sind die Konsequenzen aber noch viel weitreichender:</p>\n<pre><code class=\"language-apacheconf\"><i>RedirectMatch</i> permanent <kbd>&quot;/source&quot;</kbd> <kbd>&quot;/target&quot;</kbd>\n<u># Redirects /source to /target</u>\n<u># Redirects /source123 to /target</u>\n<u># Redirects /source/12 to /target</u>\n<u># Redirects /source/?a to /target</u>\n<u># Redirects /your-shiny/source/?a to /target</u></code></pre>\n<p>Eine Entsprechung zu <code>RedirectMatch</code> findet sich bei <a href=\"https://httpd.apache.org/docs/current/mod/mod_rewrite.html\"><code>mod_rewrite</code></a>, das auch kompliziertere Umleitungen abbilden kann.</p>\n<figure class=\"blockquote\"><blockquote cite=\"https://httpd.apache.org/docs/current/mod/mod_alias.html\"><p><code>mod_alias</code> is designed to handle simple URL manipulation tasks. For more complicated tasks such as manipulating the query string, use the tools provided by <code>mod_rewrite</code>.</p></blockquote>\n<figcaption><cite><a href=\"https://httpd.apache.org/docs/current/mod/mod_alias.html\">mod_alias Apache HTTP Server Version 2.4</a></cite></figcaption></figure>\n<p>Die <code>RewriteRule</code>-Direktive hat entsprechende Fallstricke im Angebot, da sie ebenfalls mit regulären Ausdrücken arbeitet <em>und</em> je nach Einsatzort ein anderes Matching verwendet:</p>\n<figure class=\"blockquote\"><blockquote cite=\"https://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriterule\"><p>In VirtualHost context, The <em>Pattern</em> will initially be matched against the part of the URL after the hostname and port, and before the query string (e.g. „/app1/index.html“). This is the (%-decoded) URL-path.<br />In per-directory context (Directory and <code>.htaccess</code>), the <em>Pattern</em> is matched against only a partial path, for example a request of „/app1/index.html“ may result in comparison against „app1/index.html“ or „index.html“ depending on where the RewriteRule is defined.<br />[…]<br />The removed prefix always ends with a slash, meaning the matching occurs against a string which never has a leading slash. Therefore, a Pattern with ^/ never matches in per-directory context.</p></blockquote>\n<figcaption><cite><a href=\"https://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriterule\">mod_rewrite Apache HTTP Server Version 2.4</a></cite></figcaption></figure>\n<p>Die Einschränkung für <code>.htaccess</code>-Dateien kann übrigens mit einem vorangestellten <code>RewriteCond %{REQUEST_URI}</code> aufgehoben werden, so dass sich die Regeln wieder analog zu ihrem Aufruf innerhalb einer <code>&lt;VirtualHost&gt;</code>-Direktive verhalten.</p>\n<p>Damit sehen die Matches wie folgt aus:</p>\n<pre><code class=\"language-apacheconf\"><i>RewriteRule</i> <kbd>&quot;/source&quot;</kbd> <kbd>&quot;/target&quot;</kbd> [R=301,L]\n<u># Redirects /source to /target</u>\n<u># Redirects /source123 to /target</u>\n<u># Redirects /source/12 to /target</u>\n<u># Redirects /source/?a to /target</u>\n<u># Redirects /your-shiny/source/?a to /target</u></code></pre>\n<h3 id=\"fallstricke-zum-selberknüpfen\">Fallstricke zum Selberknüpfen</h3>\n<p>Die Gefährlichkeit von <code>Redirect</code> wird dann offenbar, wenn man seine Funktionalität mit <code>RedirectMatch</code> und <code>RewriteRule</code> nachbaut. Denn tatsächlich benutzt <code>Redirect</code> implizit ein nicht wenig komplexes Pattern-Matching. Folgendes Beispiel zeigt, wie inhaltlich identische Regeln teilweise sehr unschuldig aussehen können:</p>\n<pre><code class=\"language-apacheconf\"><i>Redirect</i> permanent <kbd>&quot;/source&quot;</kbd> <kbd>&quot;/target&quot;</kbd>\n<i>RedirectMatch</i> permanent <kbd>&quot;^/source(.*)&quot;</kbd> <kbd>&quot;/target$1&quot;</kbd>\n<i>RewriteRule</i> <kbd>&quot;^/source(.*)&quot;</kbd> <kbd>&quot;/target$1&quot;</kbd> [R=301,L]</code></pre>\n<h2 id=\"wie-richte-ich-bombensichere-redirects-für-den-apache-ein\">Wie richte ich bombensichere Redirects für den Apache ein?</h2>\n<p>Um sich komplett sicher zu sein, von wo nach wo Redirects erzeugt werden, sollten nur die Redirect-Direktiven mit regulären Ausdrücken verwendet werden. Diese weisen von vorne herein darauf hin, dass ihre Konfiguration wohl überlegt sein möchte. Dabei helfen die <a href=\"https://www.debuggex.com/cheatsheet/regex/pcre\">Steuerzeichen für PCREs bzw. Perl-kompatible reguläre Ausdrücke</a>:</p>\n<ul>\n<li><code>^</code>: Stimmt mit dem Anfang einer Zeichenkette überein.</li>\n<li><code>$</code>: Stimmt mit dem Ende einer Zeichenkette überein.</li>\n<li><code>?</code>: Das Zeichen bzw. die Gruppe vor dem <code>?</code> ist optional.</li>\n</ul>\n<p>Ein super-einfacher, direkter Redirect von exakt einer Anfrage-URL auf exakt eine Ziel-URL kann mittels Umschließung mit <code>^…$</code> realisiert werden:</p>\n<pre><code class=\"language-apacheconf\"><i>RewriteEngine</i> On\n<i>RewriteCond</i> %{REQUEST_URI}\n<i>RewriteRule</i> <kbd>&quot;^/source$&quot;</kbd> <kbd>&quot;/target&quot;</kbd> [R=301,L]\n<u># Redirects /source to /target</u></code></pre>\n<p>Wenn Anfrage-URLs ohne <em>und</em> mit abschließenden <code>/</code> erlaubt sein sollen, kann dieses Muster um ein optionales <code>/</code> erweitert werden:</p>\n<pre><code class=\"language-apacheconf\"><i>RewriteEngine</i> On\n<i>RewriteCond</i> %{REQUEST_URI}\n<i>RewriteRule</i> <kbd>&quot;^/source(/)?$&quot;</kbd> <kbd>&quot;/target$1&quot;</kbd> [R=301,L]\n<u># Redirects /source to /target</u>\n<u># Redirects /source/ to /target/</u></code></pre>\n<p>Wenn ganze URL-Bereiche auf <em>eine</em> Ziel-URL umgeleitet werden sollen, kann der letzte Teil der URL explizit mit einem Muster erfasst werden. <code>.*</code> erfasst bei regulären Ausdrücken eine beliebige Anzahl von beliebigen Zeichen:</p>\n<pre><code class=\"language-apacheconf\"><i>RewriteEngine</i> On\n<i>RewriteCond</i> %{REQUEST_URI}\n<i>RewriteRule</i> <kbd>&quot;^/source/.*$&quot;</kbd> <kbd>&quot;/target/&quot;</kbd> [R=301,L]\n<u># Redirects /source/ to /target/</u>\n<u># Redirects /source/example to /target/</u>\n<u># Redirects /source/?abc to /target/</u></code></pre>\n<p>Und nicht zuletzt kann ein ganzer Bereich auch 1:1 auf einen anderen Bereich umgeleitet werden, indem man die überschüssigen URL-Teile der Anfrage-URL an die Ziel-URL weiterleitet:</p>\n<pre><code class=\"language-apacheconf\"><i>RewriteEngine</i> On\n<i>RewriteCond</i> %{REQUEST_URI}\n<i>RewriteRule</i> <kbd>&quot;^/source/(.*)$&quot;</kbd> <kbd>&quot;/target/$1&quot;</kbd> [R=301,L]\n<u># Redirects /source/ to /target/</u>\n<u># Redirects /source/example to /target/example</u>\n<u># Redirects /source/?abc to /target/?abc</u></code></pre>\n<h2 id=\"und-für-nginx\">Und für nginx?</h2>\n<p>Der nginx-Webserver erfreut sich stetig wachsender Beliebtheit, und verfügt über ähnliche Methoden namens <a href=\"https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite\"><code>rewrite</code></a> zum Erzeugen von Redirects. Entsprechend sieht das letzte Beispiel für den Apache im nginx wie folgt aus:</p>\n<pre><code class=\"language-nginx\"><i>rewrite</i> ^/source/(.*)$ /target/$1 permanent\n<u># Redirects /source/ to /target/</u>\n<u># Redirects /source/example to /target/example</u>\n<u># Redirects /source/?abc to /target/?abc</u></code></pre>\n<p>Eine <a href=\"https://stackoverflow.com/questions/49191594/nginx-rewrite-a-lot-2000-of-urls-with-parameters/49192527#49192527\">besonders geniale Lösung für nginx-Redirects auf Stackoverflow</a> schmeißt aber die gesamte Denkarbeit über Bord, und erlaubt tatsächlich das Anlegen einer einfachen Tabelle von Anfrage- und Ziel-URLs.</p>\n<h2 id=\"fazit\">Fazit</h2>\n<p>Die Einrichtung von Redirects im Apache-Webserver kann schnell unbeabsichtigte Folgen heraufbeschwören, und sogar den gefürchteten Redirect-Loop mit seiner bekannten Fehlermeldung „Too many redirects“ provozieren. Die Einrichtung mit Augenmaß und das Studium der Anleitung bewahrt euch davor, euren Internetauftritt unerreichbar zu machen.</p>\n<p>Falls ihr Wünsche für Redirects in Form einer Liste „Anfrage → Ziel“ erhaltet, dürft ihr diese Liste nicht 1:1 in eure Redirect-Direktiven umwandeln, sondern solltet mit den obigen Beispielen eine präzisere Übersetzung durchführen.</p><img src=\"https://stats.3960.org/p.php?idsite=8amp;action_name=Redirects%20f%C3%BCr%20den%20Apache%20verstehen&amp;url=https%3A%2F%2Fjournal.3960.org%2Fposts%2F2019-10-01-redirects-fuer-apache-verstehen%2F%3Futm_source%3Dnewsfeed_view\" style=\"border:0;\" alt=\"\" />",
"summary": "Nach größeren Änderungen an einem Internetauftritt gibt es oft den Wunsch, veraltete URLs auf neue URLs umzuleiten. Dazu kann man in Webservern sogenannte …",
"date_published": "2019-10-01T18:03:10+02:00",
"date_modified": "2020-01-06T12:37:22+01:00",
"author": {
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
},
"authors": [
{
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
}
],
"banner_image": "https://cdn.3960.org/favicon-192x192.png",
"language": "de-DE",
"image": "https://cdn.3960.org/favicon-192x192.png",
"tags": [
"Programmierung",
"Webdevelop",
"Apache"
]
},
{
"id": "user/posts/2019-09-22-vfr-ohne-technischen-schnickschnack/index.md",
"url": "https://journal.3960.org/posts/2019-09-22-vfr-ohne-technischen-schnickschnack/",
"title": "VFR ohne technischen Schnickschnack",
"content_html": "<p><a href=\"https://journal.3960.org/posts/2019-09-22-vfr-ohne-technischen-schnickschnack/sunset.jpg\" class=\"gallery__link\"><img src=\"https://journal.3960.org/posts/2019-09-22-vfr-ohne-technischen-schnickschnack/sunset-400x225.jpg\" class=\"default\" width=\"400\" height=\"225\" style=\"--aspect-ratio: 400/225;\" alt=\"\" /></a></p>\n<p>Mein aktueller Lieblings-Flugsimulator <a href=\"https://journal.3960.org/tagged/aerofly-fs2/\">Aerofly FS2</a> überredet mich immer wieder zu neuen Experimenten. Nachdem ich <a href=\"https://journal.3960.org/posts/2017-12-17-vor-freude-ifr-mit-aerofly-fs2/\">IFR ohne GPS in Aerofly FS2</a> ausprobiert hatte, animierte mich die Geschichte der <a href=\"http://sometimes-interesting.com/2013/12/04/concrete-arrows-and-the-u-s-airmail-beacon-system/\">Leuchttürmen und großen Beton-Pfeilen für Flugzeuge</a> aus der Gründerzeit der Fliegerei, mir eine neue Aufgabe vorzuknöpfen: Navigation <em>ohne</em> moderne technische Hilfsmittel an Bord!</p>\n<!-- more -->\n<h2 id=\"more\">Die Herausforderung</h2>\n<p>Die Aufgabe: Ohne jedes technische Hilfsmittel zur Funk- oder Satelliten-Navigation an Bord sicher und zuverlässig mit dem simulierten Flugzeug einen Cross-Country-Flug vom Start- zum Zielflughafen zu finden. Damit entfällt nicht nur das allgegenwärtige GPS, sondern auch die Nutzung von VOR- und NDB-Empfängern. Was erlaubt ist: eine gute Karte, ein Kompass, eine Uhr und ein guter Plan.</p>\n<p>Inspiration für solche Abenteuer finden sich z.B. in diesem <a href=\"https://www.youtube.com/watch?v=OVYGTa_OUEs\">Youtube-Video, in dem Flugnavigation ohne technische Hilfsmittel im echten Leben</a> zu bewundern ist.</p>\n<div class=\"video-player video-player--youtube\"><iframe allowfullscreen=\"allowfullscreen\" title=\"https://www.youtube.com/watch?v=OVYGTa_OUEs\" src=\"https://www.youtube-nocookie.com/embed/OVYGTa_OUEs?enablejsapi=1\" srcdoc=\"&lt;style&gt;*{padding:0;margin:0;overflow:hidden}html,body{height:100%}img,span{position:absolute;width:100%;top:0;bottom:0;margin:auto}span{height:1.5em;text-align:center;font:48px/1.5 sans-serif;color:white;text-shadow:0 0 0.5em black}&lt;/style&gt;&lt;a href=&quot;https://www.youtube.com/embed/OVYGTa_OUEs?autoplay=1&quot;&gt;&lt;img src=&quot;https://img.youtube.com/vi/OVYGTa_OUEs/hqdefault.jpg&quot; alt=&quot;&quot;&gt;&lt;span&gt;▶&lt;/span&gt;&lt;/a&gt;\"></iframe><!-- img src=\"https://img.youtube.com/vi/OVYGTa_OUEs/hqdefault.jpg\" --></div>\n<p><a href=\"https://de.wikipedia.org/wiki/Sichtflug\">VFR</a> nach diesen Regeln verändert deutlich die Art und Weise, wie ein Flug in einem Simulator durchgeführt werden muss:</p>\n<ol>\n<li>Vor der Flugplanung muss deutlich genauer das <strong>Wetter</strong> überprüft werden. Nicht nur eine hinreichend hohe Sichtweite muss gegeben sein auch der Wind spielt beim VFR eine wichtigere Rolle als bei der Fliegerei mit Navigationsunterstützung.</li>\n<li>Im Vorfeld muss ein <strong>präziser Flugplan</strong> ausgearbeitet werden, bei dem der jeweilige Kurs und die Distanzen vermerkt werden müssen, sowie die daraus resultierenden Zeiten.</li>\n<li>Der Flugplan muss dabei nicht zwangläufig der kürzeste Weg sein, sondern vor allen Dingen sich an <strong>aus der Luft sichtbaren Merkmalen</strong> orientieren.</li>\n<li>Im Flug wiederum wollen der <strong>Kurs, die Geschwindigkeit und die Zeit</strong> beachtet werden, um ein Gefühl dafür zu bekommen, wie weit man auf dem Flugplan bereits gekommen ist.</li>\n<li>Und nicht zuletzt muss der Pilot beständig aus dem Fenster schauen, um <strong>Geländemerkmale wieder zu erkennen</strong>, an Hand derer er oder sie seine Position feststellen kann.</li>\n</ol>\n<p>Statt also seine Hände in den Schoß und sein Schicksal in die Hände des Autopiloten zu legen, ist bei Gelände-VFR-Flügen Aufmerksamkeit und Konzentration gefragt.</p>\n<p><strong>Disclaimer:</strong> Natürlich ist diese Anleitung weder vollständig, professionell, noch für die Verwendung im wahren Leben geeignet. Andererseits kann diese Anleitung auch für andere Simulatoren genutzt werden, wie zum Beispiel den <i>Microsoft Flight Simulator</i> oder <i>X-Plane</i>.</p>\n<h2 id=\"aeroflys-arbeitspferde-für-gelände-vfr\">Aeroflys Arbeitspferde für Gelände-VFR</h2>\n<p>In <i>Aerofly FS2</i> gibt es mehrere Fluggeräte, die heimliches Spicken auf etwaigen Navigationsgeräten unterbinden… weil sie nämlich über keine Navigationsgeräte verfügen. Neben den Flugzeugen aus dem Ersten und Zweiten Weltkrieg eignen sich vor allen Dingen die Doppeldecker im Bestand sehr für VFR-Fliegerei: Sowohl die <i><a href=\"https://de.wikipedia.org/wiki/B%C3%BCcker_B%C3%BC_133\">Bückner Jungmeister</a></i> als auch die <i><a href=\"https://de.wikipedia.org/wiki/Pitts_Special\">Pitts S-2</a></i> verfügen über eine ausgezeichnete Aussicht und keinen einzigen Funknavigations-Empfänger.</p>\n<p>Bei X-Plane eignet sich z.B. die mitgelieferte <i>Aero-Works Aerolite 103</i> oder <i>Stinson L-5 Sentinel</i> für Flüge ohne Navigations-Bordinstrumente.</p>\n<p><span class=\"figure default\"><a href=\"https://journal.3960.org/posts/2019-09-22-vfr-ohne-technischen-schnickschnack/pitts-s-2.jpg\" class=\"gallery__link\"><img src=\"https://journal.3960.org/posts/2019-09-22-vfr-ohne-technischen-schnickschnack/pitts-s-2-400x225.jpg\" class=\"default\" width=\"400\" height=\"225\" style=\"--aspect-ratio: 400/225;\" alt=\"Taxifahrer brauchen kein GPS: Unterwegs mit der Pitts S-2\" /></a><span class=\"figcaption\" aria-hidden=\"true\">Taxifahrer brauchen kein GPS: Unterwegs mit der Pitts S-2<br /></span></span></p>\n<h2 id=\"wetter-wichtiger-denn-je\">Wetter: Wichtiger denn je</h2>\n<p>Schon vor Beginn der eigentlichen Flugplanung muss ein scharfer Blick in die Wetterdaten geworfen werden. Die Mindestanforderungen sind natürlich die <a href=\"https://de.wikipedia.org/wiki/Visual_Meteorological_Conditions\">Visual Meteorological Conditions</a> (VMC). Für VFR (MVFR) muss die <strong>Sichtweite</strong> mindestens 5SM (3SM) und die <strong>Wolkenuntergrenze</strong> mindestens 3.000ft (1.000ft) sein. Besseres Wetter ist natürlich zu bevorzugen, da das <em>Gelände</em> sichtbar sein muss.</p>\n<p>Zu beachten ist die Korrelation zwischen Wolken und <strong>Flughöhe</strong>: Da unsere Flughöhe <em>mindestens</em> 500ft über dem nächsten Hindernis in 2.000ft Umkreis sein muss (bzw. 1000ft über dem nächsten Hindernis in 2.000ft Umkreis in bebauten Gelände), kann nicht jedes Wetter unterflogen werden. Außerdem sollten wir eine Flughöhe von 3.000ft AGL nicht überschreiten, um das Gelände im Blick zu behalten. Nicht zuletzt sollte die Regel bedacht werden, dass je nach Kurs eine unterschiedliche Flughöhen eingehalten werden muss: </p>\n<div class=\"table-wrapper\"><table>\n<colgroup>\n<col class=\"table-cell--right\" />\n<col class=\"table-cell--right\" />\n</colgroup>\n<thead>\n<tr>\n<th style=\"text-align:right\">Kurs 0179°</th>\n<th style=\"text-align:right\">Kurs 180359°</th>\n</tr>\n</thead>\n<tbody><tr>\n<td style=\"text-align:right\">1.500ft MSL</td>\n<td style=\"text-align:right\">2.500ft MSL</td>\n</tr>\n<tr>\n<td style=\"text-align:right\">3.500ft MSL</td>\n<td style=\"text-align:right\">4.500ft MSL</td>\n</tr>\n<tr>\n<td style=\"text-align:right\">5.500ft MSL</td>\n<td style=\"text-align:right\">6.500ft MSL</td>\n</tr>\n<tr>\n<td style=\"text-align:right\">7.500ft MSL</td>\n<td style=\"text-align:right\">8.500ft MSL</td>\n</tr>\n<tr>\n<td style=\"text-align:right\">9.500ft MSL</td>\n<td style=\"text-align:right\">10.500ft MSL</td>\n</tr>\n<tr>\n<td style=\"text-align:right\">11.500ft MSL</td>\n<td style=\"text-align:right\">12.500ft MSL</td>\n</tr>\n</tbody></table></div>\n<p>All diese Bedingungen zusammen machen die Flugplanung nochmals herausfordernd.</p>\n<p>Nicht zuletzt muss die <strong>Windrichtung und -stärke</strong> vermerkt werden. Je nach eigener Flugrichtung und -geschwindigkeit wird <a href=\"https://3960.org/sandbox/wind-deviation.html\">Wind den eigenen Kurs verfälschen und sollte von vorne herein mit einkalkuliert werden</a>.</p>\n<h2 id=\"flugpläne-für-sichtflieger\">Flugpläne für Sichtflieger</h2>\n<p>Grundlage für einen Cross-Country-VFR-Flug ist ein gut durchdachter Flugplan. Glücklicherweise hat Aerofly FS2 ein eingebautes Tool zur Erstellung einfacher Flugpläne.</p>\n<p>Für eine besondere Herausforderung sorgt die Tatsache, dass eher tief geflogen wird. Dementsprechend muss bei der Planung berücksichtigt werden, ob es Hindernisse oder Flugverbotszonen gibt, die den eigenen Flugplan beeinflussen.</p>\n<p>Flugpläne werden vom Start zum Ziel gedanklich in <strong>Streckenabschnitte</strong> zerlegt. Dabei ist es sinnvoll, Geländemerkmale zu finden, die den <strong>Verlauf</strong> und das <strong>Ende</strong> jedes einzelnen Streckenabschnitts markieren. Auch hierbei unterstützt Aerofly FS2, indem es automatisch Wegpunkte (und damit Streckenabschnitte) in den Flugplan einfügt.</p>\n<p>Für einen Flugplan geeignete <strong>Geländemerkmale</strong> müssen gut aus der Luft erkennbar sein. Wichtig ist dabei, sich wirklich <em>große</em> Merkmale auszusuchen. Ein vom Boden aus imposanter Hügel kann aus der Luft einfach nur wie ein <em>flacher</em> Hügel aussehen, oder ein malerisch von Bäumen eingefasster Fluss aus der Luft fast unsichtbar sein.</p>\n<p>Für den letzten Streckenabschnitt gibt es auf jeden Fall ein gut sichtbares Geländemerkmal: Den Zielflughafen. </p>\n<h2 id=\"die-verwendung-von-geländemerkmalen\">Die Verwendung von Geländemerkmalen</h2>\n<p>Folgende Geländemerkmale eignen sich in der Regel sehr gut:</p>\n<ul>\n<li>Küstenlinien, z.B. von Meeren (unübersehbar), Seen und große Flüsse</li>\n<li>Markante Berge bzw. hohe Bergketten</li>\n<li>Größere Areale mit auffälliger Vegetation oder Bebauung</li>\n<li>Große Straßen (auf denen Nachts auch Verkehr ist)</li>\n</ul>\n<p>Dabei unterscheidet man <em>linienförmige</em> von <em>punktförmigen</em> Geländemerkmalen. Linien werden z.B. durch Küstenlinien, Vegetationsgrenzen, Straßen oder Wasserwege erzeugt alles, was länger als ein paar Kilometer ist. Punktförmige Geländemerkmale sind z.B. markante Bergspitzen, Seen oder Bauwerke.</p>\n<p>Ein gutes Hilfsmittel zur Identifikation von Geländemerkmalen sind Luft- oder Satellitenaufnahmen.</p>\n<p><span class=\"figure default\"><a href=\"https://journal.3960.org/posts/2019-09-22-vfr-ohne-technischen-schnickschnack/ocean-reef.jpg\" class=\"gallery__link\"><img src=\"https://journal.3960.org/posts/2019-09-22-vfr-ohne-technischen-schnickschnack/ocean-reef-400x225.jpg\" class=\"default\" width=\"400\" height=\"225\" style=\"--aspect-ratio: 400/225;\" alt=\"Ausflug zum Golf(en), immer der Straße nach\" /></a><span class=\"figcaption\" aria-hidden=\"true\">Ausflug zum Golf(en), immer der Straße nach<br /></span></span></p>\n<p>Geländemerkmale könne auf vielfältige Weise für den Flugplan verwendet werden:</p>\n<h3 id=\"1-leitlinien\">1. Leitlinien</h3>\n<p>Die einfachste Methode ist es, einem linienförmigen Geländemerkmal als <strong>Leitlinie</strong> zu verwenden, dem der Flugplan bzw. das Flugzeug folgen muss. Der Flugplan wird z.B. parallel zu einer großen Straße oder einer Bergkette gelegt, an der entlang geflogen wird. Damit entfällt die Aufgabe, den Kurs des Flugzeugs zu überwachen.</p>\n<p>In den meisten Fällen werden Geländemerkmale nicht direkt zum Zielflughafen führen. Wichtig ist es also für den Piloten, einen Anhaltspunkt für das <strong>Ende eines Streckenabschnitts</strong> zu haben, zum Beispiel ein weiteres Geländemerkmal.</p>\n<p><span class=\"figure default\"><a href=\"https://journal.3960.org/posts/2019-09-22-vfr-ohne-technischen-schnickschnack/ocean-reef-visual.jpg\" class=\"gallery__link\"><img src=\"https://journal.3960.org/posts/2019-09-22-vfr-ohne-technischen-schnickschnack/ocean-reef-visual-400x225.jpg\" class=\"default\" width=\"400\" height=\"225\" style=\"--aspect-ratio: 400/225;\" alt=\"Highways sind aus der Luft eine Augenweide\" /></a><span class=\"figcaption\" aria-hidden=\"true\">Highways sind aus der Luft eine Augenweide<br /></span></span></p>\n<h3 id=\"2-auffanglinien\">2. Auffanglinien</h3>\n<p>Eine sehr gute Methode zur Orientierung ist die Verwendung einer <strong>Auffanglinie</strong>. Dabei wird der aktuelle Streckenabschnitt von einem anderen, gut sichtbaren linienförmigen Geländemerkmal gekreuzt und ergibt somit ein deutlich sichtbares Signal, an welcher Stelle des Streckenabschnitts man sich befindet. Sinnigerweise ist eine Auffanglinie am Ende eines Streckenabschnitts vorhanden, so dass das Ende des Abschnitts unübersehbar wird.</p>\n<p>Das Prinzip der Auffanglinie ist vielseitig nutzbar. So können Streckenabschnitte <em>ohne</em> Leitlinie auskommen, solange das Ende des Abschnitts von einem quer zur Flugrichtung verlaufenden Geländemerkmal begrenzt wird. Dabei ist es dann auch nicht so wichtig, auf welchem Punkt das eigene Flugzeug genau auf die Auffanglinie trifft, solange man sich sicher ist, ob der Linie dann nach links oder rechts gefolgt werden muss. Hier hilft ggf. der Trick, weiter nach links zu zielen, wenn man an der Auffanglinie nach rechts fliegen muss bzw. umgekehrt.</p>\n<p>Ein ausgezeichnetes Beispiel für eine gut nutzbare Auffanglinie ist z.B. die <a href=\"https://de.wikipedia.org/wiki/Porta_Westfalica_%28Weserdurchbruch%29\">Porta Westfalica</a>, eine von einem Fluss durchbrochene Bergkette… oder der <a href=\"https://de.wikipedia.org/wiki/Overseas_Highway\">Overseas Highway in Florida</a>, der von Norden kommend schwer zu verfehlen ist.</p>\n<p><span class=\"figure default\"><a href=\"https://journal.3960.org/posts/2019-09-22-vfr-ohne-technischen-schnickschnack/flamingo.jpg\" class=\"gallery__link\"><img src=\"https://journal.3960.org/posts/2019-09-22-vfr-ohne-technischen-schnickschnack/flamingo-400x225.jpg\" class=\"default\" width=\"400\" height=\"225\" style=\"--aspect-ratio: 400/225;\" alt=\"Auf zu den Flamingos - die Küste fängt uns auf\" /></a><span class=\"figcaption\" aria-hidden=\"true\">Auf zu den Flamingos - die Küste fängt uns auf<br /></span></span></p>\n<h3 id=\"3-orientierungspunkte\">3. Orientierungspunkte</h3>\n<p>Auf Streckenabschnitte können an Stelle von Auffanglinien auch <strong>Orientierungspunkte</strong> verwendet werden, um den Fortschritt entlang des Streckenabschnitts einschätzen zu können, oder um das Ende des aktuellen Streckenabschnitts zu markieren.</p>\n<p>Städte, Industriekomplexe, auffällige Brücken oder Flughäfen sind hervorragende Möglichkeiten, eindeutig seine Position festzulegen. Ein todsicheres Zeichen für das Erreichen des letzten Streckenabschnittes ist in der Regel ein Flughafen, der Tag wie Nacht gut zu sehen sein sollte.</p>\n<p>Im Gegensatz zu linienartigen Geländemerkmalen besteht bei punktförmigen Geländemerkmalen aber immer die Gefahr, diese zu verfehlen oder schlicht zu übersehen.</p>\n<h3 id=\"4-ohne-gelände-zeitmessung-via-stoppuhr\">4. Ohne Gelände: Zeitmessung via Stoppuhr</h3>\n<p>Das größte Problem besteht bei Flugplänen über eintöniges Gelände <em>ohne</em> Leit- und Auffanglinien sowie <em>ohne</em> Orientierungspunkte wenn zum Beispiel das Ziel eine einzelne Insel weit draußen im Meer ist. Da die Landschaft hier keinen Anhaltspunkt für Abweichungen vom Kurs darstellt, hilft hier nur die penible Messung von Kurs und Zeit. Die im Vorfeld berechneten Längen des Streckenabschnitts kann durch die Fluggeschwindigkeit geteilt werden, um die <strong>Flugdauer für einen Streckenabschnitt</strong> zu berechnen. Wichtig ist dabei, die Einheiten korrekt umzurechnen:</p>\n<ul>\n<li>1 Nautische Meile = 1,852 km</li>\n<li>1 Standardmeile = 1,609 km</li>\n<li>1 Knoten = 1 <em>Nautische Meile</em> / h</li>\n</ul>\n<p>Daraus resultiert: Zeit (h) = Strecke (NM) / Geschwindigkeit (kts)</p>\n<p>Zu Beginn des Streckenabschnitts wird eine Stoppuhr gestartet, so dass beim Erreichen der vorher kalkulierten Zeit der Pilot weiß, dass er das Ende des Streckenabschnitts erreicht hat. Dummerweise hat diese Methode den Nachteil, dass viele Faktoren die tatsächliche Flugzeit beeinflussen. Hier hilft nur die strikte Kontrolle des Kurses und der Geschwindigkeit und ein waches Auge.</p>\n<h2 id=\"vom-winde-verweht-kurs--geschwindigkeit\">Vom Winde verweht: Kurs &amp; Geschwindigkeit</h2>\n<p>Das eigentliche Problem beim Abfliegen eines Flugplans nach Kompass ohne weitere Geländemerkmale ist, dass Windrichtung und -geschwindigkeit die Position des Flugzeugs unbemerkt verändern können. Während Gegenwind die Geschwindigkeit über dem Boden herab- und Rückenwind die Geschwindigkeit über dem Boden heraufsetzt, kann Seitenwind das Flugzeug vom eigentlich geplanten Kurs abbringen.</p>\n<p><span class=\"figure default\"><a href=\"https://journal.3960.org/posts/2019-09-22-vfr-ohne-technischen-schnickschnack/tortuga.jpg\" class=\"gallery__link\"><img src=\"https://journal.3960.org/posts/2019-09-22-vfr-ohne-technischen-schnickschnack/tortuga-400x225.jpg\" class=\"default\" width=\"400\" height=\"225\" style=\"--aspect-ratio: 400/225;\" alt=\"Schildkröten lieben die Einsamkeit: Dry Tortugas, irgendwo im Golf von Mexiko\" /></a><span class=\"figcaption\" aria-hidden=\"true\">Schildkröten lieben die Einsamkeit: Dry Tortugas, irgendwo im Golf von Mexiko<br /></span></span></p>\n<p>Dabei gibt es keine Instrument an Bord, die auf diese Umstände hinweisen: Die Geschwindigkeit eines Flugzeugs wird an Bord des Flugzeugs <em>relativ</em> zur umgebenden Luft angezeigt. Das kann unter anderem dafür sorgen, dass <a href=\"https://www.livescience.com/61501-norwegian-jet-stream-transatlantic-record.html\">Flugzeug eine fantastische Geschwindigkeit über dem Boden erreichen, die sie als wahre Geschwindigkeit relativ zur sie umgebenden Luft niemals überstehen würden</a>. Und das ein starker Seitenwind das Flugzeug seitwärts vom Kurs drückt, verändert den Kompass an Bord ebenfalls nicht ein Flugzeug muss nicht zwangsläufig in die Richtung zeigen, in die es fliegt. Das erleben Instrumentenflieger, wenn sie versuchen, <a href=\"https://journal.3960.org/posts/2017-12-17-vor-freude-ifr-mit-aerofly-fs2/\">auf einem eingestellten Radial zu bleiben</a>.</p>\n<p>Dementsprechend ist es wichtig, vor dem Abflug (und sinnigerweise auch unterwegs) die genaue Windrichtung und -geschwindigkeit zu kennen, und die Auswirkung auf den eigenen Kurs einzukalkulieren. Während bei Gegen- und Rückenwind keine Auswirkungen auf den Kurs zu befürchten sind, sondern nur auf die Geschwindigkeit über dem Boden, ist die korrekte Einschätzung von Seitenwinden deutlich schwieriger. Mit ein bisschen angewandter Trigonometrie kann man diese Berechnungen selber durchführen ich persönlich habe mir <a href=\"https://3960.org/sandbox/wind-deviation.html\">einen kleinen Rechner zum Berechnen des Korrekturkurses und der tatsächlichen Geschwindigkeit</a> gebaut.</p>\n<h2 id=\"fazit\">Fazit</h2>\n<p>Die Welt der GPS-Navigation und Autopiloten hat euch den Spaß am Fliegen genommen? Dann macht mit beim <i>VFR</i>. Selbst kurze Strecken werden zur fliegerischen Herausforderung und ihr erlebt eine ganz neue Verbundenheit mit eurer Umgebung, da auf einmal jede Straße, jeder Fluss und jedes Gebirge relevant wird.</p><img src=\"https://stats.3960.org/p.php?idsite=8amp;action_name=VFR%20ohne%20technischen%20Schnickschnack&amp;url=https%3A%2F%2Fjournal.3960.org%2Fposts%2F2019-09-22-vfr-ohne-technischen-schnickschnack%2F%3Futm_source%3Dnewsfeed_view\" style=\"border:0;\" alt=\"\" />",
"summary": "Mein aktueller Lieblings-Flugsimulator Aerofly FS2 überredet mich immer wieder zu neuen Experimenten. Nachdem ich IFR ohne GPS in Aerofly FS2 ausprobiert…",
"date_published": "2019-09-22T18:43:14+02:00",
"date_modified": "2020-02-07T14:31:40+01:00",
"author": {
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
},
"authors": [
{
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
}
],
"banner_image": "https://journal.3960.org/posts/2019-09-22-vfr-ohne-technischen-schnickschnack/sunset.jpg",
"language": "de-DE",
"image": "https://journal.3960.org/posts/2019-09-22-vfr-ohne-technischen-schnickschnack/sunset.jpg",
"tags": [
"Aerofly FS2",
"Fliegerei",
"Geografie",
"Simulation",
"Spiel",
"X-Plane"
],
"_geo": {
"about": "http://geojson.org/",
"type": "Point",
"coordinates": [
-80.343874,
25.279406
]
}
},
{
"id": "user/posts/2019-09-16-f-16-fighting-falcon-fuer-dcs/index.md",
"url": "https://journal.3960.org/posts/2019-09-16-f-16-fighting-falcon-fuer-dcs/",
"title": "Die F-16 Fighting Falcon für DCS",
"content_html": "<div class=\"video-player video-player--youtube\"><iframe allowfullscreen=\"allowfullscreen\" title=\"https://www.youtube.com/watch?v=8QfANpD0GHY\" src=\"https://www.youtube-nocookie.com/embed/8QfANpD0GHY?enablejsapi=1\" srcdoc=\"&lt;style&gt;*{padding:0;margin:0;overflow:hidden}html,body{height:100%}img,span{position:absolute;width:100%;top:0;bottom:0;margin:auto}span{height:1.5em;text-align:center;font:48px/1.5 sans-serif;color:white;text-shadow:0 0 0.5em black}&lt;/style&gt;&lt;a href=&quot;https://www.youtube.com/embed/8QfANpD0GHY?autoplay=1&quot;&gt;&lt;img src=&quot;https://img.youtube.com/vi/8QfANpD0GHY/hqdefault.jpg&quot; alt=&quot;&quot;&gt;&lt;span&gt;▶&lt;/span&gt;&lt;/a&gt;\"></iframe><!-- img src=\"https://img.youtube.com/vi/8QfANpD0GHY/hqdefault.jpg\" --></div>\n<p>Endlich! Nachdem für den <a href=\"https://www.digitalcombatsimulator.com/de/\">Digital Combat Simulator</a> bereits jetzt eine riesige Palette an Fluggeräten erhältlich ist, produziert Eagle Dynamics nun selber den Klassiker unter den westlichen Kampfflugzeugen: Die <a href=\"https://en.wikipedia.org/wiki/General_Dynamics_F-16_Fighting_Falcon\">F-16 Fighting Falcon aka „Viper“</a>.</p>\n<!-- more -->\n<p id=\"more\">Dieses Flugzeug befindet sich seit 1974 in Produktion, und wird auch heute nach über 40 Jahren immer noch hergestellt wenn auch die neueren Ausgaben der F-16 Block 60 sich gegenüber dem Ursprungsmodell sowohl von der Leistung als auch von der Sensorik her stark weiter entwickelt haben. Von de F-16 wurden bis heute über 4.000 Einheiten hergestellt und in über 20 Ländern in Dienst gestellt.</p>\n<p>DCS hatte schon immer eine ansprechende Palette von westlichen Kampfflugzeugen: A-10 Warthog, F-5 Tiger, F-14 Tomcat, F-15 Eagle, F-18 Hornet, AV-8B Harrier. Aber die F-16 war und ist <em>das</em> ikonische Kampfflugzeug der NATO. Wenn also nichts dazwischen kommt, steige ich demnächst von meiner (kostenlosen) Su-25 Frogfoot auf die F-16 um.</p>\n<p>Ich persönlich war schon früh der (simulierten) F-16 verbunden: Schon auf dem Commodore C-64 hatte ich mit <a href=\"https://www.mobygames.com/game/f-16-combat-pilot\">Digital Integrations <i>F-16 Combat Pilot</i></a> meine ersten Erfahrungen gemacht. Und obwohl ich die legendäre <a href=\"https://www.mobygames.com/game-group/falcon-series\">Spectrum Holobytes <i>Falcon</i>-Reihe</a> nur kurz gestreift habe, so habe ich doch zumindest in <a href=\"https://www.mobygames.com/game/strike-commander\"><i>Strike Commander</i></a> (einem Ableger der <i>Wing Commander</i>-Serie) die F-16 (simuliert) geflogen. So oder so ist die <a href=\"https://www.mobygames.com/game-group/aircraft-f-16-fighting-falcon\">F-16 ein in unzähligen Computerspielen und -simulationen auftretender Kampfjet</a>.</p>\n<p>DCS bzw. Eagle Dynamics haben übrigens schon begonnen, Schulungsvideos bei Youtube einzustellen damit zukünftige DCS-F-16-Piloten sich schonmal mit ihrem neuen Arbeitsgerät vertraut machen können.</p>\n<div class=\"video-player video-player--youtube\"><iframe allowfullscreen=\"allowfullscreen\" title=\"https://www.youtube.com/watch?v=Jpug6-Si_i0\" src=\"https://www.youtube-nocookie.com/embed/Jpug6-Si_i0?enablejsapi=1\" srcdoc=\"&lt;style&gt;*{padding:0;margin:0;overflow:hidden}html,body{height:100%}img,span{position:absolute;width:100%;top:0;bottom:0;margin:auto}span{height:1.5em;text-align:center;font:48px/1.5 sans-serif;color:white;text-shadow:0 0 0.5em black}&lt;/style&gt;&lt;a href=&quot;https://www.youtube.com/embed/Jpug6-Si_i0?autoplay=1&quot;&gt;&lt;img src=&quot;https://img.youtube.com/vi/Jpug6-Si_i0/hqdefault.jpg&quot; alt=&quot;&quot;&gt;&lt;span&gt;▶&lt;/span&gt;&lt;/a&gt;\"></iframe><!-- img src=\"https://img.youtube.com/vi/Jpug6-Si_i0/hqdefault.jpg\" --></div><img src=\"https://stats.3960.org/p.php?idsite=8amp;action_name=Die%20F-16%20Fighting%20Falcon%20f%C3%BCr%20DCS&amp;url=https%3A%2F%2Fjournal.3960.org%2Fposts%2F2019-09-16-f-16-fighting-falcon-fuer-dcs%2F%3Futm_source%3Dnewsfeed_view\" style=\"border:0;\" alt=\"\" />",
"summary": "Endlich! Nachdem für den Digital Combat Simulator bereits jetzt eine riesige Palette an Fluggeräten erhältlich ist, produziert Eagle Dynamics nun selber den…",
"date_published": "2019-09-16T18:01:22+02:00",
"date_modified": "2019-09-29T17:43:04+02:00",
"author": {
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
},
"authors": [
{
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
}
],
"banner_image": "https://img.youtube.com/vi/8QfANpD0GHY/hqdefault.jpg",
"language": "de-DE",
"image": "https://img.youtube.com/vi/8QfANpD0GHY/hqdefault.jpg",
"tags": [
"DCS",
"Fliegerei",
"Simulation",
"Spiel",
"Militär"
]
},
{
"id": "user/posts/2019-09-13-programmierung-zurueck-zur-werkbank/index.md",
"url": "https://journal.3960.org/posts/2019-09-13-programmierung-zurueck-zur-werkbank/",
"title": "Programmierung: Zurück zur Werkbank",
"content_html": "<p>Wie schon in dem Artikel <a href=\"https://journal.3960.org/posts/2019-04-23-einfachheit-programmierung/\">„Simple &amp; Boring“</a> von Chris Coyier hat auch Bastian Allgeier eine Lanze für Einfachheit in der Programmierung gebrochen. Sein Artikel <a href=\"https://bastianallgeier.com/notes/simplicity-part-2\">„Simplicity (II)“</a> dürfte vielen altgedienten Programmierern aus der Seele sprechen.</p>\n<p>Tatsächlich bemerke ich sowohl in der privaten als auch beruflichen Programmierung den Trend, für mehr Geschwindigkeit ein neues Tool einzusetzen… das kleine Probleme verursacht, die durch ein weiteres Tool gelöst werden müssen… das kleine Probleme verursacht, die durch ein weiteres Tool gelöst werden müssen…</p>\n<figure class=\"blockquote\"><blockquote cite=\"https://bastianallgeier.com/notes/simplicity-part-2\"><p>When everything works, it feels like magic. When something breaks, it&#39;s hell.</p></blockquote>\n<figcaption><a href=\"https://bastianallgeier.com/notes/simplicity-part-2\">Bastian Allgeier, „<cite>Simplicity (II)</cite>“</a></figcaption></figure>\n<p>Der Artikel dreht sich zwar primär darum, was diese Abhängigkeiten gerade für ältere Projekte bedeuten (nämlich, dass Abhängigkeiten nach ein paar Jahren sich nicht wieder auslösen lassen, weil die dafür benötigten Versionen an Tools nicht mehr zur Verfügung stehen), inzwischen bemerke ich aber auch bei aktuellen Projekten die Probleme, die übermäßige Abhängigkeiten für die Entwicklungsgeschwindigkeit bedeuten können, wenn auch nur ein Teil ausfällt.</p><img src=\"https://stats.3960.org/p.php?idsite=8amp;action_name=Programmierung%3A%20Zur%C3%BCck%20zur%20Werkbank&amp;url=https%3A%2F%2Fjournal.3960.org%2Fposts%2F2019-09-13-programmierung-zurueck-zur-werkbank%2F%3Futm_source%3Dnewsfeed_view\" style=\"border:0;\" alt=\"\" />",
"summary": "Wie schon in dem Artikel „Simple & Boring“ von Chris Coyier hat auch Bastian Allgeier eine Lanze für Einfachheit in der Programmierung gebrochen. Sein Artikel…",
"date_published": "2019-09-13T18:23:11+02:00",
"date_modified": "2019-10-17T18:51:03+02:00",
"author": {
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
},
"authors": [
{
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
}
],
"banner_image": "https://cdn.3960.org/favicon-192x192.png",
"language": "de-DE",
"image": "https://cdn.3960.org/favicon-192x192.png",
"external_url": "https://bastianallgeier.com/notes/simplicity-part-2",
"tags": [
"CSS",
"Javascript",
"Meinung",
"PHP",
"Programmierung",
"Webdevelop",
"Geckobar"
]
},
{
"id": "user/posts/2019-05-08-rueckkehr-von-b-und-i/index.md",
"url": "https://journal.3960.org/posts/2019-05-08-rueckkehr-von-b-und-i/",
"title": "Die Rückkehr von <i> und <b>",
"content_html": "<p>Vor vielen Jahren haben Web-Entwickler <code>&lt;i&gt;</code>-, <code>&lt;b&gt;</code>- und <code>&lt;u&gt;</code>-Tags im HTML den Rücken gekehrt.</p>\n<p>In der Anfangsphase von HTML waren Tags und Attribute sowohl für Inhalt als <em>auch</em> Styling zuständig waren. Mit dem Aufkommen von CSS, der Idee von semantischen Layout und Barrierefreiheit wurden Tags aussortiert, die nur für Styling zuständig waren. Und so wurden auch <code>&lt;i&gt;</code>, <code>&lt;b&gt;</code> und <code>&lt;u&gt;</code> mit HTML4 gestrichen, und waren ab dort <i>deprecated</i> bzw. <i>personae non gratae</i>.</p>\n<p>Aber tatsächlich sind sie wieder da! In HTML5 wurden diese HTML-Tags mit neuer Bedeutung wieder eingeführt, und können wieder verwendet werden.</p>\n<!-- more -->\n<h2 id=\"more\">Elemente, die regulär gefettet dargestellt werden</h2>\n<p>Als Ersatz von <code>&lt;b&gt;</code> wurde <code>&lt;strong&gt;</code> propagiert. Tatsächlich haben aber weiterhin <em>beide</em> Tags ihre Relevanz. Das Mozilla Developer Network weiß das folgende über <code>&lt;strong&gt;</code> und <code>&lt;b&gt;</code> zu berichten:</p>\n<figure class=\"blockquote\"><blockquote cite=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/strong\"><p>The <b>HTML Strong Importance Element (<code>&lt;strong&gt;</code>)</b> indicates that its contents have strong importance, seriousness, or urgency.</p></blockquote>\n<figcaption><a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/strong\">MDN-Definition von <code>&lt;strong&gt;</code></a></figcaption></figure>\n<figure class=\"blockquote\"><blockquote cite=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/b\"><p>The <b>HTML Bring Attention To element (<code>&lt;b&gt;</code>)</b> is used to draw the reader&#39;s attention to the element&#39;s contents, which are not otherwise granted special importance.</p></blockquote>\n<figcaption><a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/b\">MDN-Definition von <code>&lt;b&gt;</code></a></figcaption></figure>\n<p>Nach dieser Definition wird <code>&lt;strong&gt;</code> für Wörter verwendet, die man bei Aussprache besonders betonen würde. <code>&lt;b&gt;</code> dagegen empfiehlt sich z.B. für die Hervorhebung von wichtigen Begriffen in einem Text.</p>\n<h2 id=\"elemente-die-regulär-kursiv-dargestellt-werden\">Elemente, die regulär kursiv dargestellt werden</h2>\n<p>Für <code>&lt;i&gt;</code> sollte vor geraumer Zeit nur noch <code>&lt;em&gt;</code> verwendet werden. Aber auch hier hat sich ein Wandel vollzogen. Das Mozilla Developer Network hat folgende Information <code>&lt;em&gt;</code> und <code>&lt;i&gt;</code> parat:</p>\n<figure class=\"blockquote\"><blockquote cite=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/em\"><p>The <b>HTML <code>&lt;em&gt;</code></b> element marks text that has stress emphasis.</p></blockquote>\n<figcaption><a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/em\">MDN-Definition von <code>&lt;em&gt;</code></a></figcaption></figure>\n<figure class=\"blockquote\"><blockquote cite=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/i\"><p>The <b>HTML <code>&lt;i&gt;</code></b> element represents a range of text that is set off from the normal text for some reason. Some examples include technical terms, foreign language phrases, or fictional character thoughts.</p></blockquote>\n<figcaption><a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/i\">MDN-Definition von <code>&lt;i&gt;</code></a></figcaption></figure>\n<p>Dementsprechend wird <code>&lt;em&gt;</code> für Wörter verwendet, die bei Aussprache besonders betont werden würden. Mit <code>&lt;i&gt;</code> dagegen würden spezielle Begriffe und Wörter aus dem Text herausgehoben werden.</p>\n<h2 id=\"und-sogar-unterstrichene-elemente\">Und sogar unterstrichene Elemente</h2>\n<p>Selbst das verpönte <code>&lt;u&gt;</code> hat eine Wiederauferstehung erlebt:</p>\n<figure class=\"blockquote\"><blockquote cite=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/u\"><p>The <b>HTML Unarticulated Annotation Element (<code>&lt;u&gt;</code>)</b> represents a span of inline text which should be rendered in a way that indicates that it has a non-textual annotation.</p></blockquote>\n<figcaption><a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/u\">MDN-Definition von <code>&lt;u&gt;</code></a></figcaption></figure>\n<p>…wobei im Beispiel von MDN die rote Unterkringelung von falsch geschriebenen Wörtern aufgeführt wird.</p>\n<h2 id=\"die-verwendung-von-i-und-b-in-markdown\">Die Verwendung von <code>&lt;i&gt;</code> und <code>&lt;b&gt;</code> in Markdown</h2>\n<p>In <a href=\"https://daringfireball.net/projects/markdown/basics\">Markdown</a> wird mit <code>_Wort_</code> bzw. <code>*Wort*</code> immer ein <code>&lt;em&gt;Wort&lt;/em&gt;</code>, mit <code>__Wort__</code> bzw. <code>**Wort**</code> immer ein <code>&lt;strong&gt;Wort&lt;/strong&gt;</code> erzeugt. Um <code>&lt;i&gt;</code> und <code>&lt;b&gt;</code> in Markdown zu erzeugen gibt es <em>keine</em> Symbole.</p>\n<p>Dafür erlaubt Markdown aber die Verwendung von HTML-Tags! Wenn in Markdown also <code>&lt;b&gt;Wort&lt;/b&gt;</code> eingegeben wird, wird auch <code>&lt;b&gt;Wort&lt;/b&gt;</code> ausgegeben. Demzufolge ist dies hier ein valider Markdown-Text:</p>\n<pre><code class=\"language-markdown\">Hier kommt ein <i>_kursives Wort_</i>, gefolgt von einem <i>*kursiven Wort*</i>, beide mit <samp>`&lt;em&gt;`</samp> geschrieben.\n\nHier kommt ein <i>__gefettetes Wort__</i>, gefolgt von einem <i>**gefetteten Wort**</i>, beide mit <samp>`&lt;strong&gt;`</samp> geschrieben.\n\nHier dagegen kommt ein &lt;i&gt;kursives Wort&lt;/i&gt;, mit <samp>`&lt;i&gt;`</samp> geschrieben.\n\nUnd hier kommt ein &lt;b&gt;gefettetes Wort&lt;/b&gt;, mit <samp>`&lt;b&gt;`</samp> geschrieben.</code></pre>\n<h2 id=\"fazit\">Fazit</h2>\n<p>Viele von HTML-Entwicklern als Dogmen verstandene Leitsätze müssen immer wieder überprüft werden. Genau so wie die Vorstellung falsch ist, dass <code>&lt;table&gt;</code>- und <code>&lt;div&gt;</code>-Tags oder <code>id</code>-Attribute nicht verwenden werden dürften, ist die Verwendung von <code>&lt;i&gt;</code>, <code>&lt;b&gt;</code> und <code>&lt;u&gt;</code> im richtigen Kontext nicht nur erlaubt, sondern tatsächlich eine sehr gute Idee.</p><img src=\"https://stats.3960.org/p.php?idsite=8amp;action_name=Die%20R%C3%BCckkehr%20von%20%3Ci%3E%20und%20%3Cb%3E&amp;url=https%3A%2F%2Fjournal.3960.org%2Fposts%2F2019-05-08-rueckkehr-von-b-und-i%2F%3Futm_source%3Dnewsfeed_view\" style=\"border:0;\" alt=\"\" />",
"summary": "Vor vielen Jahren haben Web-Entwickler <i>-, <b>- und <u>-Tags im HTML den Rücken gekehrt.\nIn der Anfangsphase von HTML waren Tags und Attribute sowohl für…",
"date_published": "2019-05-08T19:10:30+02:00",
"date_modified": "2019-10-17T18:50:52+02:00",
"author": {
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
},
"authors": [
{
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
}
],
"banner_image": "https://cdn.3960.org/favicon-192x192.png",
"language": "de-DE",
"image": "https://cdn.3960.org/favicon-192x192.png",
"tags": [
"Blog",
"Programmierung",
"Webdevelop"
]
},
{
"id": "user/posts/2019-04-24-verantwortung-von-software/index.md",
"url": "https://journal.3960.org/posts/2019-04-24-verantwortung-von-software/",
"title": "Die Verantwortung von Software",
"content_html": "<p>Ein Tipp von den Wedeler Jungs: Gregory Travis erklärt aus seiner Erfahrung als Programmierer <em>und</em> Pilot, warum <a href=\"https://spectrum.ieee.org/aerospace/aviation/how-the-boeing-737-max-disaster-looks-to-a-software-developer\">Flugzeugbau und Softwarebau zwei sehr unterschiedliche Grundphilosophien haben, die nicht gut zueinander passen</a> am Beispiel des Abstürze der Boeing 737 Max.</p>\n<!-- more -->\n<p id=\"more\">Tatsächlich finde ich genug Beispiele: Das Smartphone hat einen größerer Bug? Keine Angst, es wird ein Update geben. Der Staubsauger-Roboter bleibt öfter an Teppich-Kanten hängen? Kein Problem, da kommt früher oder später ein Update. Die Rumble-Packs der WMR-Brille funktionieren nicht? Nach dem nächsten Update tun sie das bestimmt. In dem Spiel fehlen versprochene Features? Ach, das werden die Entwickler früher oder später schon nachliefern.</p>\n<p>Als Software-Entwickler verlassen wir uns sehr darauf, dass wir Fehler später immer noch korrigieren können. Wir verzichten auf Testing, QA, Methoden zur Fehlerbehandlung, Exception-Abarbeitung, Prüfung von Variablen, Quoting, saubere Typisierung weil für uns als Entwickler nicht viel davon abhängt, als gegebenenfalls später ein Patch dafür bauen zu müssen. Zum Glück leben wir ja nicht mehr in der Zeit, in der Software auf einem Datenträger verteilt werden muss oder auf ein Modul gebrannt wird, und dort bis in alle Ewigkeit funktionieren muss.</p>\n<p>Tatsächlich sollten wir als Programmierer etwas mehr Ehrfurcht vor unserer Aufgabe haben und diese Ehrfurcht auch einfordern. Außerdem sollten wir uns selber einen defensiven Programmierstil auferlegen. In diesem Zusammenhang möchte ich nochmals auf <strong><a href=\"https://de.wikipedia.org/wiki/Kalaschnikow\">Kalashnikov</a>-Programmierung</strong> hinweisen: </p>\n<blockquote><p>Die Programmierung muss nicht technisch herausragend sein sie muss robust, unter jeder Umgebung einsatzbereit und einfach zu reparieren sein.</p></blockquote>\n<p>Sie auch den Artikel über die <a href=\"https://journal.3960.org/posts/2019-04-23-einfachheit-programmierung/\">die Vorzüge einfacher Programmierung</a>.</p><img src=\"https://stats.3960.org/p.php?idsite=8amp;action_name=Die%20Verantwortung%20von%20Software&amp;url=https%3A%2F%2Fjournal.3960.org%2Fposts%2F2019-04-24-verantwortung-von-software%2F%3Futm_source%3Dnewsfeed_view\" style=\"border:0;\" alt=\"\" />",
"summary": "Ein Tipp von den Wedeler Jungs: Gregory Travis erklärt aus seiner Erfahrung als Programmierer und Pilot, warum Flugzeugbau und Softwarebau zwei sehr…",
"date_published": "2019-04-24T19:02:28+02:00",
"date_modified": "2019-04-24T19:02:28+02:00",
"author": {
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
},
"authors": [
{
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
}
],
"banner_image": "https://cdn.3960.org/favicon-192x192.png",
"language": "de-DE",
"image": "https://cdn.3960.org/favicon-192x192.png",
"tags": [
"Fliegerei",
"Geckobar",
"Programmierung",
"Technologie"
]
},
{
"id": "user/posts/2019-04-23-einfachheit-programmierung/index.md",
"url": "https://journal.3960.org/posts/2019-04-23-einfachheit-programmierung/",
"title": "Einfachheit in Programmierung",
"content_html": "<p>Meine persönlichen Grundsätze für Programmierung finden sich bestens in dem Artikel <a href=\"https://css-tricks.com/simple-boring/\">Simple &amp; Boring</a> zusammengefasst. Meine eigenen Ideen dazu:</p>\n<p>Wenn ich ein neues Tool, ein neues Konzept oder eine neue Sprache verwenden möchte, frage ich mich vorher: <em>Welches Problem löst das?</em> Außerdem eine gute Frage: <em>Welche Probleme verursacht das?</em></p>\n<p>Außerdem verbreite ich gerne die Idee der <strong><a href=\"https://de.wikipedia.org/wiki/Kalaschnikow\">Kalashnikov</a>-Programmierung</strong>: Die Programmierung muss nicht technisch herausragend sein sie muss robust, unter jeder Umgebung einsatzbereit und einfach zu reparieren sein.</p><img src=\"https://stats.3960.org/p.php?idsite=8amp;action_name=Einfachheit%20in%20Programmierung&amp;url=https%3A%2F%2Fjournal.3960.org%2Fposts%2F2019-04-23-einfachheit-programmierung%2F%3Futm_source%3Dnewsfeed_view\" style=\"border:0;\" alt=\"\" />",
"summary": "Meine persönlichen Grundsätze für Programmierung finden sich bestens in dem Artikel Simple & Boring zusammengefasst. Meine eigenen Ideen dazu:\nWenn ich ein…",
"date_published": "2019-04-23T19:16:18+02:00",
"date_modified": "2019-04-23T19:16:18+02:00",
"author": {
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
},
"authors": [
{
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
}
],
"banner_image": "https://cdn.3960.org/favicon-192x192.png",
"language": "de-DE",
"image": "https://cdn.3960.org/favicon-192x192.png",
"external_url": "https://css-tricks.com/simple-boring/",
"tags": [
"Geckobar",
"Meinung",
"Philosophie",
"Programmierung",
"Webdevelop"
]
},
{
"id": "user/posts/2019-04-10-bilder-iframes-einfach-mit-lazy-loading-ausstatten/index.md",
"url": "https://journal.3960.org/posts/2019-04-10-bilder-iframes-einfach-mit-lazy-loading-ausstatten/",
"title": "Bilder und iFrames einfach mit Lazy-Loading ausstatten",
"content_html": "<p>Lazy-loading ist eine beliebte Technik, um die gefühlte Geschwindigkeit einer Internetseite zu erhöhen. Statt alle Bilder einer Webseite schon beim Laden der Seite mitzuladen, werden nur die Bilder geladen, die auch <em>tatsächlich</em> sichtbar sind. Damit verringert man gerade auf langen Seiten die initial geladene Menge an Bildern.</p>\n<p>Bisher hatte das mit etwas Aufwand zu tun, und auf jeden Fall mit JavaScript. Netterweise gibt es da jetzt auch eine deutlich einfachere Lösung.</p>\n<!-- more -->\n<p id=\"more\">Die bisherigen Lösungen gingen davon aus, dass irgendeine Form von <a href=\"https://appelsiini.net/projects/lazyload/\">LazyLoad-JavaScript</a> auf der Seite montiert wurde, und das HTML eines jeden Bildes abgeändert werden musste:</p>\n<pre><code class=\"language-html\"><u>&lt;!-- Load when visible --&gt;</u>\n&lt;<i>img</i> <var>src</var>=&quot;<kbd>example-lowres.jpg</kbd>&quot;\n <var>data-src</var>=&quot;<kbd>example-highres.jpg</kbd>&quot; <var>class</var>=&quot;<kbd>lazyload</kbd>&quot;\n <var>alt</var>=&quot;<kbd></kbd>&quot; <var>width</var>=&quot;<kbd>240</kbd>&quot; <var>height</var>=&quot;<kbd>240</kbd>&quot; /&gt;</code></pre>\n<p>Google Chrome unterstützt in absehbarer Zukunft ein Attribut namens <code>loading</code>, dass das Ladeverhalten von <code>&lt;img&gt;</code> und <code>&lt;iframe&gt;</code> steuert, <em>ohne</em> zusätzliches Javascript. Genaue Details kann man einem <a href=\"https://addyosmani.com/blog/lazy-loading/\">Blog-Post eines Chrome-Entwicklers über Lazy-Loading</a> entnehmen, im HTML sieht das aber schlicht und ergreifend wie folgt aus:</p>\n<pre><code class=\"language-html\"><u>&lt;!-- Load when visible --&gt;</u>\n&lt;<i>img</i> <var>src</var>=&quot;<kbd>example.jpg</kbd>&quot; <var>loading</var>=&quot;<kbd>lazy</kbd>&quot; <var>alt</var>=&quot;<kbd></kbd>&quot; <var>width</var>=&quot;<kbd>240</kbd>&quot; <var>height</var>=&quot;<kbd>240</kbd>&quot; /&gt;\n&lt;<i>iframe</i> <var>src</var>=&quot;<kbd>example.html</kbd>&quot; <var>loading</var>=&quot;<kbd>lazy</kbd>&quot;&gt;&lt;/<i>iframe</i>&gt;\n\n<u>&lt;!-- Load as soon as possible --&gt;</u>\n&lt;<i>img</i> <var>src</var>=&quot;<kbd>example.jpg</kbd>&quot; <var>loading</var>=&quot;<kbd>eager</kbd>&quot; <var>alt</var>=&quot;<kbd></kbd>&quot; <var>width</var>=&quot;<kbd>240</kbd>&quot; <var>height</var>=&quot;<kbd>240</kbd>&quot; /&gt;\n&lt;<i>iframe</i> <var>src</var>=&quot;<kbd>example.html</kbd>&quot; <var>loading</var>=&quot;<kbd>eager</kbd>&quot;&gt;&lt;/<i>iframe</i>&gt;</code></pre>\n<p>Damit entfällt in Zukunft in Google Chrome (und allen anderen Browsern, die da nachziehen werden) die Notwendigkeit, JavaScript für Lazy-Loading auf der eigenen Seite zu montieren. Zudem können browser ohne diese Möglichkeit bzw. ohne JavaScript immer noch die selben Inhalte sehen.</p>\n<h2 id=\"tests-mit-chrome\">Tests mit Chrome</h2>\n<p>Solange Google Chrome das Feature noch nicht direkt unterstützt, muss man im aktuellen Google Chrome Lazy-Loading noch einmalig einschalten:</p>\n<ol>\n<li>In Chrome <code>chrome://flags</code> in die URL-Zeile eingeben</li>\n<li>Nach „Lazy“ suchen.</li>\n<li>Die beiden nun angezeigten Optionen aktivieren.</li>\n<li>Chrome neu starten.</li>\n</ol>\n<p>Danach sollte man beim Besuch einer Seite, die mit <code>loading</code>-Attributen versehen ist, beim Öffnen des Inspektors bemerken, dass erst beim Scrollen auf der Seite weiter unten befindliche Bilder nachgeladen werden.</p>\n<h2 id=\"mit-der-gießkanne-umsetzung-in-nodejs\">Mit der Gießkanne: Umsetzung in NodeJs</h2>\n<p>Um in einem gesamten Content-Block jedes <code>&lt;img&gt;</code> und <code>&lt;iframe&gt;</code> mit dem passenden <code>loading</code>-Attribut zu versehen, reicht folgende kleine Funktion:</p>\n<pre><code class=\"language-javascript\"><b>const</b> lazyloadAttributes = <b>function</b>(html, loading = <kbd>'lazy'</kbd>) {\n <i>return</i> html.replace(/(&lt;(?:img|iframe) )/g, <kbd>'$1loading=&quot;'</kbd> + loading + <kbd>'&quot; '</kbd>);\n};</code></pre>\n<h2 id=\"und-in-php\">…und in PHP</h2>\n<p>Gleichsam können in PHP z.B. redaktionelle Texte durch diese Funktion durchgeleitet werden, um überall Lazy-Loading hinzuzufügen:</p>\n<pre><code class=\"language-php\"><b>function</b> lazyloadAttributes(<var>$html</var>, <var>$loading</var> = <kbd>'lazy'</kbd>) {\n <i>return</i> preg_replace(<kbd>'/(&lt;(?:img|iframe) )/is'</kbd>, <kbd>'$1loading=&quot;'</kbd> . <var>$loading</var> . <kbd>'&quot; '</kbd>, <var>$html</var>);\n}</code></pre>\n<h2 id=\"fazit\">Fazit</h2>\n<p>Eigentlich gibt es wenig Gründe, dass Attribut nicht einzusetzen. Gerade auf länglichen Übersichtsseiten kann das Erlebnis für den Besucher deutlich verbessert werden. Und für Mobilgeräten mit geringer Bandbreite kann der Geschwindigkeitszuwachs immens sein.</p>\n<p>Außerdem steht zu erwarten, dass in Zukunft auch Safari und vielleicht sogar Firefox dieses Feature unterstützen werden während Microsofts Edge ja gerade auf die Browser-Engine von Chrome wechselt, und damit dieses Feature implizit unterstützt.</p><img src=\"https://stats.3960.org/p.php?idsite=8amp;action_name=Bilder%20und%20iFrames%20einfach%20mit%20Lazy-Loading%20ausstatten&amp;url=https%3A%2F%2Fjournal.3960.org%2Fposts%2F2019-04-10-bilder-iframes-einfach-mit-lazy-loading-ausstatten%2F%3Futm_source%3Dnewsfeed_view\" style=\"border:0;\" alt=\"\" />",
"summary": "Lazy-loading ist eine beliebte Technik, um die gefühlte Geschwindigkeit einer Internetseite zu erhöhen. Statt alle Bilder einer Webseite schon beim Laden der…",
"date_published": "2019-04-10T19:02:20+02:00",
"date_modified": "2019-04-20T09:57:01+02:00",
"author": {
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
},
"authors": [
{
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
}
],
"banner_image": "https://cdn.3960.org/favicon-192x192.png",
"language": "de-DE",
"image": "https://cdn.3960.org/favicon-192x192.png",
"tags": [
"Für Facebook",
"Javascript",
"Programmierung",
"Webdevelop"
]
},
{
"id": "user/posts/2019-03-27-wettergeraet-fuer-aerofly-fs2/index.md",
"url": "https://journal.3960.org/posts/2019-03-27-wettergeraet-fuer-aerofly-fs2/",
"title": "Das Wettergerät für Aerofly FS2",
"content_html": "<p><img src=\"https://journal.3960.org/posts/2019-03-27-wettergeraet-fuer-aerofly-fs2/favicon-512x512-240x240.png\" class=\"quad\" width=\"240\" height=\"240\" style=\"--aspect-ratio: 240/240;\" alt=\"\" /> Was Anfang des Jahres als kleine Idee begonnen hatte, ist inzwischen in einem einigermaßen komplexen Projekt gemündet: Ich wollte das Wetter in meinem Lieblings-Flugsimulator <a href=\"https://www.aerofly.com/\">Aerofly FS2</a> verbessern.</p>\n<!-- more -->\n<p id=\"more\">Aerofly FS2 ist noch weit entfernt von der Tiefe und Komplexität von X-Plane oder auch Prepar3D. Darum hatte ich mir zwischenzeitlich <a href=\"https://www.x-plane.com/\">X-Plane</a> angeschaut, war aber inzwischen bereits sehr verwöhnt von der Performance und Unkompliziertheit von Aerofly FS2. Gerade die Unterstützung für Virtual Reality gefiel mir in AFS2 einfach besser, so dass ich X-Plane inzwischen wieder in den Hangar gerollt hatte.</p>\n<p>Nach meiner Rückkehr zu AFS2 vermisste ich nun aber doch ein paar Features:</p>\n<ol>\n<li><a href=\"https://en.wikipedia.org/wiki/Air_traffic_control\">Air Traffic Control</a>, d.h. die korrekte Verwendung des Funkgerätes,</li>\n<li>eine lebendig wirkende Umwelt,</li>\n<li>und den realen Bedingungen entsprechendes Wetter.</li>\n</ol>\n<p>Während die lebendig wirkende Umwelt (in Form von Autos und Schiffen) gerade durch das <a href=\"https://steamcommunity.com/games/434030/announcements/detail/1804161464656648118\">Aerofly Life Project</a> angegangen wird, habe ich mir also das Wetter vorgenommen.</p>\n<p>Tatsächlich existiert in X-Plane eine Idee, die in <a href=\"https://journal.3960.org/tagged/aerofly-fs2/\">Aerofly FS2</a> ebenfalls funktioniert: Jeder größere Flughafen auf diesem Planeten veröffentlicht in relativ kurzen Abständen seinen aktuellen Wetterbericht in Form eines <a href=\"https://de.wikipedia.org/wiki/METAR\">METAR</a>. Dieser Wetterbericht ist nicht nur sehr verdichtet, sondern auch mit etwas Geschick maschinenlesbar.</p>\n<pre><code class=\"language-metar\"><i title=\"Location\">KEYW</i> <span title=\"Day of month\">26</span><b title=\"Time\">1153Z</b> <span title=\"Wind direction\">360</span><b title=\"Wind speed\">05KT</b> 10SM <var title=\"Cloud\">FEW012</var> <b title=\"Temperature\">23</b>/<span title=\"Dewpoint\">23</span> <span title=\"Pressure\">A3004</span> RMK AO2 SLP172 T02330217 10233 20222 53012</code></pre>\n<p>Darüber hinaus gibt es viele Anlaufstellen, die METARs über eine HTTP-Schnittstelle zur Verfügung stellen. Die <strong>Quelle</strong> war also gefunden.</p>\n<p>Gleichzeitig hatte ich in der Hauptkonfigurationsdatei <code>main.mcf</code> von AFS2 entdeckt, dass die Wetterdaten darin gespeichert wurden. Zu meiner Überraschung fanden sich dort sogar Schalter, die in der Simulation selber gar nicht konfigurierbar waren. Mit ein paar wenigen Experimenten konnte ich nachweisen, dass Veränderungen in der <code>main.mcf</code> tatsächlich in AFS2 übernommen wurden hier war also mein <strong>Ziel</strong>.</p>\n<h2 id=\"die-aufgabe\">Die Aufgabe</h2>\n<p>Die Aufgabe war jetzt also klar erkennbar:</p>\n<ol>\n<li>Einen METAR für einen definierbaren Flughafen per HTTP-API abholen,</li>\n<li>den METAR-Bericht in ein strukturiertes METAR-Objekt umwandeln,</li>\n<li>das METAR-Objekt wiederum in ein Aerofly-kompatibles Objekt umwandeln,</li>\n<li>und diese Daten dann in die Simulation schreiben hier also in die <code>main.mcf</code>.</li>\n</ol>\n<h2 id=\"phase-1-kommandozeile\">Phase 1: Kommandozeile</h2>\n<p><img src=\"https://journal.3960.org/posts/2019-03-27-wettergeraet-fuer-aerofly-fs2/aerofly-weather-desktop.png\" width=\"931\" height=\"570\" style=\"--aspect-ratio: 931/570;\" alt=\"\" /></p>\n<p>Als Webprogrammierer habe ich mich für das Projekt an eine Sprache gehalten, die ich gut kannte: JavaScript, bzw. <a href=\"https://nodejs.org/\">NodeJS</a>.</p>\n<p>Hier zahlte sich vor allen Dingen aus, dass ich privat sehr gerne test-getrieben entwickele, da das Format von METARs doch einige Überraschungen parat hatte. Unzählige Tests später hatte ich dann aber einen METAR-Parser, der mit vielen Fallstricken der METAR-Angaben umgehen konnte.</p>\n<p>Schon nach einem Monat kopierte das Kommandozeilen-Tool fröhlich METAR-Daten in Aerofly FS2. Das ganze Projekt veröffentliche ich als <a href=\"https://www.npmjs.com/package/aerofly-weather\">„Aerofly-Weather“ bzw. „AeroWX“ bei NPM</a>.</p>\n<p>Schon bald fiel mir aber auf, dass ich zu kurz gesprungen war: Einerseits erforderte mein Programm die Installation von NodeJS andererseits war es ein Kommandozeilenprogramm, mit entsprechend wenig ansprechender Präsentation.</p>\n<h2 id=\"phase-2-electron\">Phase 2: Electron</h2>\n<p><img src=\"https://journal.3960.org/posts/2019-03-27-wettergeraet-fuer-aerofly-fs2/aerofly-weather-app.png\" width=\"984\" height=\"742\" style=\"--aspect-ratio: 984/742;\" alt=\"\" /></p>\n<p>Es musste also eine bedienbare Desktop-Applikation her. Da ich als Webprogrammierer mit dieser Welt bisher nur sehr wenig Erfahrung hatte, fand ich zum Glück eine Lösung genau nach meinem Geschmack: <a href=\"https://electronjs.org/\">Electron</a>.</p>\n<p>Mit Electron konnte ich nicht nur meine NodeJS-Programmierung direkt weiterverwenden, das GUI meiner Applikation konnte mit HTML, CSS und JavaScript gebaut werden Sprachen, mit denen ich jeden Tag arbeite. So konnte mit relativ moderatem Aufwand nach einem Monat eine Desktop-Applikation gebaut werden. Diese wurden mit dem <a href=\"https://www.electron.build/\">Electron-Builder</a> zu einer eigenständigen EXE-Datei kompiliert und ließ sich dann als <a href=\"https://github.com/fboes/aerofly-weather\">„Aerofly-Weather“ bzw. „AeroWX“ bei Github herunterladen</a>.</p>\n<p>Aber auch hier nagte die Unzufriedenheit an mir: Diese Applikation hatte als ZIP gepackt eine Größe von über 60MB, und auch die Ausführung dieses Programms verschlang Unmengen an RAM. Für eine so kleine Applikation war dies kaum zu rechtfertigen.</p>\n<h2 id=\"phase-3-kommandozeile-aber-in-c\">Phase 3: Kommandozeile, aber in C++</h2>\n<p><img src=\"https://journal.3960.org/posts/2019-03-27-wettergeraet-fuer-aerofly-fs2/aerofly-wx-cli.png\" width=\"711\" height=\"400\" style=\"--aspect-ratio: 711/400;\" alt=\"\" /></p>\n<p>Durch einen Tipp aus der Aerofly-Community hatte man mir einen neuen Floh ins Ohr gesetzt: Eine Umsetzung in C++. Damit könnte ich den Nutzer von der Last befreien, entweder NodeJS zu installieren oder sich eine immens große Electron-App herunterzuladen. Nach ein bisschen Recherche und Interviews mit befreundeten Programmierern stürzte ich mich erneut ins Unterholz, um das Projekt nochmals zu bauen nur diesmal in C++.</p>\n<p>Praktischer Nebeneffekt war, dass ich alle funktionalen Überlegungen bereits in NodeJS gelöst hatte. In meiner Vorstellung konnte ich mich also ganz auf das Umschreiben meines Projekts von JavaScript auf C++ konzentrieren. Tatsächlich waren ein Großteil der Ideen in C++ reproduzierbar, wenn auch die strenge Typisierung (als PHP- und JavaScript-Programmierer eine ganz neue Erfahrung) und die nun notwendige IDE (Microsoft Visual Studio) doch zuerst eine erhebliche Hürde darstellte.</p>\n<p>Nichtsdestotrotz konnte nach knapp zwei Wochen das ursprüngliche Projekt als eigenständig ausführbare Applikation umgesetzt werden. Die Ausgabe auf der Kommandozeile war beinahe identisch die Größe der eigentlichen Applikation aber deutlich kompakter, und vor allen Dingen die Installation von NodeJS nicht mehr erforderlich. Mit einem einfachen Deployment-Workflow konnte die Applikation als <a href=\"https://github.com/fboes/aerofly-wettergeraet\">„Aerofly Wettergerät“ bei Github bereitgestellt werden</a>.</p>\n<h2 id=\"phase-4-eine-echte-desktop-applikation\">Phase 4: Eine echte Desktop-Applikation</h2>\n<p><img src=\"https://journal.3960.org/posts/2019-03-27-wettergeraet-fuer-aerofly-fs2/aerofly-wx-desktop.png\" width=\"625\" height=\"473\" style=\"--aspect-ratio: 625/473;\" alt=\"\" /></p>\n<p>Das <i>Aerofly Wettergerät</i> brauchte nun ebenfalls einen feschen Desktop-Aufsatz. Hier hatte ich zuerst Sciter ausprobiert ähnlich wie Electron hätte man HTML und CSS für die Gestaltung des Frontends verwenden können. Nach einigen Tests erwies sich aber Sciter für meine Belange als wenig geeignet. Stattdessen war der Tipp eines Kollegen goldrichtig: <a href=\"https://www.wxwidgets.org/\">WxWidgets</a> erlaubte mit überschaubarem Aufwand von zwei weiteren Wochen, eine native Applikation im Look &amp; Feel des Betriebssystems zu erstellen.</p>\n<p>Die so entstandene Desktop-Applikation wurde ebenfalls im Paket vom <a href=\"https://github.com/fboes/aerofly-wettergeraet\">„Aerofly Wettergerät“ bei Github bereitgestellt</a>, so dass sowohl die Kommandozeilen- als auch die Desktop-Version nicht nur die selben Sourcen haben, sondern auch im selben Installationspaket geliefert werden. Die Download-Größe liegt unter einem Zehntel des ursprünglichen NodeJS-Paketes, und auch der Fußabdruck im RAM ist um Größenordnungen kleiner wenn auch die Ausgabe nun etwas schlichter wirkt.</p>\n<h2 id=\"die-nächste-phase\">Die nächste Phase?</h2>\n<p>Bis jetzt verbleibt ein Wehrmutstropfen bei dem Projekt: Das Wetter kann nur <em>außerhalb</em> der Simulation heruntergeladen und eingestellt werden. Damit bleiben folgende Fälle außen vor:</p>\n<ul>\n<li>Nach dem Starten der Simulation unternimmt man einen längeren Flug, bei dem sich sowohl aufgrund der geografischen Position als auch der voranschreitenden Zeit das Wetter verändert hätte.</li>\n<li>Nach dem Starten des Simulators entscheidet man sich spontan für einen ganz anderen Start- bzw. Zielflughafen.</li>\n</ul>\n<p>Meine Überlegungen dazu waren, mit dem von IPACS angebotenen SDK eine eigene DLL zu bauen, die alle zehn Minuten den nächstgelegenen Flughafen sucht, das Wetter herunterlädt und dann in die laufende Simulation importiert. Da für diese Idee die Schnittstellen in die Simulation aber aktuell nicht ausreichend dokumentiert sind bzw. auch nicht existieren, liegt das Projekt erstmal auf unbestimmte Zeit auf Eis.</p><img src=\"https://stats.3960.org/p.php?idsite=8amp;action_name=Das%20Wetterger%C3%A4t%20f%C3%BCr%20Aerofly%20FS2&amp;url=https%3A%2F%2Fjournal.3960.org%2Fposts%2F2019-03-27-wettergeraet-fuer-aerofly-fs2%2F%3Futm_source%3Dnewsfeed_view\" style=\"border:0;\" alt=\"\" />",
"summary": "Was Anfang des Jahres als kleine Idee begonnen hatte, ist inzwischen in einem einigermaßen komplexen Projekt gemündet: Ich wollte das Wetter in meinem…",
"date_published": "2019-03-27T19:32:27+01:00",
"date_modified": "2020-02-11T08:52:46+01:00",
"author": {
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
},
"authors": [
{
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
}
],
"banner_image": "https://journal.3960.org/posts/2019-03-27-wettergeraet-fuer-aerofly-fs2/favicon-512x512.png",
"language": "de-DE",
"image": "https://journal.3960.org/posts/2019-03-27-wettergeraet-fuer-aerofly-fs2/favicon-512x512.png",
"tags": [
"Aerofly FS2",
"Fliegerei",
"API",
"Für Tumblr",
"Programmierung",
"Simulation",
"Spiel"
]
},
{
"id": "user/posts/2019-02-28-ueber-impertinenz/index.md",
"url": "https://journal.3960.org/posts/2019-02-28-ueber-impertinenz/",
"title": "Über Impertinenz",
"content_html": "<blockquote><p>Wer sich einen impertinenten Tonfall leistet, sollte sich seiner Sache besser sicher sein.</p></blockquote>\n<p>Besser ist es natürlich, Recht zu haben <em>und</em> ein angenehmer Gesprächspartner zu bleiben.</p><img src=\"https://stats.3960.org/p.php?idsite=8amp;action_name=%C3%9Cber%20Impertinenz&amp;url=https%3A%2F%2Fjournal.3960.org%2Fposts%2F2019-02-28-ueber-impertinenz%2F%3Futm_source%3Dnewsfeed_view\" style=\"border:0;\" alt=\"\" />",
"summary": "Wer sich einen impertinenten Tonfall leistet, sollte sich seiner Sache besser sicher sein.\n\nBesser ist es natürlich, Recht zu haben und ein angenehmer Gespr…",
"date_published": "2019-02-28T18:46:14+01:00",
"date_modified": "2019-02-28T18:46:14+01:00",
"author": {
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
},
"authors": [
{
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
}
],
"banner_image": "https://cdn.3960.org/favicon-192x192.png",
"language": "de-DE",
"image": "https://cdn.3960.org/favicon-192x192.png",
"tags": [
"Idee",
"Meinung",
"Philosophie"
]
},
{
"id": "user/posts/2019-02-14-simplex-duplex/index.md",
"url": "https://journal.3960.org/posts/2019-02-14-simplex-duplex/",
"title": "Simplex, Duplex",
"content_html": "<ul>\n<li>Simplex: Es funktioniert nur eine Richtung gleichzeitig.</li>\n<li>Duplex: Es funktionieren beide Richtungen gleichzeitig.</li>\n<li>Durex: Es funktioniert keine Richtung… in 99% der Fälle jedenfalls.</li>\n</ul><img src=\"https://stats.3960.org/p.php?idsite=8amp;action_name=Simplex%2C%20Duplex&amp;url=https%3A%2F%2Fjournal.3960.org%2Fposts%2F2019-02-14-simplex-duplex%2F%3Futm_source%3Dnewsfeed_view\" style=\"border:0;\" alt=\"\" />",
"summary": "Simplex: Es funktioniert nur eine Richtung gleichzeitig.\nDuplex: Es funktionieren beide Richtungen gleichzeitig.\nDurex: Es funktioniert keine Richtung… in 99%…",
"date_published": "2019-02-14T19:11:34+01:00",
"date_modified": "2019-02-14T19:11:34+01:00",
"author": {
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
},
"authors": [
{
"name": "Frank Boës",
"url": "mailto:info@3960.org",
"avatar": "https://www.gravatar.com/avatar/71fcf51cf2ae9acdd54182d3e367ceca"
}
],
"banner_image": "https://cdn.3960.org/favicon-192x192.png",
"language": "de-DE",
"image": "https://cdn.3960.org/favicon-192x192.png",
"tags": [
"Lustiges",
"Programmierung",
"Webdevelop"
]
}
]
}