====== Newsletter-Werkzeuge ====== ^ Stand | 2026-11-14 (nach #11–#20) | ^ Bezug | [[ki:sitzungen:2026-11-14_newsletter]], [[news:newsletter:start]], [[ki:galnet:werkzeuge:edwiki_import]] | Skripte, mit denen die Newsletter aus den Wayback-Kopien (HTML) zu Wiki-Seiten und Import-Paketen werden. Herunterladen: auf den Dateinamen über dem Code klicken. ===== Ablauf pro Block ===== - HTML-Kopien (Wayback, „Webseite komplett“) je in einen eigenen Ordner; Datumsliste ''newsletter_index.json'' (aus der Galnet-France-Liste). - ''html2wiki.py raw'' → ''raw/en_NNN.txt'' (Rohtext) + ''raw/images_NNN.json'' (Bilder in Reihenfolge, erstes = Kopfbild = Box-Bild). - Gegenprobe mit dem Forumtext von CMDR Kzak (fehlende Sätze in beide Richtungen). - ''clean_en.py raw newsletter_index.json en'' → ''en/en_NNN.txt'': Inhaltsverzeichnis als fette Zeile, Links auf andere Newsletter als ''[[NL:NNN|…]]'', Einzelkorrekturen in ''FIXES''. - Deutsche Übersetzung von Hand (Claude) nach ''de/de_NNN.txt'' – gleiche Bildzeilen und Links wie EN (wird geprüft), Begriffe nach [[ki:galnet:glossar]], Drabble-Titel englisch + deutsch in Klammern, Rubrik „Elite Fiction“ → „Elite-Fiction“. - ''meta.json'' je Nummer: ''author'', ''wayback'', ''related'' (nur vorhandene Seiten), ''translation''. - ''build_newsletter.py . '' → ''pakete/newsletter_paket_-_tN.zip'' (≤ 3,7 MB, CSV im letzten Teil), dazu ''luecken_*.txt'' mit defekten Bildern. ===== Regeln ===== * Seiten: ''news:newsletter:NNN'' (DE, KI-Übersetzung mit Hinweis „ungeprüft“) und ''en:news:newsletter:NNN'' (Original). Medien: ''news:newsletter:NNN:'' (Name ohne Wayback-Anhang, klein). * JPG über 1920 px werden verkleinert (wie Galnet), PNG/GIF unverändert. * Abonnenten-Kennungen (''&e=…''), Werbe-Parameter (''utm_…'') und persönliche Anreden aus dem Seriendruck („Hi ,“ → „Hi Commander,“) werden entfernt; Links auf die Mailchimp-Archivliste zeigen auf [[news:newsletter:start]]. * Verfasser nur, wenn der Newsletter ihn nennt (Unterschrift, „von …“); sonst bleibt das Feld leer. * Schema ''newsletter'': number, date (Anzeige d.m.Y), picture, author, url (Original), archive (Wayback), translation. Schiffe, Fraktionen, Konzerne, Systeme über ''relations.related''. ===== Skripte ===== #!/usr/bin/env python3 """Mailchimp-Newsletter (Wayback-Kopie) -> DokuWiki-Rohtext (Englisch) + Bildliste. Aufruf: html2wiki.py Schreibt /en_.txt (Seitenrumpf ohne Rahmen) und /images_.json """ import json import os import re import sys import urllib.parse from bs4 import BeautifulSoup, NavigableString, Tag SKIP_IMG = re.compile(r'(social|google|tumblr|like_|cdn-images|facebook|twitter)', re.I) WAYBACK = re.compile(r'^https?://web\.archive\.org/web/\d+[a-z_]*/', re.I) MEDIA_NS = 'news:newsletter:{nr}:' def clean_name(fname): """Wayback-Anhang entfernen, DokuWiki-taugliche Kleinschreibung.""" base, ext = os.path.splitext(fname) base = re.sub(r'_[A-Za-z0-9]{4}$', '', base) # _0oNk usw. base = re.sub(r'[^A-Za-z0-9]+', '_', base).strip('_').lower() ext = ext.lower().replace('jpeg', 'jpg') return base + ext def wrap(text, mk): """Formatierung je Absatz/Zeile, Leerraum außerhalb der Marker.""" parts = re.split(r'(\n+)', text) res = [] for p in parts: if not p.strip() or p.startswith('\n'): res.append(p) continue lead = p[:len(p) - len(p.lstrip())] trail = p[len(p.rstrip()):] res.append(lead + mk + p.strip() + mk + trail) return ''.join(res) def esc(text): """Sternchen-Folgen (z. B. Teaser 'the *****') vor DokuWiki schützen.""" return re.sub(r'(?.*?', '', html, flags=re.S) soup = BeautifulSoup(html, 'html.parser') body = soup.find(id='templateBody') or soup.body header = soup.find(id='templateHeader') c = Conv(path, nr) if header: for im in header.find_all('img'): c.add_img(im) c.walk(body) c.flush() # Ende abschneiden: "Follow Elite: Dangerous" und alles danach blocks = [] for b in c.out: if b[0] == 'h' and re.match(r'follow elite', b[1], re.I): break blocks.append(b) ns = MEDIA_NS.format(nr=nr) lines = [] # Kopfbild (mail_head / erstes Bild im Kopf) nicht in den Text, es ist das Box-Bild if blocks and blocks[0][0] == 'img': blocks = blocks[1:] grouped = [] for b in blocks: if b[0] == 'img' and b[2] < 500 and grouped and grouped[-1][0] == 'imgs': grouped[-1][1].append(b) elif b[0] == 'img' and b[2] < 500: grouped.append(('imgs', [b])) else: grouped.append(b) blocks = grouped for b in blocks: if b[0] == 'imgs': lines.append(' '.join('{{%s%s?%d|}}' % (ns, i[1], i[2]) for i in b[1]) + '\n') continue if b[0] == 'p': lines.append(b[1] + '\n') elif b[0] == 'h': lines.append('===== %s =====\n' % b[1]) elif b[0] == 'img': lines.append('{{%s%s?%d|}}\n' % (ns, b[1], min(b[2], 560))) elif b[0] in ('ul', 'ol'): mark = '*' if b[0] == 'ul' else '-' lines.append('\n'.join(' %s %s' % (mark, i) for i in b[1]) + '\n') os.makedirs(outdir, exist_ok=True) open(os.path.join(outdir, 'en_%s.txt' % nr), 'w').write('\n'.join(lines)) json.dump(c.images, open(os.path.join(outdir, 'images_%s.json' % nr), 'w'), indent=1) if __name__ == '__main__': main() #!/usr/bin/env python3 """Rohtext (html2wiki) -> bereinigter englischer Seitenrumpf. - Inhaltsverzeichnis: Überschrift -> fette Zeile, ohne "Follow Elite: Dangerous", Banner bleibt - Links auf andere Newsletter (Mailchimp-IDs) -> interne Links - E-Mail-Adressen nicht fett, kleine Leerzeichen-/Satzzeichenfehler - gezielte Einzelkorrekturen (FIXES) Aufruf: clean_en.py """ import json import os import re import sys FIXES = { '015': [('**[[http://elite.frontier.co.uk/|http://elite.frontier.co.u]]k**', '**[[http://elite.frontier.co.uk/|http://elite.frontier.co.uk]]**'), ('**Engines**//: "When', '**Engines:** //"When')], '002': [('but**[[', 'but **[['), (']]**to check', ']]** to check')], '003': [('**[[http://i1305.photobucket.com/albums/s553/FrontierAshley/EmpireshipsketchesCropped_zpsc19947fb.jpg|smaller Imperial Ships]]**', '**[[NL:002|smaller Imperial Ships]]**')], '004': [('**[[http://s1305.photobucket.com/user/FrontierAshley/media/FedandEmpirefighters_zps35212663.jpg.html|early concept thumbnails]]**', '**[[NL:001|early concept thumbnails]]**'), ('\nShield Systems:\n', '\n**Shield Systems:**\n')], '007': [('&e=[UNIQID]', '')], '008': [(' \\\\ --- \\\\ This week’s drabble', '\n\n===== Elite Fiction: Childish Dreams =====\n\nThis week’s drabble'), ('**[[http://www.laveradio.com/|their site]]**now', '**[[http://www.laveradio.com/|their site]]** now')], '009': [('**“**"We don\'t need the whole universe, just the Milky Way." Where to start?', '“We don\'t need the whole universe, just the Milky Way.” Where to start?'), ('ring system(s). **”**', 'ring system(s).'), ('**[[http://elite.frontier.co.uk/images/newsletter_2013_07_05/schematic_flat_empfigher.png|Empire]][[http://elite.frontier.co.uk/images/newsletter_2013_07_05/schematic_flat_empfigher.png|Fighter]]**', '**[[http://elite.frontier.co.uk/images/newsletter_2013_07_05/schematic_flat_empfigher.png|Empire Fighter]]**'), ('\n- Elsewhere in the Elite galaxy', '\nElsewhere in the Elite galaxy')], } def main(): rawdir, index, outdir = sys.argv[1:4] idx = json.load(open(index)) by_id = {} for r in idx: m = re.search(r'id=([0-9a-f]{10})', r['url']) if m and re.fullmatch(r'\d+', r['nr']): by_id.setdefault(m.group(1), '%03d' % int(r['nr'])) os.makedirs(outdir, exist_ok=True) for fn in sorted(os.listdir(rawdir)): m = re.match(r'en_(\d{3})\.txt$', fn) if not m: continue nr = m.group(1) t = open(os.path.join(rawdir, fn)).read() # Inhaltsverzeichnis t = re.sub(r'===== Table of Contents[^=]*=====', '**Contents:**', t) t = re.sub(r'\n \* (\*\*)?Follow Elite: Dangerous(\*\*)?\n', '\n', t) # persönliche Anrede aus dem Mailchimp-Seriendruck (Name des Abonnenten) neutralisieren t = re.sub(r'^Hi (?!Commander)[^,\n]{1,40},', 'Hi Commander,', t) t = re.sub(r'^===== return to contents =====\n', '', t, flags=re.M | re.I) t = re.sub(r'^\{\{[^}]*transparent[^}]*\}\}\n', '', t, flags=re.M) # Platzhalter-GIF # Werbe-Parameter (utm_…) aus Links entfernen t = re.sub(r'[?&]utm_[^|\]]*?(?=[|\]])', '', t) # Einzelkorrekturen for a, b in FIXES.get(nr, []): assert a in t, (nr, a[:60]) t = t.replace(a, b) # Links auf andere Newsletter def nl_link(mm): url, text = mm.group(1), mm.group(2) i = re.search(r'id=([0-9a-f]{10})', url) if i and i.group(1) in by_id: target = by_id[i.group(1)] if target != nr: return '[[NL:%s|%s]]' % (target, text) return mm.group(0) t = re.sub(r'\[\[https?://us2\.campaign-archive\d?\.com/home/[^|\]]*\|', '[[NL:start|', t) t = re.sub(r'\[\[(https?://us2\.campaign-archive[^|\]]*)\|([^\]]*)\]\]', nl_link, t) # Fettung um Links mit eigener Fettung: [[url|**x**]] -> **[[url|x]]** t = re.sub(r'\[\[([^|\]]+)\|\*\*([^\]]*?)\*\*\]\]', r'**[[\1|\2]]**', t) # E-Mail-Adresse nicht fett t = re.sub(r'\*\*([\w.]+@frontier\.co\.uk)\*\*', r'\1', t) t = re.sub(r' +([.,!?])', r'\1', t) t = re.sub(r'\]\]\*\*(?=[A-Za-z])', ']]** ', t) t = re.sub(r'(?<=[A-Za-z])\*\*\[\[', ' **[[', t) t = re.sub(r'^If you do not wish to receive any more.*\n', '', t, flags=re.M) t = re.sub(r'\n{3,}', '\n\n', t).strip() + '\n' open(os.path.join(outdir, 'en_%s.txt' % nr), 'w').write(t) if __name__ == '__main__': main() #!/usr/bin/env python3 """Newsletter-Paket für edwiki-import.php bauen. Eingaben (Arbeitsordner): en/en_NNN.txt bereinigter englischer Rumpf (clean_en.py) de/de_NNN.txt deutsche Übersetzung (Claude) raw/images_NNN.json Bildliste (html2wiki.py) newsletter_index.json Nummer, Datum, Original-Link (galnet.fr-Liste) meta.json je Nummer: author, wayback, related, translation Ausgabe: build/pages/..., build/media/..., build/newsletter_NNN-NNN.csv, pakete/newsletter_paket_-_tN.zip (je <= 3,7 MB, CSV im letzten Teil) Aufruf: build_newsletter.py """ import csv import io import json import os import re import shutil import sys import zipfile from PIL import Image MAXPX = 1920 ZIPMAX = 3_700_000 KI_NOTE = '//Übersetzung aus dem Englischen: Claude, ungeprüft.//' LANGS = {'de': 'news:newsletter', 'en': 'en:news:newsletter'} def frame(title, body, footer): return f"""[<>] ====== {title} ====== ---- {body.strip()} {footer} {{{{structbox>newsletter}}}} ---- [<>] """ def de_date(iso): y, m, d = iso.split('-') return f'{d}.{m}.{y}' def links(text, lang): ns = LANGS[lang] text = text.replace('[[NL:start|', '[[news:newsletter:start|') # Übersicht gibt es nur auf Deutsch return re.sub(r'\[\[NL:(\d{3})\|', lambda m: f'[[{ns}:{m.group(1)}|', text) def save_image(src, dst): try: Image.open(src).verify() except Exception: return 'FEHLT (Wayback-Kopie defekt)' os.makedirs(os.path.dirname(dst), exist_ok=True) ext = os.path.splitext(dst)[1] if ext == '.jpg': im = Image.open(src) if max(im.size) > MAXPX: im.thumbnail((MAXPX, MAXPX), Image.LANCZOS) im.convert('RGB').save(dst, 'JPEG', quality=88, optimize=True) return 'verkleinert' shutil.copyfile(src, dst) return '' def main(): work, a, b = sys.argv[1], int(sys.argv[2]), int(sys.argv[3]) idx = {r['nr']: r for r in json.load(open(os.path.join(work, 'newsletter_index.json')))} meta = json.load(open(os.path.join(work, 'meta.json'))) build = os.path.join(work, 'build') shutil.rmtree(build, ignore_errors=True) rows, report, gaps = [], [], [] for n in range(a, b + 1): nr = '%03d' % n info, m = idx[str(n)], meta[nr] date = info['date'] title = f'Elite: Dangerous Newsletter #{n}' src = f'//Quelle: Frontier Developments, {title}, {de_date(date)}//' de = links(open(os.path.join(work, 'de', f'de_{nr}.txt')).read(), 'de') en = links(open(os.path.join(work, 'en', f'en_{nr}.txt')).read(), 'en') pages = { f'pages/news/newsletter/{nr}.txt': frame(title, de, KI_NOTE + ' \\\\\n' + src), f'pages/en/news/newsletter/{nr}.txt': frame(title, en, f'//Source: Frontier Developments, {title}, {date}//'), } for p, t in pages.items(): os.makedirs(os.path.dirname(os.path.join(build, p)), exist_ok=True) open(os.path.join(build, p), 'w').write(t) # Bilder: alle, die im Text vorkommen + Kopfbild (Box) used = set(re.findall(r'\{\{news:newsletter:%s:([^?|}]+)' % nr, de)) imgs = json.load(open(os.path.join(work, 'raw', f'images_{nr}.json'))) head = imgs[0]['name'] if m.get('header_local'): # Wayback hat ein falsches Kopfbild geliefert (gleicher Dateiname bei Mailchimp) imgs[0]['local'] = m['header_local'] report.append(f'#{n} Kopfbild ersetzt durch {os.path.basename(m["header_local"])}') for im in imgs: if im['name'] in used or im['name'] == head: note = save_image(im['local'], os.path.join(build, 'media/news/newsletter', nr, im['name'])) if note.startswith('FEHLT'): gaps.append(f'#{n}\tnews:newsletter:{nr}:{im["name"]}\t{im["orig"] or "-"}') elif note: report.append(f'#{n} {im["name"]}: {note} auf {MAXPX} px') missing = used - {i['name'] for i in imgs} if missing: report.append(f'#{n} FEHLENDE BILDER: {sorted(missing)}') rows.append({ 'pid': f'news:newsletter:{nr}', 'number': str(n), 'date': date, 'picture': f'news:newsletter:{nr}:{head}', 'author': m['author'], 'url': re.sub(r'&e=[^&]*', '', info['url']), # Abonnenten-Kennung entfernen 'archive': m['wayback'], 'translation': m.get('translation', 'KI'), 'relations.related': ','.join(m.get('related', [])), }) # feste Seiten (Übersicht, Vorlage, news:start, Sidebar): static/pages/... 1:1 übernehmen shutil.copytree(os.path.join(work, 'static', 'pages'), os.path.join(build, 'pages'), dirs_exist_ok=True) if gaps: open(os.path.join(build, f'luecken_newsletter_{a:03d}-{b:03d}.txt'), 'w').write( 'Nr\tfehlendes Bild (Medien-ID)\tOriginal (über Wayback suchen)\n' + '\n'.join(gaps) + '\n') report.append(f'{len(gaps)} Bilder fehlen, siehe luecken_newsletter_{a:03d}-{b:03d}.txt') csvname = f'newsletter_{a:03d}-{b:03d}.csv' with open(os.path.join(build, csvname), 'w', newline='') as fh: w = csv.DictWriter(fh, fieldnames=list(rows[0])) w.writeheader() w.writerows(rows) # Pakete files = [] for root, _, fs in os.walk(build): for f in sorted(fs): full = os.path.join(root, f) rel = os.path.relpath(full, build) if rel.endswith('.csv'): continue files.append((rel, full)) files.sort() outdir = os.path.join(work, 'pakete') shutil.rmtree(outdir, ignore_errors=True) os.makedirs(outdir) parts, cur, size = [], [], 0 for rel, full in files: s = os.path.getsize(full) + 200 + len(rel) * 2 if cur and size + s > ZIPMAX: parts.append(cur) cur, size = [], 0 cur.append((rel, full)) size += s cur.append((csvname, os.path.join(build, csvname))) parts.append(cur) for i, part in enumerate(parts, 1): zn = os.path.join(outdir, f'newsletter_paket_{a:03d}-{b:03d}_t{i}.zip') with zipfile.ZipFile(zn, 'w', zipfile.ZIP_DEFLATED) as z: for rel, full in part: z.write(full, rel) report.append(f'{os.path.basename(zn)}: {len(part)} Dateien, {os.path.getsize(zn) / 1e6:.2f} MB') print('\n'.join(report)) if __name__ == '__main__': main() ===== Metadaten ===== { "001": { "author": "Michael Brookes", "wayback": "https://web.archive.org/web/20190316200753/https://us2.campaign-archive.com/?u=dcbf6b86b4b0c7d1c21b73b1e&id=bafc8227dd", "related": [ "hangar:ships:sidewinder", "codex:federal:start", "codex:imperial:start" ], "translation": "KI" }, "002": { "author": "Ashley Barley", "wayback": "https://web.archive.org/web/20150408094846/http://us2.campaign-archive2.com/?u=dcbf6b86b4b0c7d1c21b73b1e&id=b5519ec0fe", "related": [ "hangar:ships:sidewinder", "hangar:ships:anaconda", "codex:imperial:start", "codex:federal:start", "galaxy:systems:lave" ], "translation": "KI" }, "003": { "author": "Ashley Barley", "wayback": "https://web.archive.org/web/20170901205441/http://us2.campaign-archive1.com/?u=dcbf6b86b4b0c7d1c21b73b1e&id=7b8136bd4a", "related": [ "hangar:ships:sidewinder", "codex:imperial:start", "codex:federal:start" ], "translation": "KI" }, "004": { "author": "Ashley Barley", "wayback": "https://web.archive.org/web/20201112042442/https://us2.campaign-archive.com/?u=dcbf6b86b4b0c7d1c21b73b1e&id=d266df1c3b", "related": [ "hangar:ships:sidewinder", "hangar:ships:cobra_mk3", "codex:federal:start", "galaxy:systems:lave" ], "translation": "KI" }, "005": { "author": "Ashley Barley", "wayback": "https://web.archive.org/web/20151104160412/http://us2.campaign-archive1.com/?u=dcbf6b86b4b0c7d1c21b73b1e&id=a4bd777a7f", "related": [ "codex:imperial:start", "codex:federal:start", "codex:corporations:lakon_spaceways", "codex:corporations:saud_kruger", "codex:corporations:gutamaya", "codex:corporations:core_dynamics" ], "translation": "KI" }, "006": { "author": "Ashley Barley", "wayback": "https://web.archive.org/web/20151104144759/http://us2.campaign-archive1.com/?u=dcbf6b86b4b0c7d1c21b73b1e&id=94dad3b09c", "related": [ "hangar:ships:eagle", "hangar:ships:adder", "hangar:ships:asp_explorer" ], "translation": "KI" }, "007": { "author": "Ashley Barley", "wayback": "https://web.archive.org/web/20151104144817/http://us2.campaign-archive1.com/?u=dcbf6b86b4b0c7d1c21b73b1e&id=c0b11fe947", "related": [ "hangar:ships:imperial_courier", "hangar:ships:imperial_cutter", "codex:imperial:start" ], "translation": "KI" }, "008": { "author": "Ashley Barley", "wayback": "https://web.archive.org/web/20150130055157/http://us2.campaign-archive1.com/?u=dcbf6b86b4b0c7d1c21b73b1e&id=b3760cf65e", "related": [ "hangar:ships:sidewinder", "hangar:ships:anaconda", "codex:federal:start", "codex:imperial:start", "codex:alliance:start" ], "translation": "KI" }, "009": { "author": "Ashley Barley", "wayback": "https://web.archive.org/web/20140901000640/http://us2.campaign-archive2.com/?u=dcbf6b86b4b0c7d1c21b73b1e&id=ffe2385d13", "related": [ "codex:federal:start", "codex:imperial:start", "codex:alliance:start", "codex:misc:pilotenvereinigung", "galaxy:systems:sol", "galaxy:systems:achenar", "galaxy:systems:alioth" ], "translation": "KI" }, "010": { "author": "Ashley Barley", "wayback": "https://web.archive.org/web/20140901000639/http://us2.campaign-archive2.com/?u=dcbf6b86b4b0c7d1c21b73b1e&id=ee59a3bb5e", "related": [ "hangar:ships:dolphin", "hangar:ships:orca", "codex:corporations:gutamaya" ], "translation": "KI" }, "011": { "author": "Ashley Barley", "wayback": "https://web.archive.org/web/20140723125234/http://us2.campaign-archive1.com/?u=dcbf6b86b4b0c7d1c21b73b1e&id=7157d0e3e1", "related": [ "hangar:ships:cobra_mk3", "codex:federal:start" ], "translation": "KI" }, "012": { "author": "", "wayback": "https://web.archive.org/web/20190316185013/https://us2.campaign-archive.com/?u=dcbf6b86b4b0c7d1c21b73b1e&id=d6ef3ab726", "related": [], "translation": "KI", "header_local": "/home/claude/nl2_in/Elite_Dangerous Newsletter #017_files/mail_head_copy_jWHE.JPG", "header_note": "Wayback-Kopien von #12 und #17 haben die Kopfbilder vertauscht (Mailchimp-Dateiname mail_head_copy.jpg doppelt)" }, "013": { "author": "", "wayback": "https://web.archive.org/web/20150130220838/http://us2.campaign-archive2.com/?u=dcbf6b86b4b0c7d1c21b73b1e&id=94e38570c6", "related": [], "translation": "KI" }, "014": { "author": "", "wayback": "https://web.archive.org/web/20140901000640/http://us2.campaign-archive2.com/?u=dcbf6b86b4b0c7d1c21b73b1e&id=f703580f39", "related": [ "hangar:ships:sidewinder", "codex:corporations:remlok" ], "translation": "KI" }, "015": { "author": "", "wayback": "https://web.archive.org/web/20140901000556/http://us2.campaign-archive1.com/?u=dcbf6b86b4b0c7d1c21b73b1e&id=4075b302f4", "related": [ "hangar:ships:sidewinder", "hangar:ships:anaconda", "hangar:ships:cobra_mk3" ], "translation": "KI" }, "016": { "author": "", "wayback": "https://web.archive.org/web/20170901201148/http://us2.campaign-archive1.com/?u=dcbf6b86b4b0c7d1c21b73b1e&id=7d88ceec82", "related": [ "hangar:ships:anaconda", "hangar:ships:sidewinder", "codex:federal:start" ], "translation": "KI" }, "017": { "author": "Michael Brookes, Mark Boss", "wayback": "https://web.archive.org/web/20150131230822/http://us2.campaign-archive1.com/?u=dcbf6b86b4b0c7d1c21b73b1e&id=f9f6f99d01", "related": [ "codex:corporations:sirius_corporation" ], "translation": "KI", "header_local": "/home/claude/nl2_in/Elite_Dangerous Newsletter #012_files/mail_head_copy_vJtR.jpg", "header_note": "Wayback-Kopien von #12 und #17 haben die Kopfbilder vertauscht (Mailchimp-Dateiname mail_head_copy.jpg doppelt)" }, "018": { "author": "", "wayback": "https://web.archive.org/web/20140806215529/http://us2.campaign-archive2.com/?u=dcbf6b86b4b0c7d1c21b73b1e&id=89b597852e", "related": [ "hangar:ships:cobra_mk3", "hangar:ships:sidewinder", "hangar:ships:python", "codex:corporations:faulcon_delacy" ], "translation": "KI" }, "019": { "author": "Frontier-Team", "wayback": "https://web.archive.org/web/20140901000600/http://us2.campaign-archive1.com/?u=dcbf6b86b4b0c7d1c21b73b1e&id=d6f301a16e", "related": [ "hangar:ships:cobra_mk3", "hangar:ships:eagle", "hangar:ships:sidewinder", "codex:misc:pilotenvereinigung", "galaxy:systems:sol", "galaxy:systems:achenar", "galaxy:systems:alioth" ], "translation": "KI" }, "020": { "author": "Frontier-Team", "wayback": "https://web.archive.org/web/20140901000638/http://us2.campaign-archive2.com/?u=dcbf6b86b4b0c7d1c21b73b1e&id=ee05d74c71", "related": [ "hangar:ships:imperial_courier", "hangar:ships:sidewinder", "codex:federal:start", "codex:imperial:start", "codex:alliance:start" ], "translation": "KI" } }