{ "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": "
", "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": "Da ist es zwar nicht ganz billig,
dafür schmeckt's aber auch nicht.
METAR-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:
\nEHAM 091725Z 20037G51KT 170V230 9999 FEW011 BKN014 BKN025 11/11 Q0986 RE/RA TEMPO 7000
\nSolch einen METAR-Code kann z.B. mit dem Aerofly FS2 Wettergerät verwendet werden.
", "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": "", "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": "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 alle 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.
\n\nGenerell gibt es zwei Arten, unter Windows einen SSH-Schlüssel zu speichern:
\nppk
)Viele Anleitungen beschränken sich auf die eine oder andere Methode zum Anlegen von SSH-Schlüsseln. Tatsächlich macht es aber unter Windows sehr viel Sinn, den eigenen Schlüssel in beiden Formate verfügbar zu haben. Das geht deutlich schmerzloser, wenn beide Schlüsselformate in einem Aufwasch angelegt werden.
\nputtygen
Schlüsselgenerator, pageant
Schlüsselagenten und das plink
SSH-Verbindungstool.mkdir -p ~/.ssh
angelegt werden.C:\\Users\\USERNAME\\.ssh
) die insgesamt drei Dateien anzulegen, die zusammen alle Schlüssel-Komponenten darstellen.In PuttyGen selber wird es nun etwas trickreich:
\nC:\\Users\\USERNAME\\.ssh\\id_rsa.ppk
speichern.C:\\Users\\USERNAME\\.ssh\\id_rsa.pub
einfügen (mit der Funktion „Save public key“ wird der Public Key nicht im korrekten Format exportiert).C:\\Users\\USERNAME\\.ssh\\id_rsa
speichern. Wichtig ist hierbei, dass keine Dateiendung verwendet wird.In eurem SSH-Verzeichnis C:\\Users\\USERNAME\\.ssh
sollten nun mindestens drei Dateien liegen:
id_rsa.ppk # Privater / öffentlicher Schlüssel für PuTTY\nid_rsa.pub # Öffentlicher Schlüssel für OpenSSH\nid_rsa # Privater Schlüssel für OpenSSH
\nSpäter werden in diesem Verzeichnis ggf. noch mehr Dateien auftauchen, wie z.B. known_hosts
, authorized_keys
und config
.
Übrigens solltet ihr mit der Git Bash mittels chmod 644 ~/.ssh/* && chmod 600 ~/.ssh/id_rsa
allen Dateien die korrekten Zugriffsrechte (-rw-r--r--
bzw. -rw-------
) geben, falls dies nicht schon geschehen ist.
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 id_rsa.ppk
entweder in den Einstellungen übergeben bekommen müssen, oder aber aus einem vorher zu startenden pageant
Schlüsselagenten übernehmen können. Falls ihr SSH-Schlüssel für eure tägliche Arbeit benutzt, könnt ihr den Pageant auch automatisch starten und den Schlüssel laden lassen.
Viele Windows-Programme können so euren SSH-Schlüssel nutzen, u.a.:
\nSo 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.
\nUnter Linux und Mac OSX ist der Vorgang übrigens etwas kürzer:
\nssh-keygen -t rsa -b 4096 -C "YOUR@EMAIL"
",
"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": "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?
\n\nSchon vor einiger Zeit war ich auf Firefox für Android 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.
\n\nOh, ein Nerd-Telefon! Android, Firefox und DuckDuckGo.
Ein Wermutstropfen 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 Mozillas Android-Apps eine neue Version von Firefox für Android findet: Mozilla Firefox Preview.
\nVon seinem Vorgänger unterscheidet Firefox Preview 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. ETP genannt) funktioniert einfach fantastisch (so das meine Bastelei für den FritzBox-AdBlocker für diesen Browser überflüssig wird).
\nNebenbei kann der Firefox Preview auch den Webview auf Android ersetzen. Damit sind alle Apps auf dem Telefon, die Webview verwenden, nicht nur mit der Rendering-Engine sondern auch mit dem AdBlocker von Firefox Preview ausgestattet.
\nNicht zuletzt ist in Firefox Preview der Dienst „Firefox Sync“ eingebaut. Sobald man sich einen kostenlosen Firefox Account 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.
\nÜbrigens: Mozillas Bemühen um neue Privatsphären-Services hat Firefox Monitor 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 nicht von mir benutzter Dienst, womit sich hier möglicherweise der Kreis zum Trackingschutz von Mozilla Firefox schließt. 😉
", "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": "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 (You Might Not Need jQuery). Abhängig von der gewählten Methode lässt sich damit… die Performance einer Website gründlich ruinieren.
\nAber das muss nicht sein – wie dieser Überblick über die Montage von Event-Handlern in JavaScript / jQuery zeigt.
\n\nGanz grundsätzlich muss jeder Prozessschritt beim Hinzufügen eines Event-Handlers richtig angewendet werden. Der ganze Vorgang besteht aus drei Schritten:
\nIn jedem dieser Schritte lässt sich zum Teil massiv optimieren.
\nUm 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.
\n\nFaustformel: Je eindeutiger das Suchmerkmal und je kleiner die Menge der zu durchsuchenden Elemente, desto schneller ist die Suche.
Die schnellste Methode ist dabei die Selektion über ein id
-Attribut – die langsamste dagegen die Suche nach einem beliebigen Attribut, im schlimmsten Fall mit der Prüfung, ob dieses Attribut einen bestimmten Wert beinhaltet.
Methode | \njQuery | \nJavaScript | \nNeues JavaScript | \n
---|---|---|---|
ID | \n$('#x') | \ndocument.getElementById('x') | \ndocument.querySelector('#x') | \n
Klasse | \n$('.x') | \ndocument.getElementsByClassName('x') | \ndocument.querySelectorAll('.x') | \n
Tag | \n$('x') | \ndocument.getElementsByTagName('x') | \ndocument.querySelectorAll('x') | \n
Attribut | \n$('[x]') | \nn/a | \ndocument.querySelectorAll('[x]') | \n
CSS (s.u.) | \n$('x y') | \nn/a | \ndocument.querySelectorAll('x y') | \n
Sowohl die jQuery-Methode $(…)
als auch die JavaScript-Methoden .querySelector()
/ .querySelectorAll()
unterstützen die Auswahl per CSS-Selektor. Damit können auch kompliziertere Suchen im DOM durchgeführt werden, wie z.B. mit nav a
das Auffinden aller <a>
in einem <nav>
. Zum Glück ist die Browser-Unterstützung für .querySelector()
/ .querySelectorAll()
inzwischen sehr gut.
Zu beachten ist, dass die JavaScript-Methoden .querySelector()
/ .querySelectorAll()
je nach Browser um ein Mehrfaches langsamer sind als ihre „einfachen“ Geschwister .getElementById
, .getElementsByClassName
und .getElementsByTagName
.
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.
\nIn jQuery existiert dafür die .find()
-Methode, die analog zu .on()
funktioniert…
var navigation = $('nav');\nvar navLinks = navigation.find('a');\nvar navBolds = navigation.find('b');
\n…in regulärem JavaScript bleiben die Methoden identisch zu den für die Suche im Dokument verfügbaren Methoden:
\nvar navigation = document.querySelector('nav');\nvar navLinks = navigation.querySelectorAll('a');\nvar navBolds = navigation.querySelectorAll('b');
\nDiese Methode kann sehr hilfreich sein, wenn später sowieso DOM-Manipulation an übergeordneten DOM-Elementen notwendig werden.
\nZu beachten ist bei regulärem JavaScript, dass die Methoden .getElementById()
und .querySelector()
ein einzelnes Element
bzw. einen einzelnen Node
(d.h. ein DOM-Element) zurückgeben, während alle anderen Selektions-Methoden eine HTMLCollection
bzw. NodeList
zurückgeben, die vereinfacht gesagt Arrays von Node
s sind.
Für das Hinzufügen von Event-Listenern bietet jQuery die Methode .on()
, und JavaScript die Methode .addEventListener()
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.)
In beiden Fällen verfügt die Selektion über eine Methode, der man nur den Event-Typ und den eigentlichen Event-Listener übergeben muss.
\n$('nav').on('click', function() {\n $(this).addClass('active');\n})
\nDer selbe Aufruf ist in Vanilla-JavaScript etwas mehr Schreibarbeit, aber ansonsten identisch:
\ndocument.querySelector('nav').addEventListener('click', function(event) {\n event.target.classList.add('active');\n});
\nZu beachten in JavaScript: Event-Listener können nur einem einzelnen DOM-Element hinzugefügt werden – jQuery erlaubt es, am Stück mehreren DOM-Elementen ein und denselben Event-Listener hinzuzufügen.
\nIn beiden Fällen steht im Event-Listener mit $(this)
bzw. event.target
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 event
gesetzt bekommen hat.
Ein nicht unwahrscheinlicher Anwendungsfall ist, verschiedene Event-Typen mit dem selben Event-Handler bedienen zu wollen. In jQuery kann man an die .on()
-Methode eine Liste an verschiedenen Event-Typen übergeben:
// Fires on `click` `keyup` `blur`\n$('nav').on('click keyup blur', function() {\n $(this).addClass('active');\n})
\nIn 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…
\n// Bad example: Fires on `click` `keyup` `blur`\n['click', 'keyup', 'blur'].forEach(function(eventType) {\n document.querySelector('nav').addEventListener(eventType, function(event) {\n event.target.classList.add('active');\n });\n});
\n…und handelt sich auf diese Weise zwei Performance-Killer ein: Einerseits wird in jedem Schleifendurchlauf document.querySelector
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:
// Better example: Fires on `click` `keyup` `blur`\nvar eventTarget = document.querySelector('nav');\nvar eventListener = function(event) {\n event.target.classList.add('active');\n};\n\n['click', 'keyup', 'blur'].forEach(function(eventType) {\n eventTarget.addEventListener(eventType, eventListener);\n});
\nDas Array abgerollt sieht dann sogar noch übersichtlicher aus, und zeigt plastisch den Vorteil der vorherigen Deklaration von Event-Ziel und -Listener:
\n// Best example for readability: Fires on `click` `keyup` `blur`\nvar eventTarget = document.querySelector('nav');\nvar eventListener = function(event) {\n event.target.classList.add('active');\n};\n\neventTarget.addEventListener('click', eventListener);\neventTarget.addEventListener('keyup', eventListener);\neventTarget.addEventListener('blur', eventListener);
\nWenn sich auf einer Seite mehrere DOM-Objekte befinden, die wir mit einem identischen Event-Handler ausstatten wollen, so gibt es in jQuery die folgende Methode.
\n// Add Event Handler to all `.btn`\n$('.btn').on('click', function() {\n $(this).addClass('active');\n})
\nBesonders spannend: Bei .on()
und .querySelectorAll()
können auch mehrere CSS-Selektoren, durch Kommata getrennt, gleichzeitig abgefragt werden. Mit header a, footer a
kriegt man eine Liste aller <a>
in <header>
und <footer>
zurück.
In Vanilla-JavaScript wird das Hinzufügen zu Event-Listenern zu mehreren DOM-Elementen etwas umständlicher, weil ein Event-Handler immer nur einem 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:
\n// Add Event Handler to all `.btn`\ndocument.querySelectorAll('.btn').forEach(function(btn) {\n btn.addEventListener('click', function(event) {\n event.target.classList.add('active');\n });\n});
\nWarum 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 ein Event-Listener für eine Tabellenzelle also auf insgesamt 100 Events verteilt werden.
\nFü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 oberhalb der zu beobachtenden DOM-Objekte liegt. Dieses übergeordnete Objekt wird über alle Events informiert, die unterhalb von ihm stattfinden – das sogenannte „Event Bubbling“.
\nIn jQuery wird der Filter für das eigentliche Event-Ziel als zusätzlicher Parameter von .on()
übergeben.
// Add Event Handler to `nav`, fire if `.btn` was clicked\n$('nav').on('click', '.btn', function() {\n $(this).addClass('active');\n})
\nIn Vanilla-JavaScript wird das Event-Ziel innerhalb des Event-Listeners gefiltert:
\n// Add Event Handler to `nav`, fire if `.btn` was clicked\ndocument.querySelector('nav').addEventListener('click', function(event) {\n if (event.target.matches('.btn')) {\n event.target.classList.add('active');\n }\n});
\nBezogen 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 <nav>
-Element erst nach dem Hinzufügen des Event-Handlers neue <… class=„btn“>
zum Beispiel via AJAX hinzugefügt werden, wird unser Event-Handler auf dem <nav>
auch diese Elemente mit verarbeiten, da er ja auf alle Elemente unterhalb von ihm reagiert.
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.
\n\nStipp(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 2–3 Personen glücklich zu machen:
\nKurz zusammengefasst besteht die Sauce also aus Speck, Zwiebeln und Sahne.
\nDie Zubereitung ist fast genau so einfach:
\nDie Sauce kann durch harte körperliche (oder seelische Arbeit) verlorene Kalorie relativ flott wiederherstellen. 😉
", "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": "\n\nDies ist meine Philosophie über Programmierung. Es gibt viele davon, aber diese hier ist meine.
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.
\nDie Sturmgewehr-Familie, die mit der Kalaschnikow AK-47 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.
\nDer 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.
\nUnabhä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.
\nFür gute Programmierung existieren Unmengen an ausformulierten best practices, 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 Kalaschnikow-Programmierung.
\nIm Detail sind diese Ideen einfach zu erklären, wenn wir uns als Programmierer folgende Dinge vor Augen führen:
\nDeshalb muss für mich persönlich Programmierung die folgende Attribute besitzen – die den Attributen der Kalaschnikow-Gewehr-Familie ähneln:
\nDiese 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 Kalaschnikow-Programmierung.
\nAls 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.
\nIn diesem Sinne sollten wir nicht nur bei der Benennung von Komponenten daran denken, dass auch andere Programmierer diese verstehen können müssen. Auch übermäßig komplexe Sprach-Konstrukte oder wenig bekannte Mechanismen bzw. Funktionen 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.
\nWenn also eine solche Lösung verwendet wird, sollte diese zumindest dokumentiert werden – besser ist es aber gegebenenfalls, diese Lösung durch ein wenig komplexes, dafür gerne auch längeres Stück Programmierung zu ersetzen.
\n\nWer keine Dokumentation für seine Programmierung hinterlässt, möchte in seinem Urlaub telefonisch Fragen dazu beantworten.
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.
\nWir 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 Pragmatismus und Augenmaß unser Leitbild sein.
\nNicht zuletzt müssen wir uns bei überbordender Komplexität fragen, warum wir diesen Aufwand betreiben. Gemäß dem Pareto-Prinzip 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.
\nVor 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.
\nWir, 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 Einstiegshürde geschaffen. Schlimmer noch können wir Teile in unsere Toolchain eingeführt haben, die ein Verfallsdatum haben und nach einer gewissen Zeit ein Projekt nur noch schwer wartbar machen. Und nicht zuletzt kann ein Defekt in einem 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.
\nWenn wir schon für unseren Entwicklungsprozess eine komplexe Toolchain erfordern, müssen wir (z.B. in der README.md
des Projekts) die grundsätzlichen Anforderung und die Installation dieser Tools erläutern. Im Idealfall liefern wir ein Installations-Skript 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.
\nWelches Problem löst das – und welches Problem verursacht das?
Weitere Ideen und Inspiration zu diesem Thema finden sich in dem Artikel „Zurück zur Werkbank“.
\nGerade 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 das selbe Verständnis für die Anforderung an die Umsetzung eines solchen Projektes haben.
\nAls 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, müssen wir aus Gründen der Konsistenz und Erwartbarkeit von Code 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 Clean Code ist hier eine äußerst gute Grundlage.
\nWenn uns geschlossene Beschlüsse nicht gefallen, sollten wir auf eine Änderung hinwirken. Wenn eine Änderung beschlossen wurde, müssen wir diese aber auch konsequent und ggf. rückwirkend umsetzen. 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.
\nEinsame 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.
\nWir 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.
\nDabei geht es gar nicht so sehr um korrektes Quoting – wobei inkorrektes Quoting nicht nur Fehler, sondern gegebenenfalls auch Sicherheitsprobleme auslösen kann. Viel mehr geht es darum, Fehlerbehandlung als einen Weg zu begreifen, der auch die Performance steigert. Die Prüfung auf das Vorhandensein eines Werts 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.
\nUnsere 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 trim
entfernt werden, oder ein String per Casting sicher in eine Zahl verwandelt werden kann. Die einfache Konvertierung in erwartbare Werte 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.
Nicht zuletzt können wir mittels Mustererkennung bzw. -ersetzung 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.
\nWenn wir eine Fehlermeldung oder Exception-Message schreiben, muss diese Fehlermeldung außerhalb des lokalen Kontextes Sinn ergeben. Die Fehlermeldung „Ein Fehler trat auf, wenden Sie sich bitte an Ihren Administrator“ ist besonders dann frustrierend, wenn man selber der Administrator ist. 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 https://www.example.com scheitert mit Status-Code 503.“. Niemand beschwert sich über zu aussagekräftige Fehlermeldungen.
\nWeitere Ideen und Inspiration zu diesem Thema finden sich in dem Artikel „Die Verantwortung von Software“.
\nDie Menge an praktischen Handlungsempfehlungen aus den drei Kernideen der Kalaschnikow-Programmierung 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.
\nIch 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.
", "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": "Microsoft hat vor Kurzem den neuesten Teil ihrer weltberühmten Flight Simulator-Serie angekündigt. Innerhalb kürzester Zeit war der Microsoft Flight Simulator 2020 in aller Munde – nicht zuletzt wegen seines spektakulären Trailers:
\n\nNachdem 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 MSFS2020 für das Hobby der Flug-Simulation bedeuten kann.
\n\nDer aus dem Jahre 2006 stammende letzte Simulator aus dem Hause Microsoft war der Microsoft Flight Simulator X – ein in seiner Zeit bahnbrechendes Stück Software, dass für lange Zeit den Maßstab für private Flug-Simulation gesetzt hatte.
\nDie Jahre gingen ins Land, und der FSX 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.
\n2012 erschien das Flugspiel Microsoft Flight. Die Annahme, dass es eine Fortsetzung des FSX sein würde, wurden enttäuscht. Stattdessen handelte es sich um ein vereinfachtes Spiel, dass Simulationsfreunde nicht zufrieden stellen konnte.
\nAls weitere Signale schloss Microsoft 2009 das für den FSX verantwortliche Studio, und lizensierte die Engine an andere Unternehmen, die mehr oder weniger würdige Nachfolger für den Flight Simulator produzierten. Keines dieser Produkte konnte aber bahnbrechende Erfolge feiern.
\nSimulationsfreunden wurde klar, dass von Microsoft nichts mehr zu erwarten sein würde. So zog die Herde weiter, unter anderem zu X-Plane 11, oder schwelgte mit Prepar3d in Nostalgie.
\nDas alles änderte sich schlagartig mit den ersten Trailern für den Microsoft Flight Simulator 2020, die für alle überraschend nicht nur einen bereits sehr fertig wirkenden Simulator zeigte.
\nDie Trailer zeigten ein Flugerlebnis, das vor allen Dingen außerhalb der Simulations-Gemeinde Interesse an MSFS2020 weckte. In persönlichen Gesprächen mit Gamern zeigte sich, dass Microsoft einen Nerv getroffen hatte: Auch Spieler ohne Vorerfahrung mit Flugsimulatoren interessierten sich auf einmal brennend für den MSFS2020. Die ansprechende Grafik und die einsteigerfreundliche Präsentation machten Lust auf mehr.
\nUnd 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.
\nMicrosoft 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 Austausch mit der Community 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.
\nIn 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 Microsoft Flight Simulator 2020 direkt ins Gespräch kommen konnten.
\n\nOb es in dem Youtube-Video von FlightChops, dem Youtube-Video von Frooglesim oder dem Artikel auf Helisimmer.com ist: Alle Simfluencer konnten nicht verbergen, dass Microsoft ihre Skepsis in Begeisterung und Vorfreude verwandelt hatte.
\nDa die ersten Erfahrungen mit dem MSFS2020 vorliegen, verdichtet sich ein Bild.
\nAlles in allem scheint der Microsoft Flight Simulator 2020 aller Voraussicht nach einen neuen Standard für den Bereich der Heim-Flugsimulatoren setzen zu können.
\nDer 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:
\nEine Chance haben dagegen Simulations-Projekte, die leicht außerhalb des Fokus liegen – wenn sie ihre Karten gut spielen:
\nFür alle Simulatoren kann ein Weg sein, die Power des Internets zu nutzen:
\nWie 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.
\nAlles 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.
\nAuch Simulationsfreunde, die nicht auf MSFS2020 setzen werden, werden seine Auswirkungen früher oder später auch in ihrem Lieblings-Simulator erleben.
", "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": "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.
\nFür den Apache Webserver gibt es 2½ Wege, wie man Redirects konfigurieren kann: redirect
, redirectmatch
sowie RewriteRule
. Tatsächlich ist die korrekte und fehlerfreie Konfiguration von Redirects aber eine trickreiche Sache – und ein genaues Studium der jeweiligen Anleitung notwendig, um Redirect Loops zu vermeiden.
Die 2½ verschiedenen Redirect-Direktiven funktionieren relativ ähnlich: Sie leiten eine Anfrage-URL, die einem bestimmten Muster entspricht, auf eine Ziel-URL um. Dazu können sie der Anfrage einen HTTP-Statuscode mitgeben, der den ursprünglichen Aufrufer mitteilt, aus welchem Grund und wie lange die Umleitung existiert.
\nDer Ort für die Konfiguration von Redirects ist entweder die Apache-Konfigurationsdatei, oder aber (wenn der Webserver dieses Feature eingeschaltet hat) die .htaccess
-Konfigurationsdatei direkt im Hosting-Verzeichnis bzw. der Document Root des Webauftritts.
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.
\nBei 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:
\n# Basic redirects START\nRedirect permanent "/index" "/"\n# Basic redirects END\n\n# SEO redirects DELETE AFTER 10/2020 START\nRedirect permanent "/artikel" "/articles"\nRedirect permanent "/kontakt" "/contact"\n# SEO redirects DELETE AFTER 10/2020 END
\nGerade 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.
\nEin 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:
\n<IfModule mod_alias.c>\n Redirect permanent "/index" "/"\n</IfModule>\n\n<IfModule mod_rewrite.c>\n RewriteRule "^/source$" "/target" [R=301,L]\n</IfModule>
\nDies 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. 😉
\nWenn man sich die Anleitung für mod_alias
inklusive redirect
und redirectmatch
sowie die Anleitung für mod_rewrite
inklusive RewriteRule
genau anschaut, wird man überraschenderweise darauf stoßen, dass alle Varianten bei der Anfrage-URL nicht eine fixe URL entgegen nehmen, sondern ein Muster (bzw. Pattern). Diese Muster erwischen meistens mehr Anfrage-URLs, als man auf den ersten Blick vermuten möchte.
Selbst die harmlos wirkende Redirect
-Direktive sucht nach einem Muster (und nicht nach einem festen Wert), und hängt alle überschüssigen URL-Teile inklusive GET
-Parameter an die Ziel-URL an:
Redirect permanent "/source" "/target"\n# Redirects /source to /target\n# Redirects /source123 to /target123\n# Redirects /source/12 to /target/12\n# Redirects /source/?a to /target/?a
\nDas 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:
\nRedirect permanent "/source" "/target"\nRedirect permanent "/source/12" "/target/some-special-place"\n\n# Redirects /source to /target\n# Redirects /source123 to /target123\n# Redirects /source/12 to /target/12 (!)\n# Redirects /source/?a to /target/?a
\nVerständlicher ist dort die RedirectMatch
-Direktive, die von vorne herein mitteilt, dass sie mittels eines regulären Ausdrucks die Anfrage-URL in eine Ziel-URL umformt. Bei einer Fehlbedienung sind die Konsequenzen aber noch viel weitreichender:
RedirectMatch permanent "/source" "/target"\n# Redirects /source to /target\n# Redirects /source123 to /target\n# Redirects /source/12 to /target\n# Redirects /source/?a to /target\n# Redirects /your-shiny/source/?a to /target
\nEine Entsprechung zu RedirectMatch
findet sich bei mod_rewrite
, das auch kompliziertere Umleitungen abbilden kann.
Die RewriteRule
-Direktive hat entsprechende Fallstricke im Angebot, da sie ebenfalls mit regulären Ausdrücken arbeitet und je nach Einsatzort ein anderes Matching verwendet:
Die Einschränkung für .htaccess
-Dateien kann übrigens mit einem vorangestellten RewriteCond %{REQUEST_URI}
aufgehoben werden, so dass sich die Regeln wieder analog zu ihrem Aufruf innerhalb einer <VirtualHost>
-Direktive verhalten.
Damit sehen die Matches wie folgt aus:
\nRewriteRule "/source" "/target" [R=301,L]\n# Redirects /source to /target\n# Redirects /source123 to /target\n# Redirects /source/12 to /target\n# Redirects /source/?a to /target\n# Redirects /your-shiny/source/?a to /target
\nDie Gefährlichkeit von Redirect
wird dann offenbar, wenn man seine Funktionalität mit RedirectMatch
und RewriteRule
nachbaut. Denn tatsächlich benutzt Redirect
implizit ein nicht wenig komplexes Pattern-Matching. Folgendes Beispiel zeigt, wie inhaltlich identische Regeln teilweise sehr unschuldig aussehen können:
Redirect permanent "/source" "/target"\nRedirectMatch permanent "^/source(.*)" "/target$1"\nRewriteRule "^/source(.*)" "/target$1" [R=301,L]
\nUm 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 Steuerzeichen für PCREs bzw. Perl-kompatible reguläre Ausdrücke:
\n^
: Stimmt mit dem Anfang einer Zeichenkette überein.$
: Stimmt mit dem Ende einer Zeichenkette überein.?
: Das Zeichen bzw. die Gruppe vor dem ?
ist optional.Ein super-einfacher, direkter Redirect von exakt einer Anfrage-URL auf exakt eine Ziel-URL kann mittels Umschließung mit ^…$
realisiert werden:
RewriteEngine On\nRewriteCond %{REQUEST_URI}\nRewriteRule "^/source$" "/target" [R=301,L]\n# Redirects /source to /target
\nWenn Anfrage-URLs ohne und mit abschließenden /
erlaubt sein sollen, kann dieses Muster um ein optionales /
erweitert werden:
RewriteEngine On\nRewriteCond %{REQUEST_URI}\nRewriteRule "^/source(/)?$" "/target$1" [R=301,L]\n# Redirects /source to /target\n# Redirects /source/ to /target/
\nWenn ganze URL-Bereiche auf eine Ziel-URL umgeleitet werden sollen, kann der letzte Teil der URL explizit mit einem Muster erfasst werden. .*
erfasst bei regulären Ausdrücken eine beliebige Anzahl von beliebigen Zeichen:
RewriteEngine On\nRewriteCond %{REQUEST_URI}\nRewriteRule "^/source/.*$" "/target/" [R=301,L]\n# Redirects /source/ to /target/\n# Redirects /source/example to /target/\n# Redirects /source/?abc to /target/
\nUnd 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:
\nRewriteEngine On\nRewriteCond %{REQUEST_URI}\nRewriteRule "^/source/(.*)$" "/target/$1" [R=301,L]\n# Redirects /source/ to /target/\n# Redirects /source/example to /target/example\n# Redirects /source/?abc to /target/?abc
\nDer nginx-Webserver erfreut sich stetig wachsender Beliebtheit, und verfügt über ähnliche Methoden namens rewrite
zum Erzeugen von Redirects. Entsprechend sieht das letzte Beispiel für den Apache im nginx wie folgt aus:
rewrite ^/source/(.*)$ /target/$1 permanent\n# Redirects /source/ to /target/\n# Redirects /source/example to /target/example\n# Redirects /source/?abc to /target/?abc
\nEine besonders geniale Lösung für nginx-Redirects auf Stackoverflow schmeißt aber die gesamte Denkarbeit über Bord, und erlaubt tatsächlich das Anlegen einer einfachen Tabelle von Anfrage- und Ziel-URLs.
\nDie 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.
\nFalls 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.
", "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": "\nMein aktueller Lieblings-Flugsimulator Aerofly FS2 überredet mich immer wieder zu neuen Experimenten. Nachdem ich IFR ohne GPS in Aerofly FS2 ausprobiert hatte, animierte mich die Geschichte der Leuchttürmen und großen Beton-Pfeilen für Flugzeuge aus der Gründerzeit der Fliegerei, mir eine neue Aufgabe vorzuknöpfen: Navigation ohne moderne technische Hilfsmittel an Bord!
\n\nDie 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.
\nInspiration für solche Abenteuer finden sich z.B. in diesem Youtube-Video, in dem Flugnavigation ohne technische Hilfsmittel im echten Leben zu bewundern ist.
\n\nVFR nach diesen Regeln verändert deutlich die Art und Weise, wie ein Flug in einem Simulator durchgeführt werden muss:
\nStatt 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.
\nDisclaimer: 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 Microsoft Flight Simulator oder X-Plane.
\nIn Aerofly FS2 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 Bückner Jungmeister als auch die Pitts S-2 verfügen über eine ausgezeichnete Aussicht – und keinen einzigen Funknavigations-Empfänger.
\nBei X-Plane eignet sich z.B. die mitgelieferte Aero-Works Aerolite 103 oder Stinson L-5 Sentinel für Flüge ohne Navigations-Bordinstrumente.
\n\nSchon vor Beginn der eigentlichen Flugplanung muss ein scharfer Blick in die Wetterdaten geworfen werden. Die Mindestanforderungen sind natürlich die Visual Meteorological Conditions (VMC). Für VFR (MVFR) muss die Sichtweite mindestens 5SM (3SM) und die Wolkenuntergrenze mindestens 3.000ft (1.000ft) sein. Besseres Wetter ist natürlich zu bevorzugen, da das Gelände sichtbar sein muss.
\nZu beachten ist die Korrelation zwischen Wolken und Flughöhe: Da unsere Flughöhe mindestens 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:
\nKurs 0–179° | \nKurs 180–359° | \n
---|---|
1.500ft MSL | \n2.500ft MSL | \n
3.500ft MSL | \n4.500ft MSL | \n
5.500ft MSL | \n6.500ft MSL | \n
7.500ft MSL | \n8.500ft MSL | \n
9.500ft MSL | \n10.500ft MSL | \n
11.500ft MSL | \n12.500ft MSL | \n
All diese Bedingungen zusammen machen die Flugplanung nochmals herausfordernd.
\nNicht zuletzt muss die Windrichtung und -stärke vermerkt werden. Je nach eigener Flugrichtung und -geschwindigkeit wird Wind den eigenen Kurs verfälschen und sollte von vorne herein mit einkalkuliert werden.
\nGrundlage 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.
\nFü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.
\nFlugpläne werden vom Start zum Ziel gedanklich in Streckenabschnitte zerlegt. Dabei ist es sinnvoll, Geländemerkmale zu finden, die den Verlauf und das Ende jedes einzelnen Streckenabschnitts markieren. Auch hierbei unterstützt Aerofly FS2, indem es automatisch Wegpunkte (und damit Streckenabschnitte) in den Flugplan einfügt.
\nFür einen Flugplan geeignete Geländemerkmale müssen gut aus der Luft erkennbar sein. Wichtig ist dabei, sich wirklich große Merkmale auszusuchen. Ein vom Boden aus imposanter Hügel kann aus der Luft einfach nur wie ein flacher Hügel aussehen, oder ein malerisch von Bäumen eingefasster Fluss aus der Luft fast unsichtbar sein.
\nFür den letzten Streckenabschnitt gibt es auf jeden Fall ein gut sichtbares Geländemerkmal: Den Zielflughafen.
\nFolgende Geländemerkmale eignen sich in der Regel sehr gut:
\nDabei unterscheidet man linienförmige von punktförmigen 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.
\nEin gutes Hilfsmittel zur Identifikation von Geländemerkmalen sind Luft- oder Satellitenaufnahmen.
\n\nGeländemerkmale könne auf vielfältige Weise für den Flugplan verwendet werden:
\nDie einfachste Methode ist es, einem linienförmigen Geländemerkmal als Leitlinie 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.
\nIn 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 Ende eines Streckenabschnitts zu haben, zum Beispiel ein weiteres Geländemerkmal.
\n\nEine sehr gute Methode zur Orientierung ist die Verwendung einer Auffanglinie. 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.
\nDas Prinzip der Auffanglinie ist vielseitig nutzbar. So können Streckenabschnitte ohne 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.
\nEin ausgezeichnetes Beispiel für eine gut nutzbare Auffanglinie ist z.B. die Porta Westfalica, eine von einem Fluss durchbrochene Bergkette… oder der Overseas Highway in Florida, der von Norden kommend schwer zu verfehlen ist.
\n\nAuf Streckenabschnitte können an Stelle von Auffanglinien auch Orientierungspunkte verwendet werden, um den Fortschritt entlang des Streckenabschnitts einschätzen zu können, oder um das Ende des aktuellen Streckenabschnitts zu markieren.
\nStä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.
\nIm Gegensatz zu linienartigen Geländemerkmalen besteht bei punktförmigen Geländemerkmalen aber immer die Gefahr, diese zu verfehlen oder schlicht zu übersehen.
\nDas größte Problem besteht bei Flugplänen über eintöniges Gelände ohne Leit- und Auffanglinien sowie ohne 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 Flugdauer für einen Streckenabschnitt zu berechnen. Wichtig ist dabei, die Einheiten korrekt umzurechnen:
\nDaraus resultiert: Zeit (h) = Strecke (NM) / Geschwindigkeit (kts)
\nZu 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.
\nDas 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.
\n\nDabei gibt es keine Instrument an Bord, die auf diese Umstände hinweisen: Die Geschwindigkeit eines Flugzeugs wird an Bord des Flugzeugs relativ zur umgebenden Luft angezeigt. Das kann unter anderem dafür sorgen, dass Flugzeug eine fantastische Geschwindigkeit über dem Boden erreichen, die sie als wahre Geschwindigkeit relativ zur sie umgebenden Luft niemals überstehen würden. 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, auf einem eingestellten Radial zu bleiben.
\nDementsprechend 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 einen kleinen Rechner zum Berechnen des Korrekturkurses und der tatsächlichen Geschwindigkeit gebaut.
\nDie Welt der GPS-Navigation und Autopiloten hat euch den Spaß am Fliegen genommen? Dann macht mit beim VFR. 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.
", "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": "\nEndlich! Nachdem für den Digital Combat Simulator bereits jetzt eine riesige Palette an Fluggeräten erhältlich ist, produziert Eagle Dynamics nun selber den Klassiker unter den westlichen Kampfflugzeugen: Die F-16 Fighting Falcon aka „Viper“.
\n\nDieses 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.
\nDCS 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 das ikonische Kampfflugzeug der NATO. Wenn also nichts dazwischen kommt, steige ich demnächst von meiner (kostenlosen) Su-25 Frogfoot auf die F-16 um.
\nIch persönlich war schon früh der (simulierten) F-16 verbunden: Schon auf dem Commodore C-64 hatte ich mit Digital Integrations F-16 Combat Pilot meine ersten Erfahrungen gemacht. Und obwohl ich die legendäre Spectrum Holobytes Falcon-Reihe nur kurz gestreift habe, so habe ich doch zumindest in Strike Commander (einem Ableger der Wing Commander-Serie) die F-16 (simuliert) geflogen. So oder so ist die F-16 ein in unzähligen Computerspielen und -simulationen auftretender Kampfjet.
\nDCS 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.
\n", "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": "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 „Simplicity (II)“ dürfte vielen altgedienten Programmierern aus der Seele sprechen.
\nTatsä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…
\n\nDer 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.
", "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 und ", "content_html": "Vor vielen Jahren haben Web-Entwickler <i>
-, <b>
- und <u>
-Tags im HTML den Rücken gekehrt.
In der Anfangsphase von HTML waren Tags und Attribute sowohl für Inhalt als auch 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 <i>
, <b>
und <u>
mit HTML4 gestrichen, und waren ab dort deprecated bzw. personae non gratae.
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.
\n\nAls Ersatz von <b>
wurde <strong>
propagiert. Tatsächlich haben aber weiterhin beide Tags ihre Relevanz. Das Mozilla Developer Network weiß das folgende über <strong>
und <b>
zu berichten:
Nach dieser Definition wird <strong>
für Wörter verwendet, die man bei Aussprache besonders betonen würde. <b>
dagegen empfiehlt sich z.B. für die Hervorhebung von wichtigen Begriffen in einem Text.
Für <i>
sollte vor geraumer Zeit nur noch <em>
verwendet werden. Aber auch hier hat sich ein Wandel vollzogen. Das Mozilla Developer Network hat folgende Information <em>
und <i>
parat:
Dementsprechend wird <em>
für Wörter verwendet, die bei Aussprache besonders betont werden würden. Mit <i>
dagegen würden spezielle Begriffe und Wörter aus dem Text herausgehoben werden.
Selbst das verpönte <u>
hat eine Wiederauferstehung erlebt:
…wobei im Beispiel von MDN die rote Unterkringelung von falsch geschriebenen Wörtern aufgeführt wird.
\n<i>
und <b>
in MarkdownIn Markdown wird mit _Wort_
bzw. *Wort*
immer ein <em>Wort</em>
, mit __Wort__
bzw. **Wort**
immer ein <strong>Wort</strong>
erzeugt. Um <i>
und <b>
in Markdown zu erzeugen gibt es keine Symbole.
Dafür erlaubt Markdown aber die Verwendung von HTML-Tags! Wenn in Markdown also <b>Wort</b>
eingegeben wird, wird auch <b>Wort</b>
ausgegeben. Demzufolge ist dies hier ein valider Markdown-Text:
Hier kommt ein _kursives Wort_, gefolgt von einem *kursiven Wort*, beide mit `<em>` geschrieben.\n\nHier kommt ein __gefettetes Wort__, gefolgt von einem **gefetteten Wort**, beide mit `<strong>` geschrieben.\n\nHier dagegen kommt ein <i>kursives Wort</i>, mit `<i>` geschrieben.\n\nUnd hier kommt ein <b>gefettetes Wort</b>, mit `<b>` geschrieben.
\nViele von HTML-Entwicklern als Dogmen verstandene Leitsätze müssen immer wieder überprüft werden. Genau so wie die Vorstellung falsch ist, dass <table>
- und <div>
-Tags oder id
-Attribute nicht verwenden werden dürften, ist die Verwendung von <i>
, <b>
und <u>
im richtigen Kontext nicht nur erlaubt, sondern tatsächlich eine sehr gute Idee.
Ein Tipp von den Wedeler Jungs: Gregory Travis erklärt aus seiner Erfahrung als Programmierer und Pilot, warum Flugzeugbau und Softwarebau zwei sehr unterschiedliche Grundphilosophien haben, die nicht gut zueinander passen – am Beispiel des Abstürze der Boeing 737 Max.
\n\nTatsä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.
\nAls 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.
\nTatsä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 Kalashnikov-Programmierung hinweisen:
\n\nDie Programmierung muss nicht technisch herausragend sein – sie muss robust, unter jeder Umgebung einsatzbereit und einfach zu reparieren sein.
Sie auch den Artikel über die die Vorzüge einfacher Programmierung.
", "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": "Meine persönlichen Grundsätze für Programmierung finden sich bestens in dem Artikel Simple & Boring zusammengefasst. Meine eigenen Ideen dazu:
\nWenn ich ein neues Tool, ein neues Konzept oder eine neue Sprache verwenden möchte, frage ich mich vorher: Welches Problem löst das? Außerdem eine gute Frage: Welche Probleme verursacht das?
\nAußerdem verbreite ich gerne die Idee der Kalashnikov-Programmierung: Die Programmierung muss nicht technisch herausragend sein – sie muss robust, unter jeder Umgebung einsatzbereit und einfach zu reparieren sein.
", "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": "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 tatsächlich sichtbar sind. Damit verringert man gerade auf langen Seiten die initial geladene Menge an Bildern.
\nBisher hatte das mit etwas Aufwand zu tun, und auf jeden Fall mit JavaScript. Netterweise gibt es da jetzt auch eine deutlich einfachere Lösung.
\n\nDie bisherigen Lösungen gingen davon aus, dass irgendeine Form von LazyLoad-JavaScript auf der Seite montiert wurde, und das HTML eines jeden Bildes abgeändert werden musste:
\n<!-- Load when visible -->\n<img src="example-lowres.jpg"\n data-src="example-highres.jpg" class="lazyload"\n alt="" width="240" height="240" />
\nGoogle Chrome unterstützt in absehbarer Zukunft ein Attribut namens loading
, dass das Ladeverhalten von <img>
und <iframe>
steuert, ohne zusätzliches Javascript. Genaue Details kann man einem Blog-Post eines Chrome-Entwicklers über Lazy-Loading entnehmen, im HTML sieht das aber schlicht und ergreifend wie folgt aus:
<!-- Load when visible -->\n<img src="example.jpg" loading="lazy" alt="" width="240" height="240" />\n<iframe src="example.html" loading="lazy"></iframe>\n\n<!-- Load as soon as possible -->\n<img src="example.jpg" loading="eager" alt="" width="240" height="240" />\n<iframe src="example.html" loading="eager"></iframe>
\nDamit 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.
\nSolange Google Chrome das Feature noch nicht direkt unterstützt, muss man im aktuellen Google Chrome Lazy-Loading noch einmalig einschalten:
\nchrome://flags
in die URL-Zeile eingebenDanach sollte man beim Besuch einer Seite, die mit loading
-Attributen versehen ist, beim Öffnen des Inspektors bemerken, dass erst beim Scrollen auf der Seite weiter unten befindliche Bilder nachgeladen werden.
Um in einem gesamten Content-Block jedes <img>
und <iframe>
mit dem passenden loading
-Attribut zu versehen, reicht folgende kleine Funktion:
const lazyloadAttributes = function(html, loading = 'lazy') {\n return html.replace(/(<(?:img|iframe) )/g, '$1loading="' + loading + '" ');\n};
\nGleichsam können in PHP z.B. redaktionelle Texte durch diese Funktion durchgeleitet werden, um überall Lazy-Loading hinzuzufügen:
\nfunction lazyloadAttributes($html, $loading = 'lazy') {\n return preg_replace('/(<(?:img|iframe) )/is', '$1loading="' . $loading . '" ', $html);\n}
\nEigentlich 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.
\nAuß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.
", "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": "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 Aerofly FS2 verbessern.
\n\nAerofly FS2 ist noch weit entfernt von der Tiefe und Komplexität von X-Plane oder auch Prepar3D. Darum hatte ich mir zwischenzeitlich X-Plane 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.
\nNach meiner Rückkehr zu AFS2 vermisste ich nun aber doch ein paar Features:
\nWährend die lebendig wirkende Umwelt (in Form von Autos und Schiffen) gerade durch das Aerofly Life Project angegangen wird, habe ich mir also das Wetter vorgenommen.
\nTatsächlich existiert in X-Plane eine Idee, die in Aerofly FS2 ebenfalls funktioniert: Jeder größere Flughafen auf diesem Planeten veröffentlicht in relativ kurzen Abständen seinen aktuellen Wetterbericht in Form eines METAR. Dieser Wetterbericht ist nicht nur sehr verdichtet, sondern auch mit etwas Geschick maschinenlesbar.
\nKEYW 261153Z 36005KT 10SM FEW012 23/23 A3004 RMK AO2 SLP172 T02330217 10233 20222 53012
\nDarüber hinaus gibt es viele Anlaufstellen, die METARs über eine HTTP-Schnittstelle zur Verfügung stellen. Die Quelle war also gefunden.
\nGleichzeitig hatte ich in der Hauptkonfigurationsdatei main.mcf
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 main.mcf
tatsächlich in AFS2 übernommen wurden – hier war also mein Ziel.
Die Aufgabe war jetzt also klar erkennbar:
\nmain.mcf
.Als Webprogrammierer habe ich mich für das Projekt an eine Sprache gehalten, die ich gut kannte: JavaScript, bzw. NodeJS.
\nHier 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.
\nSchon nach einem Monat kopierte das Kommandozeilen-Tool fröhlich METAR-Daten in Aerofly FS2. Das ganze Projekt veröffentliche ich als „Aerofly-Weather“ bzw. „AeroWX“ bei NPM.
\nSchon 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.
\nEs 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: Electron.
\nMit 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 Electron-Builder zu einer eigenständigen EXE-Datei kompiliert und ließ sich dann als „Aerofly-Weather“ bzw. „AeroWX“ bei Github herunterladen.
\nAber 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.
\nDurch 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++.
\nPraktischer 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.
\nNichtsdestotrotz 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 „Aerofly Wettergerät“ bei Github bereitgestellt werden.
\nDas Aerofly Wettergerät 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: WxWidgets erlaubte mit überschaubarem Aufwand von zwei weiteren Wochen, eine native Applikation im Look & Feel des Betriebssystems zu erstellen.
\nDie so entstandene Desktop-Applikation wurde ebenfalls im Paket vom „Aerofly Wettergerät“ bei Github bereitgestellt, 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.
\nBis jetzt verbleibt ein Wehrmutstropfen bei dem Projekt: Das Wetter kann nur außerhalb der Simulation heruntergeladen und eingestellt werden. Damit bleiben folgende Fälle außen vor:
\nMeine Ü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.
", "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": "\nWer sich einen impertinenten Tonfall leistet, sollte sich seiner Sache besser sicher sein.
Besser ist es natürlich, Recht zu haben und ein angenehmer Gesprächspartner zu bleiben.
", "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": "