Zum Hauptinhalt springen
Rezept Nummer 143

Rezepte · Kapitel 9 · Vollständige Publikationen

Ein Wochenbulletin: die ersten Berichte über AIDS

Zwei CDC-Berichte von 1981 als Bulletin auf US Letter: Kopf, Fallberichte mit Dachzeilen, Stile für Reported by und Editorial Note, nummerierte Literatur.

Auf dieser Seite
Ausgabe
Canvas · PDF
Stufe
Mittel
Postext
Getestet mit Postext 1.32.0
Erfordert ≥ 1.25.0 · postext-pdf ≥ 1.25.0
Lizenz
Aktualisiert am 10. Okt. 2026
Code MIT · Text CC BY 4.0

S. 1 von 6

  • Englisches Beispiel: noch keine deutsche Ausgabe
  • Endformat 215,9 × 279,4 mm
  • 2 Spalten, 6,3 mm Spaltenabstand
  • IBM Plex Serif 9,5/13
  • IBM Plex Sans Condensed
  • Libre Franklin
  • 6 Seiten
  • Stufe
  • Postext 1.32.0
  • In 204 ms gesetzt
  • 180 Zeilen Code

Kurz gesagt

Ein Gesundheitsbulletin von 1981, neu auf Briefpapier gesetzt. Jede Art von Absatz eines Berichts (die Fälle, die Liste der meldenden Ärzte, der Kommentar der Redaktion) ist eigens gestaltet, und die Literatur wird für Sie nummeriert.

Was Sie setzen

Sechs Seiten eines epidemiologischen Wochenbulletins auf US Letter, mit einem Nachdruck der beiden Berichte, in denen die Centers for Disease Control zum ersten Mal beschrieben, was später als AIDS bekannt wurde: fünf Fälle von Pneumocystis-Pneumonie in Los Angeles (5. Juni 1981) und die Fälle von Kaposi-Sarkom, die folgten (3. Juli 1981). Der Kopf ist ein eigener Entwurf im Geist eines Regierungsbulletins jener Zeit, ein blaues Band mit einer schmalen Wortmarke über zwei Spalten Plex Serif. Jede Stimme eines Berichts hat ihren eigenen Stil: Fallberichte unter fetten nummerierten Etiketten, die Zeile Reported by in kleiner Kursive, die Editorial Note, Literaturverweise in Klammern und eine nummerierte Liste. Text, Literatur und Tabellen sind so, wie die CDC sie druckte; die Zeitleiste und die Falltabelle auf Seite 2 stammen von den Herausgebern.

Dieses Rezept beantwortet

  • Wie setze ich einen wöchentlichen Bulletin-Bericht: Zeitungskopf, Fallberichte, Anmerkung der Redaktion und nummerierte Literaturangaben?
  • Wie zitiere ich Werke und erstelle das Literaturverzeichnis nach APA, IEEE oder einem anderen Zitierstil?
  • Wie erstelle ich eine Tabelle mit Kopfzeilen, verbundenen Zellen, Spaltenbreiten und Ausrichtung je Zelle?
  • Wie setze ich einen Open-Access-Artikel aus arXiv oder PubMed Central mit Postext neu, mit seinen Zitaten, Abbildungen und seiner Lizenzzeile?

Die kurze Antwort

script.js · Zeilen 85–105im vollständigen Code
// :::paragraphs{style="…"} wraps the blocks of each voice; **Patient 1:** is a run-in label.
const voice = (id, family, size, lead, extra) => ({ id, fontFamily: family, fontSize: pt(size),
  lineHeight: pt(lead), color: col('ink'), boldColor: col('ink'), ...extra });
const aside = { textAlign: 'left', firstLineIndent: pt(0), snapToGrid: false };
const paragraphStyles = [
  // Case histories and the Editorial Note: the body texture, bold labels in the accent.
  voice('case', TEXT, 9.5, LEAD, { boldColor: col('accent'), boldFontWeight: 600 }),
  voice('editorial', TEXT, 9.5, LEAD, { boldColor: col('accent'), boldFontWeight: 600 }),
  // "Reported by …": the authors' line, italic small type in the condensed sans, off the grid.
  voice('reported', LABEL, 7.8, 10.2, { ...aside, italic: true, color: col('muted'),
    hyphenation: false, marginTop: pt(4), marginBottom: pt(6) }),
  // A line the reprint adds, in the label face and the accent: never taken for 1981 text.
  voice('editor', LABEL, 8, 10.6, { ...aside, italic: true, color: col('accent'),
    marginTop: pt(3), marginBottom: pt(5) }),
  voice('colophon', LABEL, 7.4, 9.6, { ...aside, color: col('muted'), marginTop: pt(LEAD) }),
];
// MMWR cited (1) in citation order, and each report (its H1 is a chapter) counted from 1.
registerCitationEngine(createCiteprocEngine({ styles: STYLES, locales: LOCALES }));
const citations = { style: 'american-medical-association', marker: 'parentheses',
  numbering: 'chapter', bibliography: { scope: 'chapter', fontSize: em(0.86),
    lineHeight: pt(10.6), entrySpacing: pt(1.5), labelAlign: 'right' } };

Zutaten

Schrift
IBM Plex Serif, Libre Franklin, IBM Plex Sans Condensed (SIL OFL 1.1)
Dateien
  • Figure 1, timeline of the five cases, drawn in code from the dates in the case reports (Ignacio Ferro, eigener Text)

Zubereitung

#1 · Ein Absatzformat pro Stimme

Den Code finden Sie oben unter Die kurze Antwort. Ein Bulletinbericht ist in mehreren Registern geschrieben: die Fallberichte, die Liste der Personen, die sie gemeldet haben, der Kommentar der Redaktion. Jede Passage in :::paragraphs{style="…"} einzuschließen gibt ihr ein Aussehen, ohne die Wörter anzurühren, sodass die Zeile Reported by auf 7,8 pt schmale Kursive außerhalb des Grundlinienrasters fällt, während die Fallberichte die Textur des Grundtextes behalten, mit ihren Etiketten **Patient 1:** in der Akzentfarbe. Die Zitate sind als [@walzer1974] geschrieben; american-medical-association mit marker: 'parentheses' setzt sie als (1) und listet die Werke in der Reihenfolge der Zitate, wie es das Wochenblatt tat, numbering: 'chapter' zählt die Zitate jedes Berichts ab 1, und scope: 'chapter' setzt seine Liste mit denselben Nummern darunter.

#2 · Ein Kopf, der den ersten Bericht eröffnet

script.js · Zeilen 38–68im vollständigen Code
// Kicker and dateline are attributes of each report's H1; {titleText} read with inlineMarks
// keeps the italic genus. The July report opens where June ends, under a double rule.
const reportHead = (y, size) => [
  text('kicker', '{attr.kicker}', LABEL, 8.5, { ...caps(8.5), color: col('accent'),
    placement: at('container', 'top-left', 0, y, MEASURE) }),
  text('title', '{titleText}', DISPLAY, size, { fontWeight: 800, lineHeight: 1.08,
    inlineMarks: true, placement: at('#kicker', 'below', 0, 2.2, MEASURE) }),
  text('dateline', '{attr.dateline}', LABEL, 9, { fontStyle: 'italic', color: col('muted'),
    placement: at('#title', 'below', 0, 2, MEASURE) }),
];
const masthead = { enabled: true, minHeight: mm(72), slot: { elements: [
  { kind: 'box', id: 'band', style: { backgroundColor: col('accent') }, placement: {
    anchor: { to: 'page', edge: 'top-left' }, size: { width: 'fill', height: mm(49) } } },
  text('series', 'A reprint series in public health history', LABEL, 8,
    { ...caps(8), color: col('paper'), placement: at('page', 'top-left', SIDE, 11, 120) }),
  text('number', 'Reprint No. 1', LABEL, 8, { ...caps(8), color: col('paper'), align: 'right',
    placement: at('page', 'top-right', -SIDE, 11, 50) }),
  text('wordmark', 'Surveillance Notes', DISPLAY, 50, { fontWeight: 800, color: col('paper'),
    letterSpacing: pt(-1), lineHeight: 1, placement: at('page', 'top-left', SIDE - 1, 18) }),
  text('issue', 'Two reports of June 5 and July 3, 1981: the first published accounts of '
    + 'what became known as AIDS, as the Centers for Disease Control printed them', TEXT, 9.5,
  { fontStyle: 'italic', lineHeight: 1.3, placement: at('container', 'top-left', 0, 29, 92) }),
  text('contents', '**1** *Pneumocystis* Pneumonia — Los Angeles\n**3** Kaposi’s Sarcoma '
    + 'and *Pneumocystis* Pneumonia Among Homosexual Men — New York City and California\n'
    + '**6** Notifiable diseases, week ending June 27, 1981',
  LABEL, 8, { inlineMarks: true, lineHeight: 1.3, boldColor: col('accent'),
    placement: at('container', 'top-right', 0, 29, 76), align: 'left' }),
  rule('rule-a', 46.5, 2), rule('rule-b', 48, 0.5), ...reportHead(52, 23),
] } };
const opener = { enabled: true, minHeight: mm(26), slot: { elements: [rule('rule-a', 0, 2),
  rule('rule-b', 1.5, 0.5), ...reportHead(5, 18)] } };

Der Kopf ist das Design des Überschriftenstils des ersten Berichts, daher wird er einmal gedruckt, auf Seite 1, und die Kolumnentitel lassen diese Seite aus (pages: 'body'). Dachzeile und Datumszeile kommen aus Attributen der H1 jedes Berichts, und der Titel ist {titleText}: Ein Textelement mit inlineMarks: true behält die kursive Gattung der Überschrift. Der Juli-Bericht beginnt mit denselben drei Elementen unter einer Doppellinie. Sein Überschriftenstil läuft mit spanBreak: false über die ganze Seitenbreite, sodass die Überschrift dort beginnt, wo der Juni-Bericht endet: Die Spalten darüber enden auf gleicher Höhe, und der Text läuft darunter in beiden Spalten weiter, so wie das Wochenblatt einen Bericht an den anderen anschloss.

#3 · Drei Tabellen aus tabulatorgetrenntem Text

script.js · Zeilen 439–472im vollständigen Code
const NUMBER = /^[\d,.()% –]*$/; // a column of counts aligns right, its heading centred
const table = (tsv, headerRows, columnWidths) => {
  const model = parseTSV(tsv, { headerRows });
  const numeric = model.rows[0].map((_, c) => model.rows.slice(headerRows)
    .every((row) => NUMBER.test(row[c].content)));
  return { ...model, columnWidths, rows: model.rows.map((cells, r) => cells.map((cell, c) =>
    (numeric[c] ? { ...cell, align: r < headerRows ? 'center' : 'right' } : cell))) };
};
// Two header rows, as the weekly printed them: "25th week ending" spans two columns.
const notifiable = [[0, 0, 1, 0], [0, 1, 0, 2], [0, 3, 1, 3], [0, 4, 0, 6]]
  .reduce((m, [r1, c1, r2, c2]) => mergeCells(m, { start: { row: r1, col: c1 },
    end: { row: r2, col: c2 } }), table(NOTIFIABLE, 2, [3.6, 1, 1, 1, 1.1, 1.1, 1.1]));
const added = 'Compiled for this reprint from the case reports; not part of the 1981 report.';
const res = (id, typeId, kind, placement, more) => ({ id, typeId, kind, placement,
  createdAt: 0, updatedAt: 0, ...more });
const resources = [
  res('fig-timeline', 'figure', 'svg', { position: 'bottom', span: 'page' }, {
    svg: { fileId: 'timeline.svg', width: 1780, height: 490 },
    caption: 'The five patients, September 1980 to May 1981, by month. The illness before '
      + 'the pneumonia is counted back from the month of diagnosis, as each report gives it.',
    note: `Drawn by the editors. ${added}`,
    altText: 'A timeline of five rows, one per patient: Pneumocystis pneumonia diagnosed '
      + 'between February and April 1981, two deaths in March and May.' }),
  res('tbl-cases', 'table', 'table', { position: 'top', span: 'page' }, {
    caption: 'The five case reports at a glance.', note: added,
    table: { model: table(CASES, 1, [0.7, 0.45, 1, 2.2, 2.4, 1.5]) } }),
  res('tbl-complaints', 'table', 'table', { position: 'bottom' }, {
    caption: 'Presenting complaints in 20 patients with Kaposi’s sarcoma',
    table: { model: table(COMPLAINTS, 1, [2, 1.15]) } }),
  res('tbl-notifiable', 'table', 'table', { position: 'here' }, {
    caption: 'Summary — cases of specified notifiable diseases, United States',
    note: 'Cumulative totals include revised and delayed reports through previous weeks.',
    table: { model: notifiable, styleId: 'weekly' } }),
];

Jede Tabelle ist ein Inhaltsslot mit tabulatorgetrenntem Text, dem Format, das eine Tabellenkalkulation kopiert, und parseTSV macht daraus ein Modell. Eine Spalte mit Zahlen ist rechtsbündig, ihre Überschrift zentriert; vier Aufrufe von mergeCells bauen den zweizeiligen Kopf der Übersicht meldepflichtiger Krankheiten. Der Tabellentyp setzt seinen Zähler bei jeder H1 zurück (resetOn: 'h1'), sodass jeder Bericht seine eigene Table 1 hat, wie 1981.

#4 · Ein Blau, überall verknüpft

script.js · Zeilen 17–21im vollständigen Code
const palette = { ink: '#1c1f24', accent: '#1f3f74', tint: '#e6eaf1', rule: '#a7b1c2',
  muted: '#566070', paper: '#ffffff' };
const col = (id) => ({ hex: palette[id], model: 'hex', paletteId: id });
const colorPalette = Object.entries({ ...palette, 'main-color': palette.accent })
  .map(([id, hex]) => ({ id, name: id, value: { hex, model: 'hex' } }));

Band, Etiketten, Seitenzahlen, Tabellenköpfe und Diagramm nennen alle denselben Eintrag der Palette, sodass jemand, der accent gegen die eigene Farbe eines Bulletins tauscht, die sechs Seiten auf einmal umfärbt.

Das ganze Rezept

Sandbox
// ═══ Postext Cookbook · Nº 143 · A weekly bulletin report: the first AIDS reports ═══
// https://postext.dev/en/cookbook/outbreak-report-bulletin
// Code: MIT · Text: CDC, MMWR 1981;30:250–252 and 305–308 (public domain) · Chart: original
// Fonts: IBM Plex Serif, Libre Franklin, Plex Sans Condensed (OFL) · Needs postext ≥ 1.25.0
import {
  buildDocumentWithFonts, renderPageToCanvas, registerCitationEngine, registerResourceImage,
  defaultResourceTypes, parseTSV, mergeCells, inlineSvgFonts,
} from 'https://esm.sh/postext';
import { renderToPdf, decompressWoff2 } from 'https://esm.sh/postext-pdf';
import { createCiteprocEngine, STYLES, LOCALES } from 'https://esm.sh/postext-citeproc';

const LANG = 'en'; // @lang: the language of the sample document ('en' | 'es')
const RECIPE = 'outbreak-report-bulletin';

// ─── 1 · Design ─────────────────────────────────────────────────────────────
// #region palette: a federal blue on office white, every colour linked by id
const palette = { ink: '#1c1f24', accent: '#1f3f74', tint: '#e6eaf1', rule: '#a7b1c2',
  muted: '#566070', paper: '#ffffff' };
const col = (id) => ({ hex: palette[id], model: 'hex', paletteId: id });
const colorPalette = Object.entries({ ...palette, 'main-color': palette.accent })
  .map(([id, hex]) => ({ id, name: id, value: { hex, model: 'hex' } }));
// #endregion
const [TEXT, DISPLAY, LABEL] = ['IBM Plex Serif', 'Libre Franklin', 'IBM Plex Sans Condensed'];
const [TRIM_W, TRIM_H, TOP, BOTTOM, SIDE, GUTTER] = [215.9, 279.4, 22, 20, 19, 6.35];
const MEASURE = TRIM_W - 2 * SIDE; // US Letter, two columns of 86 mm
const LEAD = 13; // pt: 9.5 pt Plex Serif, as a bulletin sets two columns of Letter

const text = (id, content, family, size, extra) => ({ kind: 'text', id, content, align: 'left',
  fontFamily: family, fontSize: pt(size), color: col('ink'), overflow: 'wrap', ...extra });
const at = (to, edge, x, y, width) => ({ anchor: { to, edge }, offset: { x: mm(x), y: mm(y) },
  ...(width && { size: { width: mm(width), height: 'auto' } }) });
const caps = (size, extra) => ({ fontFamily: LABEL, fontSize: pt(size), fontWeight: 600,
  letterSpacing: pt(size * 0.18), textTransform: 'uppercase', ...extra });
const rule = (id, y, thickness) => ({ kind: 'rule', id, color: col('accent'),
  thickness: pt(thickness), placement: at('container', 'top-left', 0, y, MEASURE) });

// #region masthead: the bulletin's band, issue strip and contents over the first report
// Kicker and dateline are attributes of each report's H1; {titleText} read with inlineMarks
// keeps the italic genus. The July report opens where June ends, under a double rule.
const reportHead = (y, size) => [
  text('kicker', '{attr.kicker}', LABEL, 8.5, { ...caps(8.5), color: col('accent'),
    placement: at('container', 'top-left', 0, y, MEASURE) }),
  text('title', '{titleText}', DISPLAY, size, { fontWeight: 800, lineHeight: 1.08,
    inlineMarks: true, placement: at('#kicker', 'below', 0, 2.2, MEASURE) }),
  text('dateline', '{attr.dateline}', LABEL, 9, { fontStyle: 'italic', color: col('muted'),
    placement: at('#title', 'below', 0, 2, MEASURE) }),
];
const masthead = { enabled: true, minHeight: mm(72), slot: { elements: [
  { kind: 'box', id: 'band', style: { backgroundColor: col('accent') }, placement: {
    anchor: { to: 'page', edge: 'top-left' }, size: { width: 'fill', height: mm(49) } } },
  text('series', 'A reprint series in public health history', LABEL, 8,
    { ...caps(8), color: col('paper'), placement: at('page', 'top-left', SIDE, 11, 120) }),
  text('number', 'Reprint No. 1', LABEL, 8, { ...caps(8), color: col('paper'), align: 'right',
    placement: at('page', 'top-right', -SIDE, 11, 50) }),
  text('wordmark', 'Surveillance Notes', DISPLAY, 50, { fontWeight: 800, color: col('paper'),
    letterSpacing: pt(-1), lineHeight: 1, placement: at('page', 'top-left', SIDE - 1, 18) }),
  text('issue', 'Two reports of June 5 and July 3, 1981: the first published accounts of '
    + 'what became known as AIDS, as the Centers for Disease Control printed them', TEXT, 9.5,
  { fontStyle: 'italic', lineHeight: 1.3, placement: at('container', 'top-left', 0, 29, 92) }),
  text('contents', '**1** *Pneumocystis* Pneumonia — Los Angeles\n**3** Kaposi’s Sarcoma '
    + 'and *Pneumocystis* Pneumonia Among Homosexual Men — New York City and California\n'
    + '**6** Notifiable diseases, week ending June 27, 1981',
  LABEL, 8, { inlineMarks: true, lineHeight: 1.3, boldColor: col('accent'),
    placement: at('container', 'top-right', 0, 29, 76), align: 'left' }),
  rule('rule-a', 46.5, 2), rule('rule-b', 48, 0.5), ...reportHead(52, 23),
] } };
const opener = { enabled: true, minHeight: mm(26), slot: { elements: [rule('rule-a', 0, 2),
  rule('rule-b', 1.5, 0.5), ...reportHead(5, 18)] } };
// #endregion

const head = (id, content, parity, edge, x, extra) => text(id, content, LABEL, 8, {
  parity, pages: 'body', fontWeight: 500, letterSpacing: pt(0.3), color: col('muted'),
  overflow: 'clip', placement: at('page', edge, x, 12, 150), ...extra });
const folio = { fontWeight: 700, color: col('accent') };
const header = { elements: [
  head('v-folio', '{pageNumber}', 'even', 'top-left', SIDE, folio),
  head('v-title', 'Surveillance Notes · Reprint No. 1', 'even', 'top-left', SIDE + 8),
  head('r-title', '{chapterTitleAtTop}', 'odd', 'top-right', -SIDE - 8, { align: 'right' }),
  head('r-folio', '{pageNumber}', 'odd', 'top-right', -SIDE, { ...folio, align: 'right' }),
] };
const footer = { elements: [head('drop-folio', '{pageNumber}', 'all', 'bottom', 0,
  { ...folio, align: 'center', pages: 'opener', placement: at('page', 'bottom', 0, -11, 20) })] };

// #region answer: case histories, "Reported by" and the Editorial Note as paragraph styles
// :::paragraphs{style="…"} wraps the blocks of each voice; **Patient 1:** is a run-in label.
const voice = (id, family, size, lead, extra) => ({ id, fontFamily: family, fontSize: pt(size),
  lineHeight: pt(lead), color: col('ink'), boldColor: col('ink'), ...extra });
const aside = { textAlign: 'left', firstLineIndent: pt(0), snapToGrid: false };
const paragraphStyles = [
  // Case histories and the Editorial Note: the body texture, bold labels in the accent.
  voice('case', TEXT, 9.5, LEAD, { boldColor: col('accent'), boldFontWeight: 600 }),
  voice('editorial', TEXT, 9.5, LEAD, { boldColor: col('accent'), boldFontWeight: 600 }),
  // "Reported by …": the authors' line, italic small type in the condensed sans, off the grid.
  voice('reported', LABEL, 7.8, 10.2, { ...aside, italic: true, color: col('muted'),
    hyphenation: false, marginTop: pt(4), marginBottom: pt(6) }),
  // A line the reprint adds, in the label face and the accent: never taken for 1981 text.
  voice('editor', LABEL, 8, 10.6, { ...aside, italic: true, color: col('accent'),
    marginTop: pt(3), marginBottom: pt(5) }),
  voice('colophon', LABEL, 7.4, 9.6, { ...aside, color: col('muted'), marginTop: pt(LEAD) }),
];
// MMWR cited (1) in citation order, and each report (its H1 is a chapter) counted from 1.
registerCitationEngine(createCiteprocEngine({ styles: STYLES, locales: LOCALES }));
const citations = { style: 'american-medical-association', marker: 'parentheses',
  numbering: 'chapter', bibliography: { scope: 'chapter', fontSize: em(0.86),
    lineHeight: pt(10.6), entrySpacing: pt(1.5), labelAlign: 'right' } };
// #endregion

const config = () => ({
  locale: 'en-us', colorPalette, citations, paragraphStyles, header, footer,
  resourceTypes: defaultResourceTypes(LANG).map((type) => ({ ...type, shortLabel: type.name,
    resetOn: 'h1', numberingTemplate: '{n}', // each report counts its tables from 1
    ...(type.id === 'table' && { captionStyle: { position: 'above' } }) })),
  headingStyles: [
    { id: 'lead', span: 'page', advancedDesign: masthead },
    { id: 'report', span: 'page', spanBreak: false, advancedDesign: opener },
    { id: 'back', span: 'page', breakBefore: { enabled: true, parity: 'any' }, // one column
      layout: { layoutType: 'single' }, advancedDesign: opener },
  ],
  page: { sizePreset: 'custom', width: mm(TRIM_W), height: mm(TRIM_H), dpi: 150, margins: {
    top: mm(TOP), bottom: mm(BOTTOM), left: mm(SIDE), right: mm(SIDE), mirror: true } },
  layout: { layoutType: 'double', gutterWidth: mm(GUTTER) },
  bodyText: { fontFamily: TEXT, fontSize: pt(9.5), lineHeight: pt(LEAD), color: col('ink'),
    boldColor: col('ink'), italicColor: col('ink'), referenceColor: col('ink'),
    referenceBold: false, firstLineIndent: mm(4), indentAfterHeading: false,
    minWordSpacing: 0.75, maxJustifyTracking: 10 }, // spaces from 0.75×, then 1 % of tracking
  headings: { fontFamily: LABEL, color: col('accent'), fontWeight: 600, levels: [
    { level: 1, breakBefore: { enabled: false } }, // a report runs on under the one before
    { level: 3, ...caps(8), lineHeight: pt(LEAD), marginTop: pt(LEAD / 2), marginBottom: pt(0) },
  ] },
  footnotes: { fontSize: pt(7.6), lineHeight: pt(10), color: col('muted'),
    numberFormat: 'symbols' }, // the 1981 asterisk: *, †, ‡ …
  tableStyle: { rules: 'horizontal', borderColor: col('rule'), borderWidth: pt(0.5),
    headerBackground: col('accent'), headerColor: col('paper'), headerBold: true,
    headerFontFamily: LABEL, headerFontSize: pt(7.8), bodyFontFamily: LABEL,
    bodyFontSize: pt(7.8), bodyColor: col('ink'), cellPadding: mm(1.3) },
  tableStyles: [{ id: 'weekly', bodyFontSize: pt(7.4), headerFontSize: pt(7.2), // set solid
    cellPadding: mm(0.75) }],
  captionStyle: { fontFamily: LABEL, fontSize: pt(8.2), color: col('ink'), labelBold: true,
    labelColor: col('accent'), gap: mm(2), note: { fontSize: pt(7), color: col('muted') } },
});

// ─── 2 · Content ────────────────────────────────────────────────────────────
const june = String.raw`---
Markdown-Beispiel · 122 Zeilen · content.en.mdtitle: "Pneumocystis Pneumonia — Los Angeles" author: "Centers for Disease Control" --- # *Pneumocystis* Pneumonia — Los Angeles {style="lead" kicker="Epidemiologic Notes and Reports" dateline="June 5, 1981 · Vol. 30, No. 21 · pp. 250–252"} In the period October 1980-May 1981, 5 young men, all active homosexuals, were treated for biopsy-confirmed *Pneumocystis carinii* pneumonia at 3 different hospitals in Los Angeles, California. Two of the patients died. All 5 patients had laboratory-confirmed previous or current cytomegalovirus (CMV) infection and candidal mucosal infection. Case reports of these patients follow. :::paragraphs{style="editor"} Figure 1 and Table 1 were added for this reprint. They restate the dates and findings of the five case reports below and add nothing to them (:ref{id="fig-timeline"}; :ref{id="tbl-cases"}). ::: :::paragraphs{style="case"} **Patient 1:** A previously healthy 33-year-old man developed *P. carinii* pneumonia and oral mucosal candidiasis in March 1981 after a 2-month history of fever associated with elevated liver enzymes, leukopenia, and CMV viruria. The serum complement-fixation CMV titer in October 1980 was 256; in May 1981 it was 32.[^paired] The patient’s condition deteriorated despite courses of treatment with trimethoprim-sulfamethoxazole (TMP/SMX), pentamidine, and acyclovir. He died May 3, and postmortem examination showed residual *P. carinii* and CMV pneumonia, but no evidence of neoplasia. **Patient 2:** A previously healthy 30-year-old man developed *P. carinii* pneumonia in April 1981 after a 5-month history of fever each day and of elevated liver-function tests, CMV viruria, and documented seroconversion to CMV, i.e., an acute-phase titer of 16 and a convalescent-phase titer of 28[^paired] in anticomplement immunofluorescence tests. Other features of his illness included leukopenia and mucosal candidiasis. His pneumonia responded to a course of intravenous TMP/SMX, but, as of the latest reports, he continues to have a fever each day. **Patient 3:** A 30-year-old man was well until January 1981 when he developed esophageal and oral candidiasis that responded to Amphotericin B treatment. He was hospitalized in February 1981 for *P. carinii* pneumonia that responded to oral TMP/SMX. His esophageal candidiasis recurred after the pneumonia was diagnosed, and he was again given Amphotericin B. The CMV complement-fixation titer in March 1981 was 8. Material from an esophageal biopsy was positive for CMV. **Patient 4:** A 29-year-old man developed *P. carinii* pneumonia in February 1981. He had had Hodgkins disease 3 years earlier, but had been successfully treated with radiation therapy alone. He did not improve after being given intravenous TMP/SMX and corticosteroids and died in March. Postmortem examination showed no evidence of Hodgkins disease, but *P. carinii* and CMV were found in lung tissue. **Patient 5:** A previously healthy 36-year-old man with a clinically diagnosed CMV infection in September 1980 was seen in April 1981 because of a 4-month history of fever, dyspnea, and cough. On admission he was found to have *P. carinii* pneumonia, oral candidiasis, and CMV retinitis. A complement-fixation CMV titer in April 1981 was 128. The patient has been treated with 2 short courses of TMP/SMX that have been limited because of a sulfa-induced neutropenia. He is being treated for candidiasis with topical nystatin. ::: [^paired]: Paired specimens not run in parallel. The diagnosis of *Pneumocystis* pneumonia was confirmed for all 5 patients antemortem by closed or open lung biopsy. The patients did not know each other and had no known common contacts or knowledge of sexual partners who had had similar illnesses. The 5 did not have comparable histories of sexually transmitted disease. Four had serologic evidence of past hepatitis B infection but had no evidence of current hepatitis B surface antigen. Two of the 5 reported having frequent homosexual contacts with various partners. All 5 reported using inhalant drugs, and 1 reported parenteral drug abuse. Three patients had profoundly depressed numbers of thymus-dependent lymphocyte cells and profoundly depressed *in vitro* proliferative responses to mitogens and antigens. Lymphocyte studies were not performed on the other 2 patients. :::paragraphs{style="reported"} Reported by MS Gottlieb, MD, HM Schanker, MD, PT Fan, MD, A Saxon, MD, JD Weisman, DO, Div of Clinical Immunology-Allergy, Dept of Medicine, UCLA School of Medicine; I Pozalski, MD, Cedars-Mt. Sinai Hospital, Los Angeles; Field Services Div, Epidemiology Program Office, CDC. ::: :::paragraphs{style="editorial"} **Editorial Note:** *Pneumocystis* pneumonia in the United States is almost exclusively limited to severely immunosuppressed patients [@walzer1974]. The occurrence of pneumocystosis in these 5 previously healthy individuals without a clinically apparent underlying immunodeficiency is unusual. The fact that these patients were all homosexuals suggests an association between some aspect of a homosexual lifestyle or disease acquired through sexual contact and *Pneumocystis* pneumonia in this population. All 5 patients described in this report had laboratory-confirmed CMV disease or virus shedding within 5 months of the diagnosis of *Pneumocystis* pneumonia. CMV infection has been shown to induce transient abnormalities of *in vitro* cellular-immune function in otherwise healthy human hosts [@rinaldo1977; @rinaldo1980]. Although all 3 patients tested had abnormal cellular-immune function, no definitive conclusion regarding the role of CMV infection in these 5 cases can be reached because of the lack of published data on cellular-immune function in healthy homosexual males with and without CMV antibody. In 1 report, 7 (3.6%) of 194 patients with pneumocystosis also had CMV infection; 40 (21%) of the same group had at least 1 other major concurrent infection [@walzer1974]. A high prevalence of CMV infections among homosexual males was recently reported: 179 (94%) of 190 males reported to be exclusively homosexual had serum antibody to CMV, and 14 (7.4%) had CMV viruria; rates for 101 controls of similar age who were reported to be exclusively heterosexual were 54% for seropositivity and zero for viruria [@drew1981]. In another study of 64 males, 4 (6.3%) had positive tests for CMV in semen, but none had CMV recovered from urine. Two of the 4 reported recent homosexual contacts. These findings suggest not only that virus shedding may be more readily detected in seminal fluid than in urine, but also that seminal fluid may be an important vehicle of CMV transmission [@lang1975]. All the above observations suggest the possibility of a cellular-immune dysfunction related to a common exposure that predisposes individuals to opportunistic infections such as pneumocystosis and candidiasis. Although the role of CMV infection in the pathogenesis of pneumocystosis remains unknown, the possibility of *P. carinii* infection must be carefully considered in a differential diagnosis for previously healthy homosexual males with dyspnea and pneumonia. ::: ### References :::bibliography{title=""} :::references{format=csl-json} [ { "id": "walzer1974", "type": "article-journal", "author": [ { "family": "Walzer", "given": "P. D." }, { "family": "Perl", "given": "D. P." }, { "family": "Krogstad", "given": "D. J." }, { "family": "Rawson", "given": "P. G." }, { "family": "Schultz", "given": "M. G." } ], "title": "<i>Pneumocystis carinii</i> pneumonia in the United States. Epidemiologic, diagnostic, and clinical features", "container-title": "Ann Intern Med", "issued": { "date-parts": [ [ 1974 ] ] }, "volume": "80", "page": "83-93" }, { "id": "cdc1981", "type": "article-journal", "author": [ { "literal": "Centers for Disease Control" } ], "title": "<i>Pneumocystis</i> pneumonia—Los Angeles", "container-title": "MMWR", "issued": { "date-parts": [ [ 1981 ] ] }, "volume": "30", "page": "250" } ] ::: :::references{format=bibtex} @article{rinaldo1977, author = {Rinaldo, Jr., C. R. and Black, P. H. and Hirsch, M. S.}, title = {Interaction of cytomegalovirus with leukocytes from patients with mononucleosis due to cytomegalovirus}, journal = {J Infect Dis}, year = 1977, volume = 136, pages = {667--678}} @article{rinaldo1980, author = {Rinaldo, Jr., C. R. and Carney, W. P. and Richter, B. S. and Black, P. H. and Hirsch, M. S.}, title = {Mechanisms of immunosuppression in cytomegaloviral mononucleosis}, journal = {J Infect Dis}, year = 1980, volume = 141, pages = {488--495}} @article{drew1981, author = {Drew, W. L. and Mintz, L. and Miner, R. C. and Sands, M. and Ketterer, B.}, title = {Prevalence of cytomegalovirus infection in homosexual men}, journal = {J Infect Dis}, year = 1981, volume = 143, pages = {188--192}} @article{lang1975, author = {Lang, D. J. and Kummer, J. F.}, title = {Cytomegalovirus in semen: observations in selected populations}, journal = {J Infect Dis}, year = 1975, volume = 132, pages = {472--473}} :::
`; // MMWR 1981;30(21):250–252 const july = String.raw`# Kaposi’s Sarcoma and *Pneumocystis* Pneumonia Among Homosexual Men — New York City and California {style="report" kicker="Epidemiologic Notes and Reports" dateline="July 3, 1981 · Vol. 30, No. 25 · pp. 305–308"}
Markdown-Beispiel · 121 Zeilen · content.july.en.md During the past 30 months, Kaposi’s sarcoma (KS), an uncommonly reported malignancy in the United States, has been diagnosed in 26 homosexual men (20 in New York City [NYC]; 6 in California). The 26 patients range in age from 26-51 years (mean 39 years). Eight of these patients died (7 in NYC, 1 in California)—all 8 within 24 months after KS was diagnosed. The diagnoses in all 26 cases were based on histopathological examination of skin lesions, lymph nodes, or tumor in other organs. Twenty-five of the 26 patients were white, 1 was black. Presenting complaints from 20 of these patients are shown in :ref{id="tbl-complaints"}. Skin or mucous membrane lesions, often dark blue to violaceous plaques or nodules, were present in most of the patients on their initial physician visit. However, these lesions were not always present and often were considered benign by the patient and his physician. A review of the New York University Coordinated Cancer Registry for KS in men under age 50 revealed no cases from 1970-1979 at Bellevue Hospital and 3 cases in this age group at the New York University Hospital from 1961-1979. Seven KS patients had serious infections diagnosed after their initial physician visit. Six patients had pneumonia (4 biopsy confirmed as due to *Pneumocystis carinii* [PC]), and one had necrotizing toxoplasmosis of the central nervous system. One of the patients with *Pneumocystis* pneumonia also experienced severe, recurrent, herpes simplex infection; extensive candidiasis; and cryptococcal meningitis. The results of tests for cytomegalovirus (CMV) infection were available for 12 patients. All 12 had serological evidence of past or present CMV infection. In 3 patients for whom culture results were available, CMV was isolated from blood, urine and/or lung of all 3. Past infections with amebiasis and hepatitis were commonly reported. Since the previous report of 5 cases of *Pneumocystis* pneumonia in homosexual men from Los Angeles [@cdc1981], 10 additional cases (4 in Los Angeles and 6 in the San Francisco Bay area) of biopsy-confirmed PC pneumonia have been identified in homosexual men in the state. Two of the 10 patients also have KS. This brings the total number of *Pneumocystis* cases among homosexual men in California to 15 since September 1979. Patients range in age from 25 to 46 years. :::paragraphs{style="reported"} Reported by A Friedman-Kien, MD, L Laubenstein, MD, M Marmor, PhD, K Hymes, MD, J Green, MD, A Ragaz, MD, J Gottleib, MD, F Muggia, MD, R Demopoulos, MD, M Weintraub, MD, D Williams, MD, New York University Medical Center, NYC; R Oliveri, MD, J Marmer, MD, NYC; J Wallace, MD, I Halperin, MD, JF Gillooley, MD, St. Vincent’s Hospital and Medical Center, NYC; N Prose, MD, Downstate Medical Center, NYC; E Klein, MD, Roosevelt Hospital, NYC; J Vogel, MD, B Safai, MD, P Myskowski, MD, C Urmacher, MD, B Koziner, MD, L Nisce, MD, M Kris, MD, D Armstrong, MD, J Gold, MD, Sloan-Kettering Memorial Institute, NYC; D Mildran, MD, Beth Israel Hospital, NYC; M Tapper, MD, Lenox Hill Hospital, NYC; JB Weissman, MD, Columbia Presbyterian Hospital, NYC; R Rothenberg, MD, State Epidemiologist, New York State Dept of Health; SM Friedman, MD, Acting Director, Bur of Preventable Diseases, New York City Dept of Health; FP Siegal, MD, Dept of Medicine, Mount Sinai School of Medicine, City College of New York, NYC; J Groundwater, MD, J Gilmore, MD, San Francisco; D Coleman, MD, S Follansbee, MD, J Gullett, MD, SJ Stegman, MD, University of California at San Francisco; C Wofsy, MD, San Francisco General Hospital, San Francisco; D Bush, MD, Franklin Hospital, San Francisco; L Drew, MD, PhD, Mt. Zion Hospital, E Braff, MD, S Dritz, MD, City/County Health Dept, San Francisco; M Klein, MD, Valley Memorial Hospital, Salinas; JK Preiksaitis, MD, Stanford University Medical Center, Palo Alto; MS Gottlieb, MD, University of California at Los Angeles; R Jung, MD, University of Southern California Medical Center, Los Angeles; J Chin, MD, State Epidemiologist, California Dept of Health Services; J Goedert, MD, National Cancer Institute, National Institute of Health; Parasitic Diseases Div, Center for Infectious Diseases, VD Control Division, Center for Prevention Services, Chronic Diseases Div, Center for Environmental Health, CDC. ::: :::paragraphs{style="editorial"} **Editorial Note:** KS is a malignant neoplasm manifested primarily by multiple vascular nodules in the skin and other organs. The disease is multifocal, with a course ranging from indolent, with only skin manifestations, to fulminant, with extensive visceral involvement [@safai1981]. Accurate incidence and mortality rates for KS are not available for the United States, but the annual incidence has been estimated between 0.02-0.06 per 100,000; it affects primarily elderly males [@oettle1962; @rothman1962]. In a series of 92 patients treated between 1949 and 1975 at the Memorial Sloan-Kettering Cancer Institute in NYC, 76% were male, and the mean age was 63 years (range 23-90 years) at the time of diagnosis [@safai1980]. The disease in elderly men is usually manifested by skin lesions and a chronic clinical course (mean survival time is 8-13 years) [@safai1981]. Two exceptions to this epidemiologic pattern have been noted previously. The first occurs in an endemic belt across equatorial Africa, where KS commonly affects children and young adults and accounts for up to 9% of all cancers [@oettle1962]. Secondly, the disease appears to have a higher incidence in renal transplant recipients [@harwood1979; @stribling1978; @myers1974; @penn1979] and in others receiving immunosuppressive therapy [@gange1978; @klepp1978; @hoshaw1980]. The occurrence of this number of KS cases during a 30-month period among young, homosexual men is considered highly unusual. No previous association between KS and sexual preference has been reported. The fulminant clinical course reported in many of these patients also differs from that classically described for elderly persons. The histopathologic diagnosis of KS may be difficult for 2 reasons. Changes in some lesions may be interpreted as nonspecific, and other cutaneous and soft tissue sarcomas, such as angiosarcoma of the skin, may be confused with KS [@girard1970; @rosai1976]. That 10 new cases of *Pneumocystis* pneumonia have been identified in homosexual men suggests that the 5 previously reported cases were not an isolated phenomenon [@cdc1981]. In addition, CDC has a report of 4 homosexual men in NYC who developed severe, progressive, perianal herpes simplex infections and had evidence of cellular immunodeficiencies. Three died, 1 with systemic CMV infection. The fourth patient is currently undergoing therapy. It is not clear if or how the clustering of KS, pneumocystis, and other serious diseases in homosexual men is related. What is known is that the patients with *Pneumocystis* pneumonia described in the previous report showed evidence of impaired cellular immunity and previous or current CMV infection [@cdc1981]. Furthermore, serologic evidence of past CMV infection and active shedding of CMV have been shown to be much more common among homosexual men than heterosexual men attending a sexually transmitted disease clinic [@drew1981]. A specific serologic association with CMV infection has been demonstrated among American and European patients with KS [@giraldo1975; @giraldo1978] and herpes-type virus particles have been demonstrated in tissue culture cell lines from African cases of KS [@giraldo1972]. It has been hypothesized that activation of oncogenic virus during periods of immunosuppression may result in the development of KS [@kapadia1977]. Although immunosuppression often results in CMV infection, it is not yet clear whether CMV infection precedes or follows the above-mentioned disorders. Although it is not certain that the increase in KS and PC pneumonia is restricted to homosexual men, the vast majority of recent cases have been reported from this group. Physicians should be alert for Kaposi’s sarcoma, PC pneumonia, and other opportunistic infections associated with immunosuppression in homosexual men. ::: ### References :::bibliography{title=""} :::references{format=bibtex} @article{safai1981, author = {Safai, B. and Good, R. A.}, title = {Kaposi's sarcoma: a review and recent developments}, journal = {CA}, year = 1981, volume = 31, pages = {1--12}} @article{oettle1962, author = {Oettle, A. G.}, title = {Geographical and racial differences in the frequency of Kaposi's sarcoma as evidence of environmental or genetic causes}, journal = {Acta Un Int Cancr}, year = 1962, volume = 18, pages = {330--363}} @article{rothman1962, author = {Rothman, S.}, title = {Remarks on sex, age, and racial distribution of Kaposi's sarcoma and on possible pathogenetic factors}, journal = {Acta Un Int Cancr}, year = 1962, volume = 18, pages = {326--329}} @article{safai1980, author = {Safai, B. and Mik\'{e}, V. and Giraldo, G. and Beth, E. and Good, R. A.}, title = {Association of Kaposi's sarcoma with second primary malignancies: possible etiopathogenic implications}, journal = {Cancer}, year = 1980, volume = 45, pages = {1472--1479}} @article{harwood1979, author = {Harwood, A. R. and Osoba, D. and Hofstader, S. L. and others}, title = {Kaposi's sarcoma in recipients of renal transplants}, journal = {Am J Med}, year = 1979, volume = 67, pages = {759--765}} @article{stribling1978, author = {Stribling, J. and Weitzner, S. and Smith, G. V.}, title = {Kaposi sarcoma in renal allograft recipients}, journal = {Cancer}, year = 1978, volume = 42, pages = {442--446}} @article{myers1974, author = {Myers, B. D. and Kessler, E. and Levi, J. and Pick, A. and Rosenfeld, J. B. and Tikvah, P.}, title = {Kaposi sarcoma in kidney transplant recipients}, journal = {Arch Intern Med}, year = 1974, volume = 133, pages = {307--311}} @article{penn1979, author = {Penn, I.}, title = {Kaposi's sarcoma in organ transplant recipients: report of 20 cases}, journal = {Transplantation}, year = 1979, volume = 27, pages = {8--11}} @article{gange1978, author = {Gange, R. W. and Jones, E. W.}, title = {Kaposi's sarcoma and immunosuppressive therapy: an appraisal}, journal = {Clin Exp Dermatol}, year = 1978, volume = 3, pages = {135--146}} @article{klepp1978, author = {Klepp, O. and Dahl, O. and Stenwig, J. T.}, title = {Association of Kaposi's sarcoma and prior immunosuppressive therapy: a 5-year material of Kaposi's sarcoma in {Norway}}, journal = {Cancer}, year = 1978, volume = 42, pages = {2626--2630}} @article{hoshaw1980, author = {Hoshaw, R. A. and Schwartz, R. A.}, title = {Kaposi's sarcoma after immunosuppressive therapy with prednisone}, journal = {Arch Dermatol}, year = 1980, volume = 116, pages = {1280--1282}} @article{girard1970, author = {Girard, C. and Johnson, W. C. and Graham, J. H.}, title = {Cutaneous angiosarcoma}, journal = {Cancer}, year = 1970, volume = 26, pages = {868--883}} @article{rosai1976, author = {Rosai, J. and Sumner, H. W. and Kostianovsky, M. and Perez-Mesa, C.}, title = {Angiosarcoma of the skin. {A} clinicopathologic and fine structural study}, journal = {Hum Pathol}, year = 1976, volume = 7, pages = {83--109}} @article{drew1981, author = {Drew, W. L. and Mintz, L. and Miner, R. C. and Sands, M. and Ketterer, B.}, title = {Prevalence of cytomegalovirus infection in homosexual men}, journal = {J Infect Dis}, year = 1981, volume = 143, pages = {188--192}} @article{giraldo1975, author = {Giraldo, G. and Beth, E. and Kourilsky, F. M. and others}, title = {Antibody patterns to herpesvirus in Kaposi's sarcoma: serologic association of {European} Kaposi's sarcoma with cytomegalovirus}, journal = {Int J Cancer}, year = 1975, volume = 15, pages = {839--848}} @article{giraldo1978, author = {Giraldo, G. and Beth, E. and Henle, W. and others}, title = {Antibody patterns to herpesvirus in Kaposi's sarcoma. {II}. {Serological} association of {American} Kaposi's sarcoma with cytomegalovirus}, journal = {Int J Cancer}, year = 1978, volume = 22, pages = {126--131}} @article{giraldo1972, author = {Giraldo, G. and Beth, E. and Haguenau, F.}, title = {Herpes-type virus particles in tissue culture of Kaposi's sarcoma from different geographic regions}, journal = {J Natl Cancer Inst}, year = 1972, volume = 49, pages = {1509--1526}} @article{kapadia1977, author = {Kapadia, S. B. and Krause, J. R.}, title = {Kaposi's sarcoma after long-term alkylating agent therapy for multiple myeloma}, journal = {South Med J}, year = 1977, volume = 70, pages = {1011--1013}} ::: # Notifiable Diseases — United States {style="back" kicker="From the issue of July 3, 1981" dateline="25th week ending June 27, 1981 · Vol. 30, No. 25 · p. 308"} :::paragraphs{style="editor"} Each weekly issue carried the counts of notifiable diseases that the states reported to CDC. The summary table of the July 3 issue is reprinted as it was printed (:ref{id="tbl-notifiable"}). ::: ::resource{id="tbl-notifiable"} :::paragraphs{style="colophon"} Surveillance Notes, Reprint No. 1. Re-set from the printed issues of June 5 and July 3, 1981 (Morbidity and Mortality Weekly Report, vol. 30, nos. 21 and 25, Centers for Disease Control, Atlanta), which are in the public domain. The text and the tables keep the wording and figures of 1981, including the terminology of the time. Figure 1 and the case table on page 2 were added by the editors. Set in IBM Plex Serif, Libre Franklin and IBM Plex Sans Condensed (SIL Open Font License). :::
`; // MMWR 1981;30(25):305–308, and its notifiable diseases const CASES = String.raw`Patient Age Pneumonia CMV evidence Other findings Course
Markdown-Beispiel · 5 Zeilen · content.cases.en.md1 33 Mar 1981 CF titer 256 (Oct 1980), 32 (May 1981); viruria Oral candidiasis; leukopenia; raised liver enzymes Died May 3 2 30 Apr 1981 Seroconversion (16 to 28); viruria Mucosal candidiasis; leukopenia Pneumonia responded; daily fever 3 30 Feb 1981 CF titer 8 (Mar 1981); esophageal biopsy positive Esophageal and oral candidiasis Pneumonia responded 4 29 Feb 1981 CMV in lung tissue at postmortem Hodgkins disease 3 years earlier, treated Died in March 5 36 Apr 1981 Clinical CMV infection (Sep 1980); retinitis; CF titer 128 Oral candidiasis; sulfa-induced neutropenia Under treatment
`; // TSV: the five case reports, compiled by the editors const COMPLAINTS = String.raw`Presenting complaint Number (percentage) of patients
Markdown-Beispiel · 6 Zeilen · content.complaints.en.mdSkin lesion(s) only 10 (50%) Skin lesions plus lymphadenopathy 4 (20%) Oral mucosal lesion only 1 (5%) Inguinal adenopathy plus perirectal abscess 1 (5%) Weight loss and fever 2 (10%) Weight loss, fever, and pneumonia (one due to *Pneumocystis carinii*) 2 (10%)
`; // TSV: Table 1 of the July 3 report const NOTIFIABLE = String.raw`Disease 25th week ending Median 1976–1980 Cumulative, first 25 weeks
Markdown-Beispiel · 29 Zeilen · content.notifiable.en.md June 27, 1981 June 21, 1980 June 27, 1981 June 21, 1980 Median 1976–1980 Aseptic meningitis 133 107 107 1,859 1,619 1,126 Brucellosis 3 5 6 73 82 82 Chickenpox 3,801 4,577 4,353 157,690 144,465 144,465 Diphtheria – – – 3 2 35 Encephalitis: Primary (arthropod-borne & unspec.) 20 8 18 360 282 287 Encephalitis: Post-infectious 2 4 4 44 98 102 Hepatitis, Viral: Type B 404 364 317 9,425 7,977 7,262 Hepatitis, Viral: Type A 430 579 595 11,981 12,945 14,023 Hepatitis, Viral: Type unspecified 185 214 178 5,367 5,296 4,253 Malaria 43 58 19 634 853 265 Measles (rubeola) 85 463 924 2,292 11,224 20,679 Meningococcal infections: Total 48 50 40 2,021 1,533 1,357 Meningococcal infections: Civilian 46 49 39 2,009 1,522 1,299 Meningococcal infections: Military 2 1 1 12 11 21 Mumps 54 158 422 2,665 6,382 11,698 Pertussis 23 26 26 482 524 524 Rubella (German measles) 30 82 362 1,443 2,756 9,753 Tetanus 4 4 1 27 29 29 Tuberculosis 505 613 689 12,863 12,672 13,778 Tularemia 8 7 4 87 70 62 Typhoid fever 7 10 8 224 171 171 Typhus fever, tick-borne (Rky. Mt. spotted) 57 39 48 436 318 299 Venereal diseases: Gonorrhea: Civilian 18,174 20,192 20,192 463,413 452,245 452,245 Gonorrhea: Military 579 368 495 13,731 12,756 12,844 Syphilis, primary & secondary: Civilian 610 488 452 14,248 12,387 11,575 Syphilis, primary & secondary: Military 6 5 5 178 151 146 Rabies in animals 162 136 73 3,479 3,250 1,509
`; // TSV: Table I of the July 3 issue const markdown = `${june}\n\n${july}`; // one document: the July report runs on // #region resources: three tables read from TSV, and the chart built from the case reports const NUMBER = /^[\d,.()% –]*$/; // a column of counts aligns right, its heading centred const table = (tsv, headerRows, columnWidths) => { const model = parseTSV(tsv, { headerRows }); const numeric = model.rows[0].map((_, c) => model.rows.slice(headerRows) .every((row) => NUMBER.test(row[c].content))); return { ...model, columnWidths, rows: model.rows.map((cells, r) => cells.map((cell, c) => (numeric[c] ? { ...cell, align: r < headerRows ? 'center' : 'right' } : cell))) }; }; // Two header rows, as the weekly printed them: "25th week ending" spans two columns. const notifiable = [[0, 0, 1, 0], [0, 1, 0, 2], [0, 3, 1, 3], [0, 4, 0, 6]] .reduce((m, [r1, c1, r2, c2]) => mergeCells(m, { start: { row: r1, col: c1 }, end: { row: r2, col: c2 } }), table(NOTIFIABLE, 2, [3.6, 1, 1, 1, 1.1, 1.1, 1.1])); const added = 'Compiled for this reprint from the case reports; not part of the 1981 report.'; const res = (id, typeId, kind, placement, more) => ({ id, typeId, kind, placement, createdAt: 0, updatedAt: 0, ...more }); const resources = [ res('fig-timeline', 'figure', 'svg', { position: 'bottom', span: 'page' }, { svg: { fileId: 'timeline.svg', width: 1780, height: 490 }, caption: 'The five patients, September 1980 to May 1981, by month. The illness before ' + 'the pneumonia is counted back from the month of diagnosis, as each report gives it.', note: `Drawn by the editors. ${added}`, altText: 'A timeline of five rows, one per patient: Pneumocystis pneumonia diagnosed ' + 'between February and April 1981, two deaths in March and May.' }), res('tbl-cases', 'table', 'table', { position: 'top', span: 'page' }, { caption: 'The five case reports at a glance.', note: added, table: { model: table(CASES, 1, [0.7, 0.45, 1, 2.2, 2.4, 1.5]) } }), res('tbl-complaints', 'table', 'table', { position: 'bottom' }, { caption: 'Presenting complaints in 20 patients with Kaposi’s sarcoma', table: { model: table(COMPLAINTS, 1, [2, 1.15]) } }), res('tbl-notifiable', 'table', 'table', { position: 'here' }, { caption: 'Summary — cases of specified notifiable diseases, United States', note: 'Cumulative totals include revised and delayed reports through previous weeks.', table: { model: notifiable, styleId: 'weekly' } }), ]; // #endregion // #region art: the timeline, drawn from the dates in the case reports // Months counted from September 1980 (0) to May 1981 (8). `ill`: the months of illness // before the pneumonia that the report gives; `pcp`: the month of diagnosis; `cmv`: a dated // CMV finding; `died`: the month of death. const PATIENTS = [ { label: 'Patient 1 · 33', ill: [4, 6], pcp: 6, cmv: [1], died: 8 }, { label: 'Patient 2 · 30', ill: [2, 7], pcp: 7, cmv: [] }, { label: 'Patient 3 · 30', ill: [4, 5], pcp: 5, cmv: [6] }, { label: 'Patient 4 · 29', pcp: 5, cmv: [], died: 6 }, { label: 'Patient 5 · 36', ill: [3, 7], pcp: 7, cmv: [0] }, ]; const MONTHS = ['Sep', 'Oct', 'Nov', 'Dec', 'Jan', 'Feb', 'Mar', 'Apr', 'May']; const r2 = (v) => +v.toFixed(2); // The chart's labels name their family on the root element: loadSvg embeds the faces they set. function timeline() { // 178 × 47 mm: the width of the page's two columns const [W, H, L, R, T, ROW] = [178, 49, 26, 2, 9.5, 6.2]; const step = (W - L - R) / MONTHS.length; const x = (m) => L + m * step; const label = (tx, ty, s, size = 2.75, anchor = 'start', weight = 400, fill = palette.ink) => `<text x="${r2(tx)}" y="${r2(ty)}" font-size="${size}" font-weight="${weight}" ` + `text-anchor="${anchor}" fill="${fill}">${s}</text>`; const cross = (cx, cy) => `<path d="M${r2(cx - 1.3)} ${r2(cy - 1.3)}l2.6 2.6M${r2(cx + 1.3)} ` + `${r2(cy - 1.3)}l-2.6 2.6" stroke="${palette.ink}" stroke-width="0.6"/>`; let out = ''; MONTHS.forEach((m, i) => { if (i % 2 === 0) out += `<rect x="${r2(x(i))}" y="${T - 1}" width="${r2(step)}" ` + `height="${PATIENTS.length * ROW + 1}" fill="${palette.tint}"/>`; out += label(x(i) + step / 2, T - 2.4, m, 2.6, 'middle', 600, palette.muted); }); out += label(x(0), T - 5.6, '1980', 2.6, 'start', 600, palette.accent) + label(x(4), T - 5.6, '1981', 2.6, 'start', 600, palette.accent); PATIENTS.forEach((p, i) => { const cy = T + i * ROW + ROW / 2; out += label(0, cy + 1, p.label, 2.9, 'start', 600); if (p.ill) out += `<rect x="${r2(x(p.ill[0]) + 0.6)}" y="${r2(cy - 1.1)}" ` + `width="${r2((p.ill[1] - p.ill[0]) * step - 1.2)}" height="2.2" rx="1.1" ` + `fill="${palette.rule}"/>`; for (const c of p.cmv) { const cx = x(c) + step / 2; out += `<path d="M${r2(cx)} ${r2(cy - 1.5)}l1.5 1.5l-1.5 1.5l-1.5-1.5Z" fill="#fff" ` + `stroke="${palette.ink}" stroke-width="0.35"/>`; } out += `<circle cx="${r2(x(p.pcp) + step / 2)}" cy="${r2(cy)}" r="1.7" ` + `fill="${palette.accent}"/>`; if (p.died !== undefined) { const cx = x(p.died) + step / 2; out += cross(cx, cy); } }); const ly = H - 2.2; out += `<rect x="${L}" y="${ly - 2}" width="8" height="2.2" rx="1.1" fill="${palette.rule}"/>` + label(L + 10, ly, 'illness before the pneumonia') + `<circle cx="${L + 52}" cy="${ly - 0.9}" r="1.7" fill="${palette.accent}"/>` + label(L + 55, ly, '<tspan font-style="italic">Pneumocystis</tspan> pneumonia diagnosed') + `<path d="M${L + 109} ${ly - 2.4}l1.5 1.5l-1.5 1.5l-1.5-1.5Z" fill="#fff" ` + `stroke="${palette.ink}" stroke-width="0.35"/>` + label(L + 112, ly, 'dated CMV finding') + cross(L + 139, ly - 0.9) + label(L + 142, ly, 'died'); return `<svg xmlns="http://www.w3.org/2000/svg" width="1780" height="490" ` + `viewBox="0 0 ${W} ${H}" font-family="${LABEL}">${out}</svg>`; } // #endregion // ─── 3 · Fonts ────────────────────────────────────────────────────────────── const FONTS = { 'IBM Plex Serif': ['400', '400i', '600', '600i'], 'Libre Franklin': ['800', '800i'], 'IBM Plex Sans Condensed': ['400', '400i', '500', '600', '600i', '700'] }; // ─── 4 · Build & show ─────────────────────────────────────────────────────── await loadSvg('timeline.svg', timeline()); const doc = await buildDocumentWithFonts({ markdown, resources }, config(), kitFonts(FONTS)); showPages(doc, { title: 'Surveillance Notes · Reprint No. 1' }); offerPdf(() => renderToPdf(doc, { fontProvider: fontsourceProvider, resourceBytes: imageBytes }), `${RECIPE}.pdf`);
Kit · core, fonts, viewer, pdf, images: in jedem Rezept gleich · 315 Zeilen// ─── Kit ── helpers shared by every Cookbook recipe · postext.dev/cookbook ───── // ─── Kit · core v1 ── the same in every recipe · postext.dev/cookbook function mm(value) { return { value, unit: 'mm' }; } function pt(value) { return { value, unit: 'pt' }; } function em(value) { return { value, unit: 'em' }; } /** The sample language's string: t({ en: 'Figure', es: 'Figura' }). */ function t(strings) { return strings[LANG] ?? Object.values(strings)[0]; } /** A file in this recipe's assets folder, served from the Postext repo by jsDelivr. */ function asset(file) { return `https://cdn.jsdelivr.net/gh/drnachio/postext@main/cookbook/${RECIPE}/assets/${file}`; } // ─── Kit · fonts v3 ── the same in every recipe · postext.dev/cookbook // Postext loads the faces a config asks for before layout (prepareFonts, // buildDocumentWithFonts) and asks the kit for the files: Fontsource's, the // files the PDF embeds too. /** The options of buildDocumentWithFonts / prepareFonts / withLoadedFonts: * the Fontsource resolver, and the faces of FONTS loaded with the ones the * config names. FONTS = { 'Family Name': ['400', '400i', '700'] }. */ function kitFonts(FONTS = {}) { const faces = Object.entries(FONTS).flatMap(([family, specs]) => specs.map((spec) => ({ family, weight: parseInt(spec, 10), style: spec.endsWith('i') ? 'italic' : 'normal' }))); return { resolve: fontsourceResolver, faces }; } /** A face's Fontsource files, in a fixed order: latin, then latin-ext and greek * when `text` needs them and the family ships them (kitSubsetsFor), each with * its unicode-range. Null for a weight or slant Fontsource does not ship. */ async function fontsourceResolver(family, weight, style, { text = '' } = {}) { const id = fontsourceId(family); const meta = await fontsourceMeta(family); if (meta && !(meta.weights.includes(weight) && meta.styles.includes(style))) return null; kitStatus('Loading fonts…'); const at = await fontsourceAt(id); return ['latin', ...kitSubsetsFor(text, meta)].map((subset) => ({ source: `${at}files/${id}-${subset}-${weight}-${style}.woff2`, unicodeRange: kitRanges()[subset], })); } /** The unicode-range of each Fontsource file the kit loads (a function: the * kit is inlined after the pen's code, which runs before a const would be set). */ function kitRanges() { return { latin: 'U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,' + 'U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD', 'latin-ext': 'U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,' + 'U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF', greek: 'U+0370-03FF', }; } /** For the cjk, arabic and comics blocks, which add their own files: the * faces of `faces` = { 'Family Name': ['400', '400i', '700'] }. `text` is the sample: * č ł † α χ also load latin-ext and greek files (kitSubsetsFor). With * `optional`, a face Fontsource does not ship is skipped instead of failing. * The files are added once all have loaded, in the order asked (latin, then * latin-ext, then greek), whatever order they arrive in: the last one added * wins a character two files hold. Resolves to the number of faces added. */ async function loadFonts(faces, text = '', { optional = false } = {}) { kitStatus('Loading fonts…'); const ranges = kitRanges(); const jobs = []; for (const [family, specs] of Object.entries(faces)) { const id = fontsourceId(family); const todo = [...new Set(specs)].map((spec) => [parseInt(spec, 10), spec.endsWith('i') ? 'italic' : 'normal']) .filter(([weight, style]) => !hasFace(family, weight, style)); // before any await const at = fontsourceAt(id); const meta = optional || /[^\0-ÿ]/u.test(text) ? await fontsourceMeta(family) : null; const subsets = ['latin', ...kitSubsetsFor(text, meta)]; for (const [weight, style] of todo) { if (optional && !(meta?.weights.includes(weight) && meta.styles.includes(style))) continue; for (const subset of subsets) { const url = `${await at}files/${id}-${subset}-${weight}-${style}.woff2`; const face = new FontFace(family, `url(${url}) format('woff2')`, { weight: String(weight), style, unicodeRange: ranges[subset] }); jobs.push(face.load().catch(() => { if (subset === 'latin' && !optional) throw new Error(`Fontsource has no ${family} ${weight} ${style}`); })); } } } const ready = await Promise.all(jobs).catch((error) => { kitFail(error); throw error; }); return ready.filter((face) => face && document.fonts.add(face)).length; } /** A loaded FontFace covers this family, weight and style (fonts.check() would * also say yes for families nobody declared). */ function hasFace(family, weight, style) { for (const face of document.fonts) { if (face.status !== 'loaded' || face.style !== style) continue; if (face.family.replace(/^["']|["']$/g, '') !== family) continue; const [low, high = low] = face.weight.split(' ').map(Number); if (weight >= low && weight <= high) return true; } return false; } /** The files beyond latin `text` needs that `meta`'s family ships. */ function kitSubsetsFor(text, meta) { return [[/[Ā-˿ᴀ-ᶿḀ-ỿ†ℓⱠ-Ɀ꜠-ꟿ]/u, 'latin-ext'], [/[Ͱ-Ͽ]/u, 'greek']] .filter(([re, x]) => re.test(text) && meta?.subsets?.includes(x)).map(([, x]) => x); } /** Fontsource's id for a family: 'Source Serif 4' → 'source-serif-4'. */ function fontsourceId(family) { return family.toLowerCase().replace(/\s+/g, '-'); } /** A package's folder at the one version @5 names now (#766). */ function fontsourceAt(id, u = `https://cdn.jsdelivr.net/npm/@fontsource/${id}@`) { return (fontsourceAt.c ??= {})[id] ??= fetch(u + '5/package.json').then((r) => r.json()) .then((p) => p.version || 5, () => 5).then((v) => `${u}${v}/`); } /** The family's Fontsource metadata (weights, styles, subsets), or null. */ function fontsourceMeta(family) { fontsourceMeta.cache ??= new Map(); const id = fontsourceId(family); if (!fontsourceMeta.cache.has(id)) { fontsourceMeta.cache.set(id, fetch(`https://api.fontsource.org/v1/fonts/${id}`) .then((res) => (res.ok ? res.json() : null), () => null)); } return fontsourceMeta.cache.get(id); } // ─── Kit · viewer v2 ── the same in every recipe · postext.dev/cookbook /** The pages as spreads on a dark desk, page 1 alone, then verso | recto, * each painted when it scrolls near. Other options go to renderPageToCanvas. */ function showPages(docs, { title, width = 460, ...render } = {}) { const root = viewer(title); const pages = [docs].flat().flatMap((doc) => doc.pages.map((page) => ({ doc, page, n: (doc.pageIndexOffset ?? 0) + page.index }))); const spreads = []; let verso = null; for (const p of pages) { if (p.n % 2 === 1) { if (verso) spreads.push([verso, null]); verso = p; } else { spreads.push([verso, p]); verso = null; } } if (verso) spreads.push([verso, null]); const density = Math.min(window.devicePixelRatio || 1, 2); showPages.painter?.disconnect(); const painter = new IntersectionObserver((entries) => { for (const { isIntersecting, target } of entries) { if (!isIntersecting) continue; painter.unobserve(target); const { doc, page } = target.postext; renderPageToCanvas(page, doc, target, { ...render, scale: (width * density) / page.width }); } }, { rootMargin: '800px' }); showPages.painter = painter; root.replaceChildren(...spreads.map((pair) => { const spread = document.createElement('div'); spread.className = 'pt-spread'; for (const p of pair) { const figure = document.createElement('figure'); if (p) { const label = p.page.pageLabel || String(p.n + 1); const canvas = document.createElement('canvas'); canvas.postext = p; canvas.style.aspectRatio = `${p.page.width} / ${p.page.height}`; canvas.setAttribute('role', 'img'); canvas.setAttribute('aria-label', `Page ${label}`); const folio = document.createElement('figcaption'); folio.textContent = label; figure.append(canvas, folio); painter.observe(canvas); } else figure.className = 'pt-blank'; spread.append(figure); } return spread; })); kitStatus(`${pages.length} ${pages.length === 1 ? 'page' : 'pages'}`); document.documentElement.dataset.postext = 'ready'; return pages.length; } /** The desk, the bar and the error reporting, created once. */ function viewer(title) { if (!document.getElementById('pt-kit')) { document.head.insertAdjacentHTML('beforeend', `<style id="pt-kit"> :root { color-scheme: dark; } body { margin: 0; background: #0e1014; color: #b9bcc4; font: 13px/1.45 system-ui, sans-serif; } #pt-bar { position: sticky; top: 0; z-index: 1; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px; padding: 10px 16px; background: rgb(14 16 20 / .92); backdrop-filter: blur(6px); border-bottom: 1px solid #23262d; } #pt-bar strong { color: #f4f1ea; font-weight: 600; } #pt-actions { display: flex; gap: 12px; margin-left: auto; } #pt-actions a, #pt-actions button { color: #d8a21a; font: inherit; background: none; border: 0; padding: 0; cursor: pointer; } #pages { display: grid; justify-items: center; gap: 48px; padding: 32px 16px 72px; } .pt-spread { display: flex; } .pt-spread figure { margin: 0; width: min(460px, 44vw); } .pt-spread canvas { display: block; width: 100%; background: #fff; box-shadow: 0 1px 2px rgb(0 0 0 / .5), 0 22px 44px -16px rgb(0 0 0 / .8); } .pt-spread figure:first-child canvas { box-shadow: inset -14px 0 14px -14px rgb(0 0 0 / .18), 0 1px 2px rgb(0 0 0 / .5), 0 22px 44px -16px rgb(0 0 0 / .8); } .pt-spread figcaption { margin-top: 10px; text-align: center; font: 600 10px/1 system-ui, sans-serif; letter-spacing: .18em; text-transform: uppercase; color: #6c7079; } .pt-blank { visibility: hidden; } @media (max-width: 760px) { .pt-spread { flex-direction: column; gap: 32px; } .pt-spread figure { width: min(460px, 92vw); } .pt-blank { display: none; } } </style>`); document.body.insertAdjacentHTML('afterbegin', '<header id="pt-bar"><strong id="pt-title"></strong><span id="pt-status" role="status"></span><span id="pt-actions"></span></header>'); document.getElementById('pt-title').textContent = document.title || 'Postext'; addEventListener('error', (event) => kitFail(event.error ?? event.message)); addEventListener('unhandledrejection', (event) => kitFail(event.reason)); } if (title) document.getElementById('pt-title').textContent = title; return document.getElementById('pages') ?? document.body.appendChild(Object.assign(document.createElement('main'), { id: 'pages' })); } function kitStatus(text) { viewer(); document.getElementById('pt-status').textContent = text; } function kitFail(error) { document.documentElement.dataset.postext = 'error'; kitStatus(`Error: ${error?.message ?? error}`); } // ─── Kit · pdf v3 ── the same in every recipe that exports a PDF /** The Fontsource files the screen used, as TrueType, with their range and * place: the nearest weight the family ships, upright with no italic; * latin, then what its letters need (kitSubsetsFor). */ async function fontsourceProvider(family, weight, style, request) { const id = fontsourceId(family); const meta = await fontsourceMeta(family); const weights = meta?.weights?.length ? meta.weights : [400, 700]; const w = weights.reduce((a, b) => (Math.abs(b - weight) < Math.abs(a - weight) ? b : a)); const s = style === 'italic' && meta && !meta.styles.includes('italic') ? 'normal' : style; const text = String.fromCodePoint(...(request?.codePoints ?? [])); const files = await Promise.all(['latin', ...kitSubsetsFor(text, meta)].map(async (subset, order) => { const res = await fetch(`${await fontsourceAt(id)}files/${id}-${subset}-${w}-${s}.woff2`); if (!res.ok) throw new Error(`Fontsource has no ${family} ${w} ${s} ${subset}`); return Object.assign(await decompressWoff2(new Uint8Array(await res.arrayBuffer())), { unicodeRange: kitRanges()[subset], order }); })); return files.length === 1 ? files[0] : files; } /** A "Build the PDF" button; then "Open the PDF" (a new tab: CodePen's frame * shows no PDFs) and a download link. */ function offerPdf(makePdf, filename) { viewer(); const button = Object.assign(document.createElement('button'), { type: 'button', textContent: 'Build the PDF' }); button.dataset.postextPdf = filename; button.addEventListener('click', async () => { button.disabled = true; button.textContent = 'Building the PDF…'; try { const bytes = await makePdf(); const url = URL.createObjectURL(new Blob([bytes], { type: 'application/pdf' })); const size = `${Math.max(1, Math.round(bytes.length / 1024))} KB`; button.replaceWith( Object.assign(document.createElement('a'), { href: url, target: '_blank', rel: 'noopener', textContent: 'Open the PDF ↗' }), Object.assign(document.createElement('a'), { href: url, download: filename, textContent: `Download ${filename} · ${size}` })); } catch (error) { button.disabled = false; button.textContent = 'Build the PDF'; kitFail(error); } }); document.getElementById('pt-actions').append(button); } // ─── Kit · images v3 ── recipes with pictures · postext.dev/cookbook /** Registers a photo or PNG for the canvas and keeps its bytes for the PDF. * fetch → ImageBitmap never taints the canvas (a plain cross-origin <img> would). */ async function loadImage(fileId, url) { const res = await fetch(url); if (!res.ok) throw new Error(`Image not found (${res.status}): ${url}`); const bytes = new Uint8Array(await res.arrayBuffer()); registerResourceImage(fileId, await createImageBitmap(new Blob([bytes]))); (loadImage.bytes ??= new Map()).set(fileId, bytes); } /** Registers SVG markup as a vector image, its fonts inside (inlineSvgFonts, ≥ 1.25). * `options` go to registerResourceImage: { singleInk: true } tints it on the canvas. */ async function loadSvg(fileId, svg, options) { if (typeof inlineSvgFonts === 'function') svg = await inlineSvgFonts(svg, svgFaces); const img = new Image(); img.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`; await img.decode(); registerResourceImage(fileId, img, options); (loadImage.bytes ??= new Map()).set(fileId, new TextEncoder().encode(svg)); } /** A face's Fontsource files: nearest weight; latin + what the SVG sets. */ async function svgFaces(family, weight, style, { codePoints = [] } = {}) { const [id, m] = [fontsourceId(family), await fontsourceMeta(family)]; const w = m?.weights.reduce((a, b) => (Math.abs(b - weight) < Math.abs(a - weight) ? b : a)) ?? weight; const s = m?.styles.includes(style) === false ? 'normal' : style; return Promise.all(['latin', ...kitSubsetsFor(String.fromCodePoint(...codePoints), m)].map(async (x) => new Uint8Array( await (await fetch(`${await fontsourceAt(id)}files/${id}-${x}-${w}-${s}.woff2`)).arrayBuffer()))); } /** renderToPdf({ resourceBytes: imageBytes }) */ function imageBytes(fileId) { return loadImage.bytes?.get(fileId); } /** renderToHtml({ resourceImageUrl: imageUrl }) */ function imageUrl(fileId) { const bytes = imageBytes(fileId); if (!bytes) return undefined; imageUrl.urls ??= new Map(); if (!imageUrl.urls.has(fileId)) { const type = /\.svg$/i.test(fileId) ? 'image/svg+xml' : /\.png$/i.test(fileId) ? 'image/png' : 'image/jpeg'; imageUrl.urls.set(fileId, URL.createObjectURL(new Blob([bytes], { type }))); } return imageUrl.urls.get(fileId); } // ─── /Kit ───────────────────────────────────────────────────────────────────────

Das zusammengesetzte script.js läuft unverändert: Fügen Sie es in das Modulskript einer beliebigen Seite ein, oder öffnen Sie das Rezept auf CodePen. Ordner des Rezepts auf GitHub ↗ (öffnet in neuem Tab)

Varianten

#Hochgestellte Literaturnummern

Die meisten medizinischen Fachzeitschriften stellen die Nummern hoch, statt sie in Klammern zu setzen.

-const citations = { style: 'american-medical-association', marker: 'parentheses',
+const citations = { style: 'american-medical-association', marker: 'superscript',

#Jeden Bericht auf einer neuen Seite beginnen

Eine Nachdruckreihe, die ihre Berichte einzeln ablegt, beginnt jeden auf einer frischen Seite.

-    { id: 'report', span: 'page', spanBreak: false, advancedDesign: opener },
+    { id: 'report', span: 'page', advancedDesign: opener },

#Die Vancouver-Liste verwenden

Ein medizinischer Fachartikel im Vancouver-Stil bearbeitet den mitgelieferten Stil elsevier-vancouver für die Literaturform der NLM.

Häufige Fehler

  • Ohne numbering: 'chapter' laufen die Literaturnummern durch das ganze Dokument, und scope: 'chapter' teilt nur die Listen: Der Juli-Bericht zitierte die Werke 4 und 6 bis 23, wo das Wochenblatt 1 bis 19 druckte.
  • Die Anmerkung von 1981 Paired specimens not run in parallel ist mit einem Sternchen markiert: footnotes.numberFormat: 'symbols' setzt *, †, ‡ und beginnt auf jeder Seite neu. Von diesen Zeichen steht nur das Sternchen in der Datei latin einer Fontsource-Schrift (das Kreuz steht in latin-ext, das Doppelkreuz in keiner der beiden), daher braucht eine Seite mit zwei oder drei Fußnoten eine Schrift, die sie hat, oder symbols: ['*', '§', '¶'].
  • Der Wortlaut von 1981 bleibt wie gedruckt, die Begriffe jener Zeit eingeschlossen, und das Impressum sagt es. Ein Nachdruck korrigiert nichts an dem Text, den er wiedergibt; was die Herausgeber hinzufügen (die Zeitleiste, die Falltabelle, die blaue kursive Zeile unter dem ersten Absatz), steht in einem eigenen Stil und ist gekennzeichnet.

Nachweise

Text
  • "Pneumocystis Pneumonia — Los Angeles", MMWR 1981;30(21):250–252, and "Kaposi's Sarcoma and Pneumocystis Pneumonia Among Homosexual Men — New York City and California", MMWR 1981;30(25):305–308, re-set in full from the printed issues; Table 1 of the first report and Figure 1 added by the editors from the case reports. "All material in the MMWR Series is in the public domain and may be used and reprinted without special permission; citation as to source, however, is appreciated." · Centers for Disease Control (CDC) · gemeinfrei
Bilder
  • Figure 1, timeline of the five cases, drawn in code from the dates in the case reports · Ignacio Ferro · eigener Text
Schriften
IBM Plex Serif (SIL OFL 1.1) · Libre Franklin (SIL OFL 1.1) · IBM Plex Sans Condensed (SIL OFL 1.1)
SandboxPDF