<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://en.battlestarwiki.org/Module:EpisodeCite/history?feed=atom</id>
	<title>Module:EpisodeCite - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://en.battlestarwiki.org/Module:EpisodeCite/history?feed=atom"/>
	<link rel="alternate" type="text/html" href="https://en.battlestarwiki.org/Module:EpisodeCite/history"/>
	<updated>2026-07-06T04:00:29Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.45.1</generator>
	<entry>
		<id>https://en.battlestarwiki.org/w/index.php?title=Module:EpisodeCite&amp;diff=263191&amp;oldid=prev</id>
		<title>Joe Beaudoin Jr. at 00:51, 6 July 2026</title>
		<link rel="alternate" type="text/html" href="https://en.battlestarwiki.org/w/index.php?title=Module:EpisodeCite&amp;diff=263191&amp;oldid=prev"/>
		<updated>2026-07-06T00:51:12Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 00:51, 6 July 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l212&quot;&gt;Line 212:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 212:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;-- multi-series auto-detected call.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;-- multi-series auto-detected call.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;--&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;--&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;-- Returns: body wikitext (&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;already &lt;/del&gt;prose- &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;or parenthetical-&lt;/del&gt;wrapped&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;)&lt;/del&gt;,&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;-- wrap (default true): whether to wrap the parenthetical (non-prose) form&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;-- a list of category names (unresolved to [[Category:]] syntax yet), and&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;-- in its own &amp;lt;span class=&quot;source-citation&quot;&amp;gt;&amp;lt;sup&amp;gt;(...)&amp;lt;/sup&amp;gt;&amp;lt;/span&amp;gt;. Pass&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;-- &lt;/del&gt;whether any title in this group failed the known-episode check.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;-- false when this group is one of SEVERAL being merged into one shared&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;local function renderGroup(entries, cfg, seriesKey, prose)&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;-- wrapper by the caller (see buildCitation&#039;s multi-series path) — without&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;-- this, a call citing an OS episode and a CAP episode together rendered&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;-- as two separate adjacent parenthetical groups, e.g.&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;-- &quot;(1980: &quot;X&quot;) (CAP: &quot;Y&quot;)&quot;, which reads as cluttered, disconnected&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;-- citations rather than one combined one. wrap=false returns just the&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;-- inner &quot;ABBR:&amp;amp;nbsp;body&quot; content with no span/sup/parens, so several&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;-- groups can be joined with &quot;; &quot; inside ONE shared wrapper instead:&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;-- &quot;(1980: &quot;X&quot;; CAP: &quot;Y&quot;)&quot;. Prose form is unaffected either way — it never&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;-- had its own wrapper to begin with.&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;--&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;-- Returns: body wikitext (prose-&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;prefixed, fully &lt;/ins&gt;wrapped, &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;or bare core&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;-- &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;content per the above), &lt;/ins&gt;a list of category names (unresolved to&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;-- &lt;/ins&gt;[[Category:]] syntax yet), and whether any title in this group failed&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;-- &lt;/ins&gt;the known-episode check.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;local function renderGroup(entries, cfg, seriesKey, prose&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;, wrap&lt;/ins&gt;)&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;	if wrap == nil then wrap = true end&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	local parts, categories, unknown = {}, {}, false&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	local parts, categories, unknown = {}, {}, false&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	for _, entry in ipairs(entries) do&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	for _, entry in ipairs(entries) do&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l237&quot;&gt;Line 237:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 252:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	if prose then&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	if prose then&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		out = cfg.prosePrefix .. body&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		out = cfg.prosePrefix .. body&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;else&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;elseif wrap then&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		out = &amp;#039;&amp;lt;span class=&amp;quot;source-citation&amp;quot;&amp;gt;&amp;lt;sup&amp;gt;(&amp;#039;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		out = &amp;#039;&amp;lt;span class=&amp;quot;source-citation&amp;quot;&amp;gt;&amp;lt;sup&amp;gt;(&amp;#039;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;			.. cfg.abbrLink .. &amp;#039;:&amp;amp;nbsp;&amp;#039; .. body .. &amp;#039;)&amp;lt;/sup&amp;gt;&amp;lt;/span&amp;gt;&amp;#039;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;			.. cfg.abbrLink .. &amp;#039;:&amp;amp;nbsp;&amp;#039; .. body .. &amp;#039;)&amp;lt;/sup&amp;gt;&amp;lt;/span&amp;gt;&amp;#039;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;	else&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;		out = cfg.abbrLink .. &#039;:&amp;amp;nbsp;&#039; .. body&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	end&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	end&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l250&quot;&gt;Line 250:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 267:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;-- which series&amp;#039; rules would apply — so titles render as plain quoted&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;-- which series&amp;#039; rules would apply — so titles render as plain quoted&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;-- links using the typed text verbatim for both target and display.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;-- links using the typed text verbatim for both target and display.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;local function renderFallbackGroup(entries, label, prose)&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;-- wrap works the same way as in renderGroup — see its comment.&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;local function renderFallbackGroup(entries, label, prose&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;, wrap&lt;/ins&gt;)&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;	if wrap == nil then wrap = true end&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	local parts = {}&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	local parts = {}&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	for _, entry in ipairs(entries) do&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	for _, entry in ipairs(entries) do&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l256&quot;&gt;Line 256:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 275:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	end&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	end&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	local body = table.concat(parts, &amp;#039;,&amp;amp;nbsp;&amp;#039;)&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	local body = table.concat(parts, &amp;#039;,&amp;amp;nbsp;&amp;#039;)&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	if prose then&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	if prose &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;or not wrap &lt;/ins&gt;then&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		return label .. &amp;#039;:&amp;amp;nbsp;&amp;#039; .. body&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		return label .. &amp;#039;:&amp;amp;nbsp;&amp;#039; .. body&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	end&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	end&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l366&quot;&gt;Line 366:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 385:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	end&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	end&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	table.sort(bucketOrder, function(a, b) return rank[a] &amp;lt; rank[b] end)&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	table.sort(bucketOrder, function(a, b) return rank[a] &amp;lt; rank[b] end)&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;	local totalGroups = #bucketOrder&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;		+ (#ambiguousBucket &amp;gt; 0 and 1 or 0)&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;		+ (#unknownBucket &amp;gt; 0 and 1 or 0)&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;	-- A single detected group (the common case: {{Ep|33}} or a call whose&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;	-- titles all happen to be the same series) renders EXACTLY as the&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;	-- explicit-series path would — wrapped, no merging logic involved.&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;	-- Merging only kicks in for a genuine multi-series call, where it&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;	-- replaces what used to be several adjacent, separately-wrapped&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;	-- parenthetical spans — e.g. &quot;(1980: &quot;X&quot;) (CAP: &quot;Y&quot;)&quot; — with one&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;	-- shared wrapper: &quot;(1980: &quot;X&quot;; CAP: &quot;Y&quot;)&quot;.&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;	local wrapPerGroup = (totalGroups &amp;lt;= 1)&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	local outputs, allCategories, anyUnknownEpisode = {}, {}, false&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	local outputs, allCategories, anyUnknownEpisode = {}, {}, false&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	for _, seriesK in ipairs(bucketOrder) do&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	for _, seriesK in ipairs(bucketOrder) do&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		local out, cats, unknown = renderGroup(buckets[seriesK], data.series[seriesK], seriesK, prose)&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		local out, cats, unknown = renderGroup(&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;			&lt;/ins&gt;buckets[seriesK], data.series[seriesK], seriesK, prose&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;, wrapPerGroup&lt;/ins&gt;)&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		outputs[#outputs + 1] = out&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		outputs[#outputs + 1] = out&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		if not suppressCats then&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		if not suppressCats then&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l381&quot;&gt;Line 381:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 414:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	if #ambiguousBucket &amp;gt; 0 then&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	if #ambiguousBucket &amp;gt; 0 then&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		outputs[#outputs + 1] = renderFallbackGroup(ambiguousBucket, &#039;ambiguous series&#039;, prose)&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		outputs[#outputs + 1] = renderFallbackGroup(ambiguousBucket, &#039;ambiguous series&#039;, prose&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;, wrapPerGroup&lt;/ins&gt;)&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		trackingCats[#trackingCats + 1] = data.ambiguousSeriesCategory&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		trackingCats[#trackingCats + 1] = data.ambiguousSeriesCategory&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	end&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	end&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	if #unknownBucket &amp;gt; 0 then&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	if #unknownBucket &amp;gt; 0 then&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		outputs[#outputs + 1] = renderFallbackGroup(unknownBucket, &#039;unresolved series&#039;, prose)&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		outputs[#outputs + 1] = renderFallbackGroup(unknownBucket, &#039;unresolved series&#039;, prose&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;, wrapPerGroup&lt;/ins&gt;)&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		trackingCats[#trackingCats + 1] = data.unresolvedSeriesCategory&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		trackingCats[#trackingCats + 1] = data.unresolvedSeriesCategory&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	end&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	end&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l392&quot;&gt;Line 392:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 425:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	end&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	end&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	local &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;joiner &lt;/del&gt;= &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;prose and &lt;/del&gt;&#039;;&amp;amp;nbsp;&#039; or &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&#039; &#039;&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	local &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;joined &lt;/ins&gt;= &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;table.concat(outputs, &lt;/ins&gt;&#039;;&amp;amp;nbsp;&#039;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;)&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	return &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;table.concat&lt;/del&gt;(&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;outputs&lt;/del&gt;, &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;joiner&lt;/del&gt;), formatCats(allCategories, trackingCats)&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;	-- Single group: outputs[1] is already fully formed (prose-prefixed &lt;/ins&gt;or&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;-- fully wrapped, per wrapPerGroup above) — pass it through unchanged.&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;	-- Multiple groups in non-prose mode: outputs are bare &quot;ABBR: body&quot;&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;	-- fragments (wrapPerGroup was false), now joined with &quot;; &quot; and wrapped&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;	-- ONCE, e.g. &quot;(1980: &quot;X&quot;; CAP: &quot;Y&quot;)&quot; instead of two separate&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;	-- adjacent parenthetical spans. Prose mode never wraps either way.&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;	if totalGroups &amp;lt;= 1 or prose then&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;		&lt;/ins&gt;return &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;joined, formatCats&lt;/ins&gt;(&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;allCategories&lt;/ins&gt;, &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;trackingCats&lt;/ins&gt;)&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;	end&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;	return &#039;&amp;lt;span class=&quot;source-citation&quot;&amp;gt;&amp;lt;sup&amp;gt;(&#039; .. joined .. &#039;)&amp;lt;/sup&amp;gt;&amp;lt;/span&amp;gt;&#039;&lt;/ins&gt;,&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;		&lt;/ins&gt;formatCats(allCategories, trackingCats)&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;end&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;end&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;

&lt;!-- diff cache key bsgwiki_db:diff:1.41:old-263180:rev-263191:php=table --&gt;
&lt;/table&gt;</summary>
		<author><name>Joe Beaudoin Jr.</name></author>
	</entry>
	<entry>
		<id>https://en.battlestarwiki.org/w/index.php?title=Module:EpisodeCite&amp;diff=263180&amp;oldid=prev</id>
		<title>Joe Beaudoin Jr.: Protected &quot;Module:EpisodeCite&quot;: Sensitive Page ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite))</title>
		<link rel="alternate" type="text/html" href="https://en.battlestarwiki.org/w/index.php?title=Module:EpisodeCite&amp;diff=263180&amp;oldid=prev"/>
		<updated>2026-07-06T00:18:05Z</updated>

		<summary type="html">&lt;p&gt;Protected &amp;quot;&lt;a href=&quot;/Module:EpisodeCite&quot; title=&quot;Module:EpisodeCite&quot;&gt;Module:EpisodeCite&lt;/a&gt;&amp;quot;: Sensitive Page ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite))&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 00:18, 6 July 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;4&quot; class=&quot;diff-notice&quot; lang=&quot;en&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(No difference)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;!-- diff cache key bsgwiki_db:diff:1.41:old-263175:rev-263180 --&gt;
&lt;/table&gt;</summary>
		<author><name>Joe Beaudoin Jr.</name></author>
	</entry>
	<entry>
		<id>https://en.battlestarwiki.org/w/index.php?title=Module:EpisodeCite&amp;diff=263175&amp;oldid=prev</id>
		<title>Joe Beaudoin Jr.: Created page with &quot;-------------------------------------------------------------------------------- -- Module:EpisodeCite -- -- Unified inline episode-citation renderer for Battlestar Wiki, replacing -- the wikitext template family: -- --   {{CAP}}, {{TRS}}, {{OS}}, {{G80}}, {{RDMep}}   → p.cite --   {{TRS video}}, {{TOS video}}                   → p.video --   {{Diswitch}}                                   → p.resolve (+ internal) -- -- The wrapper templates become one-liners, e.g....&quot;</title>
		<link rel="alternate" type="text/html" href="https://en.battlestarwiki.org/w/index.php?title=Module:EpisodeCite&amp;diff=263175&amp;oldid=prev"/>
		<updated>2026-07-05T23:59:03Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;-------------------------------------------------------------------------------- -- Module:EpisodeCite -- -- Unified inline episode-citation renderer for Battlestar Wiki, replacing -- the wikitext template family: -- --   {{CAP}}, {{TRS}}, {{OS}}, {{G80}}, {{RDMep}}   → p.cite --   {{TRS video}}, {{TOS video}}                   → p.video --   {{Diswitch}}                                   → p.resolve (+ internal) -- -- The wrapper templates become one-liners, e.g....&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;--------------------------------------------------------------------------------&lt;br /&gt;
-- Module:EpisodeCite&lt;br /&gt;
--&lt;br /&gt;
-- Unified inline episode-citation renderer for Battlestar Wiki, replacing&lt;br /&gt;
-- the wikitext template family:&lt;br /&gt;
--&lt;br /&gt;
--   {{CAP}}, {{TRS}}, {{OS}}, {{G80}}, {{RDMep}}   → p.cite&lt;br /&gt;
--   {{TRS video}}, {{TOS video}}                   → p.video&lt;br /&gt;
--   {{Diswitch}}                                   → p.resolve (+ internal)&lt;br /&gt;
--&lt;br /&gt;
-- The wrapper templates become one-liners, e.g. Template:TRS:&lt;br /&gt;
--&lt;br /&gt;
--   &amp;lt;includeonly&amp;gt;{{#invoke:EpisodeCite|cite|series=TRS}}&amp;lt;/includeonly&amp;gt;&lt;br /&gt;
--&lt;br /&gt;
-- All user-supplied parameters ({{{1}}}..{{{n}}}, del1..deln, prose, nocat)&lt;br /&gt;
-- pass through the parent frame automatically. Output is byte-compatible&lt;br /&gt;
-- with the templates it replaces, with two deliberate improvements:&lt;br /&gt;
--&lt;br /&gt;
--   1. No hard cap on the number of cited episodes (the old templates&lt;br /&gt;
--      documented 8; #fornumargs actually handled more, and so does this).&lt;br /&gt;
--   2. Cited titles are validated against the locked episode lists in&lt;br /&gt;
--      Module:EpisodeCite/data; unrecognized titles add the page to a&lt;br /&gt;
--      tracking category so typos surface instead of silently redlinking.&lt;br /&gt;
--&lt;br /&gt;
-- Targets Scribunto (Lua 5.1). MW 1.42+.&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local data = mw.loadData(&amp;#039;Module:EpisodeCite/data&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- Helpers&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
-- MediaWiki truthiness for template parameters: present and non-blank.&lt;br /&gt;
local function isYes(v)&lt;br /&gt;
	return v ~= nil and mw.text.trim(v) ~= &amp;#039;&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Resolve a typed episode title to its actual article title.&lt;br /&gt;
-- Faithful port of Template:Diswitch: the TOS map for series=TOS,&lt;br /&gt;
-- the shared default map for everything else; fall through unchanged.&lt;br /&gt;
local function resolveTitle(title, diswitchKey)&lt;br /&gt;
	local map = data.diswitch[diswitchKey]&lt;br /&gt;
	if map and map[title] then&lt;br /&gt;
		return map[title]&lt;br /&gt;
	end&lt;br /&gt;
	return title&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Display text for an episode link. Faithful port of Template:0 —&lt;br /&gt;
-- truncates the *typed* title at its first &amp;#039;(&amp;#039; (whether or not preceded&lt;br /&gt;
-- by a space, matching the original #explode), drops any whitespace&lt;br /&gt;
-- before it, and joins the remaining words with non-breaking spaces so&lt;br /&gt;
-- the quoted title never wraps mid-name:&lt;br /&gt;
--   &amp;#039;Pegasus (episode)&amp;#039;  → &amp;#039;Pegasus&amp;#039;&lt;br /&gt;
--   &amp;#039;Act of Contrition&amp;#039;  → &amp;#039;Act&amp;amp;nbsp;of&amp;amp;nbsp;Contrition&amp;#039;&lt;br /&gt;
local function displayTitle(title)&lt;br /&gt;
	local stripped = title:gsub(&amp;#039;%s*%(.*$&amp;#039;, &amp;#039;&amp;#039;)&lt;br /&gt;
	return (stripped:gsub(&amp;#039; &amp;#039;, &amp;#039;&amp;amp;nbsp;&amp;#039;))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- One quoted, linked episode citation, plus its optional deleted-scene link.&lt;br /&gt;
local function renderEpisode(title, cfg, deleted)&lt;br /&gt;
	local article = resolveTitle(title, cfg.diswitchKey)&lt;br /&gt;
	local display = displayTitle(title)&lt;br /&gt;
&lt;br /&gt;
	local link&lt;br /&gt;
	if article == display then&lt;br /&gt;
		link = string.format(&amp;#039;&amp;quot;[[%s]]&amp;quot;&amp;#039;, article)&lt;br /&gt;
	else&lt;br /&gt;
		link = string.format(&amp;#039;&amp;quot;[[%s|%s]]&amp;quot;&amp;#039;, article, display)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if deleted then&lt;br /&gt;
		local target&lt;br /&gt;
		if cfg.delLink == &amp;#039;caprica-list&amp;#039; then&lt;br /&gt;
			target = &amp;#039;List of Deleted Scenes (Caprica)#&amp;#039; .. title&lt;br /&gt;
		elseif cfg.delLink == &amp;#039;subpage-raw&amp;#039; then&lt;br /&gt;
			target = title .. &amp;#039;/Deleted Scenes&amp;#039;&lt;br /&gt;
		else -- &amp;#039;subpage&amp;#039;&lt;br /&gt;
			target = article .. &amp;#039;/Deleted scenes&amp;#039;&lt;br /&gt;
		end&lt;br /&gt;
		link = link .. &amp;#039;&amp;amp;nbsp;[[&amp;#039; .. target .. &amp;#039;|deleted scene]]&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return link, article&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Join rendered citations. serialAnd=true reproduces the TRS/CAP/RDMep&lt;br /&gt;
-- pattern (&amp;quot;A&amp;quot; and &amp;quot;B&amp;quot; / &amp;quot;A&amp;quot;, &amp;quot;B&amp;quot; and &amp;quot;C&amp;quot;); false reproduces OS/G80&lt;br /&gt;
-- (plain commas throughout).&lt;br /&gt;
local function joinCitations(parts, serialAnd)&lt;br /&gt;
	local n = #parts&lt;br /&gt;
	if n == 1 then&lt;br /&gt;
		return parts[1]&lt;br /&gt;
	end&lt;br /&gt;
	if not serialAnd then&lt;br /&gt;
		return table.concat(parts, &amp;#039;,&amp;amp;nbsp;&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
	if n == 2 then&lt;br /&gt;
		return parts[1] .. &amp;#039;&amp;amp;nbsp;and&amp;amp;nbsp;&amp;#039; .. parts[2]&lt;br /&gt;
	end&lt;br /&gt;
	return table.concat(parts, &amp;#039;,&amp;amp;nbsp;&amp;#039;, 1, n - 1)&lt;br /&gt;
		.. &amp;#039;&amp;amp;nbsp;and&amp;amp;nbsp;&amp;#039;&lt;br /&gt;
		.. parts[n]&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Membership test against the locked episode lists (resolved titles).&lt;br /&gt;
-- Built lazily per series and memoized outside the mw.loadData table.&lt;br /&gt;
local knownCache = {}&lt;br /&gt;
local function isKnownEpisode(article, seriesKey)&lt;br /&gt;
	local set = knownCache[seriesKey]&lt;br /&gt;
	if not set then&lt;br /&gt;
		set = {}&lt;br /&gt;
		local sources = data.episodeUnion[seriesKey] or { seriesKey }&lt;br /&gt;
		for _, src in ipairs(sources) do&lt;br /&gt;
			for _, ep in ipairs(data.episodes[src] or {}) do&lt;br /&gt;
				set[ep] = true&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		knownCache[seriesKey] = set&lt;br /&gt;
	end&lt;br /&gt;
	return set[article]&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- Reverse index: episode title (as typed OR as resolved) → owning series.&lt;br /&gt;
--&lt;br /&gt;
-- Built once per page parse (memoized in a module-local, since the source&lt;br /&gt;
-- table from mw.loadData is read-only and must stay pure data). Powers&lt;br /&gt;
-- series auto-detection for the new series-less universal template —&lt;br /&gt;
-- editors no longer need to know or choose which of CAP/TRS/OS/G80 an&lt;br /&gt;
-- episode belongs to.&lt;br /&gt;
--&lt;br /&gt;
-- Each series in data.seriesOrder contributes both its resolved article&lt;br /&gt;
-- titles AND its diswitch keys (the short/typed forms editors actually&lt;br /&gt;
-- use, e.g. &amp;quot;Pilot&amp;quot;, &amp;quot;Home&amp;quot;, &amp;quot;The Super Scouts&amp;quot;), so lookups succeed on&lt;br /&gt;
-- either form. RDMep is excluded: it&amp;#039;s a citation FORMAT (a fixed CAP+TRS&lt;br /&gt;
-- combination), not a franchise series, and is never an auto-detection&lt;br /&gt;
-- target — it stays an explicit, opt-in choice.&lt;br /&gt;
--&lt;br /&gt;
-- A title claimed by more than one series is recorded as AMBIGUOUS&lt;br /&gt;
-- (value `true`) rather than a series key, so callers can detect the&lt;br /&gt;
-- collision instead of silently picking one. None exist in the current&lt;br /&gt;
-- locked data — this is future-proofing against any correction that&lt;br /&gt;
-- introduces one.&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
local reverseIndexCache&lt;br /&gt;
local function buildReverseIndex()&lt;br /&gt;
	if reverseIndexCache then&lt;br /&gt;
		return reverseIndexCache&lt;br /&gt;
	end&lt;br /&gt;
	local index = {}&lt;br /&gt;
	local function claim(title, seriesKey)&lt;br /&gt;
		local existing = index[title]&lt;br /&gt;
		if existing == nil then&lt;br /&gt;
			index[title] = seriesKey&lt;br /&gt;
		elseif existing ~= seriesKey then&lt;br /&gt;
			index[title] = true -- ambiguous marker&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Pass 1: every locked article title belongs to its series.&lt;br /&gt;
	for _, seriesKey in ipairs(data.seriesOrder) do&lt;br /&gt;
		for _, article in ipairs(data.episodes[seriesKey] or {}) do&lt;br /&gt;
			claim(article, seriesKey)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Pass 2: typed short forms (diswitch keys). Ownership CANNOT be&lt;br /&gt;
	-- &amp;quot;every series sharing the map&amp;quot; — the default map is shared by&lt;br /&gt;
	-- G80/CAP/TRS/BC, which would make every short form ambiguous.&lt;br /&gt;
	-- Instead, a typed form belongs to whichever series&amp;#039; episode list&lt;br /&gt;
	-- contains the article it RESOLVES to. Where different maps resolve&lt;br /&gt;
	-- the same typed form into different series (e.g. &amp;quot;The Hand of God&amp;quot;&lt;br /&gt;
	-- → TOS article via the TOS map, RDM article via the default map),&lt;br /&gt;
	-- it is claimed by both and correctly lands on the ambiguous marker:&lt;br /&gt;
	-- that short form genuinely cannot be auto-detected and the editor&lt;br /&gt;
	-- must use an explicit-series template for it.&lt;br /&gt;
	for _, map in pairs(data.diswitch) do&lt;br /&gt;
		for typed, resolved in pairs(map) do&lt;br /&gt;
			local owner = index[resolved]&lt;br /&gt;
			if type(owner) == &amp;#039;string&amp;#039; then&lt;br /&gt;
				claim(typed, owner)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	reverseIndexCache = index&lt;br /&gt;
	return index&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Returns seriesKey, &amp;quot;AMBIGUOUS&amp;quot;, or nil (unrecognized) for a typed title.&lt;br /&gt;
local function detectSeries(title)&lt;br /&gt;
	local result = buildReverseIndex()[title]&lt;br /&gt;
	if result == true then&lt;br /&gt;
		return nil, true -- ambiguous&lt;br /&gt;
	end&lt;br /&gt;
	return result, false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- Core renderer, shared by p.cite and p.video&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
-- Render one series&amp;#039; worth of episode entries (all belonging to the same&lt;br /&gt;
-- cfg) into a citation body. This is the part of the original single-&lt;br /&gt;
-- template logic that stays identical whether it&amp;#039;s handling ALL of a&lt;br /&gt;
-- call&amp;#039;s titles (explicit series= given) or just one bucket of a&lt;br /&gt;
-- multi-series auto-detected call.&lt;br /&gt;
--&lt;br /&gt;
-- Returns: body wikitext (already prose- or parenthetical-wrapped),&lt;br /&gt;
-- a list of category names (unresolved to [[Category:]] syntax yet), and&lt;br /&gt;
-- whether any title in this group failed the known-episode check.&lt;br /&gt;
local function renderGroup(entries, cfg, seriesKey, prose)&lt;br /&gt;
	local parts, categories, unknown = {}, {}, false&lt;br /&gt;
	for _, entry in ipairs(entries) do&lt;br /&gt;
		local deleted = entry.deleted&lt;br /&gt;
		local link, article = renderEpisode(entry.value, cfg, deleted)&lt;br /&gt;
		parts[#parts + 1] = link&lt;br /&gt;
&lt;br /&gt;
		if cfg.categoryKey == &amp;#039;resolved&amp;#039; then&lt;br /&gt;
			categories[#categories + 1] = article&lt;br /&gt;
		else&lt;br /&gt;
			categories[#categories + 1] = entry.value&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		if not isKnownEpisode(article, seriesKey) then&lt;br /&gt;
			unknown = true&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local body = joinCitations(parts, cfg.serialAnd)&lt;br /&gt;
	local out&lt;br /&gt;
	if prose then&lt;br /&gt;
		out = cfg.prosePrefix .. body&lt;br /&gt;
	else&lt;br /&gt;
		out = &amp;#039;&amp;lt;span class=&amp;quot;source-citation&amp;quot;&amp;gt;&amp;lt;sup&amp;gt;(&amp;#039;&lt;br /&gt;
			.. cfg.abbrLink .. &amp;#039;:&amp;amp;nbsp;&amp;#039; .. body .. &amp;#039;)&amp;lt;/sup&amp;gt;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return out, categories, unknown&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Fallback rendering for a bucket of titles whose series couldn&amp;#039;t be&lt;br /&gt;
-- determined (unrecognized) or was ambiguous (matched &amp;gt;1 series). No&lt;br /&gt;
-- diswitch/article resolution is attempted — there&amp;#039;s no way to know&lt;br /&gt;
-- which series&amp;#039; rules would apply — so titles render as plain quoted&lt;br /&gt;
-- links using the typed text verbatim for both target and display.&lt;br /&gt;
local function renderFallbackGroup(entries, label, prose)&lt;br /&gt;
	local parts = {}&lt;br /&gt;
	for _, entry in ipairs(entries) do&lt;br /&gt;
		parts[#parts + 1] = string.format(&amp;#039;&amp;quot;[[%s]]&amp;quot;&amp;#039;, entry.value)&lt;br /&gt;
	end&lt;br /&gt;
	local body = table.concat(parts, &amp;#039;,&amp;amp;nbsp;&amp;#039;)&lt;br /&gt;
	if prose then&lt;br /&gt;
		return label .. &amp;#039;:&amp;amp;nbsp;&amp;#039; .. body&lt;br /&gt;
	end&lt;br /&gt;
	return &amp;#039;&amp;lt;span class=&amp;quot;source-citation&amp;quot;&amp;gt;&amp;lt;sup&amp;gt;(&amp;#039; .. label .. &amp;#039;:&amp;amp;nbsp;&amp;#039; .. body .. &amp;#039;)&amp;lt;/sup&amp;gt;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function isInMainspace()&lt;br /&gt;
	return mw.title and mw.title.getCurrentTitle&lt;br /&gt;
		and mw.title.getCurrentTitle().namespace == 0&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Assemble [[Category:...]] wikitext from episode categories plus any&lt;br /&gt;
-- tracking categories. Tracking categories are appended even when&lt;br /&gt;
-- nocat=y — nocat suppresses content categorization, not maintenance&lt;br /&gt;
-- visibility.&lt;br /&gt;
local function formatCats(categories, trackingCats)&lt;br /&gt;
	local out = {}&lt;br /&gt;
	for _, c in ipairs(categories) do&lt;br /&gt;
		out[#out + 1] = string.format(&amp;#039;[[Category:%s]]&amp;#039;, c)&lt;br /&gt;
	end&lt;br /&gt;
	for _, c in ipairs(trackingCats) do&lt;br /&gt;
		out[#out + 1] = string.format(&amp;#039;[[Category:%s]]&amp;#039;, c)&lt;br /&gt;
	end&lt;br /&gt;
	return table.concat(out)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function buildCitation(args, seriesKey)&lt;br /&gt;
	-- Collect positional args (episode titles) plus each one&amp;#039;s del-flag.&lt;br /&gt;
	-- #fornumargs in the old templates iterated every supplied numeric&lt;br /&gt;
	-- parameter, including non-contiguous ones ({{TRS|33|3=Water}} cites&lt;br /&gt;
	-- both) — so collect all integer keys via pairs() and sort, rather&lt;br /&gt;
	-- than counting up from 1 and stopping at the first gap. pairs() is&lt;br /&gt;
	-- required here: Scribunto&amp;#039;s frame.args is a lazy metatable-backed&lt;br /&gt;
	-- table, and pairs() is the only reliable way to enumerate it.&lt;br /&gt;
	local indices = {}&lt;br /&gt;
	for k in pairs(args) do&lt;br /&gt;
		if type(k) == &amp;#039;number&amp;#039; and k &amp;gt;= 1 and math.floor(k) == k then&lt;br /&gt;
			indices[#indices + 1] = k&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	table.sort(indices)&lt;br /&gt;
&lt;br /&gt;
	local titles = {}&lt;br /&gt;
	for _, idx in ipairs(indices) do&lt;br /&gt;
		local t = mw.text.trim(args[idx])&lt;br /&gt;
		if t ~= &amp;#039;&amp;#039; then&lt;br /&gt;
			titles[#titles + 1] = {&lt;br /&gt;
				value = t,&lt;br /&gt;
				index = idx,&lt;br /&gt;
				deleted = isYes(args[&amp;#039;del&amp;#039; .. idx]),&lt;br /&gt;
			}&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if #titles == 0 then&lt;br /&gt;
		return nil, nil -- nothing to cite; caller decides how to fail&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local prose = isYes(args.prose)&lt;br /&gt;
	local suppressCats = isYes(args.nocat)&lt;br /&gt;
	local trackingCats = {}&lt;br /&gt;
&lt;br /&gt;
	------------------------------------------------------------------------&lt;br /&gt;
	-- Explicit series (existing wrapper templates: CAP/TRS/OS/G80/RDMep).&lt;br /&gt;
	-- Unchanged behavior: every title renders under the one given series,&lt;br /&gt;
	-- with no auto-detection or grouping.&lt;br /&gt;
	------------------------------------------------------------------------&lt;br /&gt;
	if seriesKey and mw.text.trim(seriesKey) ~= &amp;#039;&amp;#039; then&lt;br /&gt;
		local cfg = data.series[seriesKey]&lt;br /&gt;
		if not cfg then&lt;br /&gt;
			error(string.format(&lt;br /&gt;
				&amp;#039;EpisodeCite: unknown series %q (expected one of CAP, TRS, OS, G80, RDMep, BC)&amp;#039;,&lt;br /&gt;
				tostring(seriesKey)), 0)&lt;br /&gt;
		end&lt;br /&gt;
		local out, categories, unknown = renderGroup(titles, cfg, seriesKey, prose)&lt;br /&gt;
		if unknown and isInMainspace() then&lt;br /&gt;
			trackingCats[#trackingCats + 1] = data.unknownEpisodeCategory&lt;br /&gt;
		end&lt;br /&gt;
		return out, formatCats(suppressCats and {} or categories, trackingCats)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	------------------------------------------------------------------------&lt;br /&gt;
	-- Auto-detect (the new series-less universal template): bucket each&lt;br /&gt;
	-- title by its detected series, order buckets per data.seriesOrder,&lt;br /&gt;
	-- render each bucket independently, then concatenate.&lt;br /&gt;
	------------------------------------------------------------------------&lt;br /&gt;
	local buckets, bucketOrder = {}, {}&lt;br /&gt;
	local ambiguousBucket, unknownBucket = {}, {}&lt;br /&gt;
&lt;br /&gt;
	for _, entry in ipairs(titles) do&lt;br /&gt;
		local detected, ambiguous = detectSeries(entry.value)&lt;br /&gt;
		if ambiguous then&lt;br /&gt;
			ambiguousBucket[#ambiguousBucket + 1] = entry&lt;br /&gt;
		elseif detected then&lt;br /&gt;
			if not buckets[detected] then&lt;br /&gt;
				buckets[detected] = {}&lt;br /&gt;
				bucketOrder[#bucketOrder + 1] = detected&lt;br /&gt;
			end&lt;br /&gt;
			table.insert(buckets[detected], entry)&lt;br /&gt;
		else&lt;br /&gt;
			unknownBucket[#unknownBucket + 1] = entry&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Sort known buckets by canonical franchise order.&lt;br /&gt;
	local rank = {}&lt;br /&gt;
	for i, key in ipairs(data.seriesOrder) do&lt;br /&gt;
		rank[key] = i&lt;br /&gt;
	end&lt;br /&gt;
	table.sort(bucketOrder, function(a, b) return rank[a] &amp;lt; rank[b] end)&lt;br /&gt;
&lt;br /&gt;
	local outputs, allCategories, anyUnknownEpisode = {}, {}, false&lt;br /&gt;
&lt;br /&gt;
	for _, seriesK in ipairs(bucketOrder) do&lt;br /&gt;
		local out, cats, unknown = renderGroup(buckets[seriesK], data.series[seriesK], seriesK, prose)&lt;br /&gt;
		outputs[#outputs + 1] = out&lt;br /&gt;
		if not suppressCats then&lt;br /&gt;
			for _, c in ipairs(cats) do&lt;br /&gt;
				allCategories[#allCategories + 1] = c&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if unknown then anyUnknownEpisode = true end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if #ambiguousBucket &amp;gt; 0 then&lt;br /&gt;
		outputs[#outputs + 1] = renderFallbackGroup(ambiguousBucket, &amp;#039;ambiguous series&amp;#039;, prose)&lt;br /&gt;
		trackingCats[#trackingCats + 1] = data.ambiguousSeriesCategory&lt;br /&gt;
	end&lt;br /&gt;
	if #unknownBucket &amp;gt; 0 then&lt;br /&gt;
		outputs[#outputs + 1] = renderFallbackGroup(unknownBucket, &amp;#039;unresolved series&amp;#039;, prose)&lt;br /&gt;
		trackingCats[#trackingCats + 1] = data.unresolvedSeriesCategory&lt;br /&gt;
	end&lt;br /&gt;
	if anyUnknownEpisode and isInMainspace() then&lt;br /&gt;
		trackingCats[#trackingCats + 1] = data.unknownEpisodeCategory&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local joiner = prose and &amp;#039;;&amp;amp;nbsp;&amp;#039; or &amp;#039; &amp;#039;&lt;br /&gt;
	return table.concat(outputs, joiner), formatCats(allCategories, trackingCats)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- Public entry points&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
-- Resolve which args table holds the user&amp;#039;s parameters.&lt;br /&gt;
--&lt;br /&gt;
-- Invoked through a wrapper template ({{TRS|33}}), the user&amp;#039;s parameters&lt;br /&gt;
-- live in frame:getParent().args. Invoked directly on a page&lt;br /&gt;
-- ({{#invoke:EpisodeCite|cite|series=TRS|33}}), getParent() is NOT nil —&lt;br /&gt;
-- it returns the page&amp;#039;s own frame with an EMPTY args table — so &amp;quot;parent&lt;br /&gt;
-- or frame&amp;quot; selection silently reads zero arguments. Instead: use the&lt;br /&gt;
-- parent args if they contain anything at all, else fall back to&lt;br /&gt;
-- frame.args. Emptiness must be tested with pairs(), not next() or #,&lt;br /&gt;
-- because Scribunto args tables are lazy metatable proxies that only&lt;br /&gt;
-- expand through the patched pairs().&lt;br /&gt;
local function getArgs(frame)&lt;br /&gt;
	local parent = frame.getParent and frame:getParent() or nil&lt;br /&gt;
	local pargs = parent and parent.args&lt;br /&gt;
	if pargs then&lt;br /&gt;
		for _ in pairs(pargs) do&lt;br /&gt;
			return pargs&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return frame.args&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- {{#invoke:EpisodeCite|cite|series=TRS}}&lt;br /&gt;
-- Replaces {{CAP}} / {{TRS}} / {{OS}} / {{G80}} / {{RDMep}}.&lt;br /&gt;
--&lt;br /&gt;
-- With NO series parameter — {{#invoke:EpisodeCite|cite}} via the new&lt;br /&gt;
-- universal wrapper {{Ep}} — the series of each episode is auto-detected&lt;br /&gt;
-- from the locked lists, titles are grouped per series, and groups render&lt;br /&gt;
-- in canonical franchise order (TOS, 1980, Caprica, B&amp;amp;C, TRS) regardless&lt;br /&gt;
-- of the order the editor typed them.&lt;br /&gt;
function p.cite(frame)&lt;br /&gt;
	local args = getArgs(frame)&lt;br /&gt;
	local seriesKey = frame.args.series or args.series&lt;br /&gt;
&lt;br /&gt;
	local out, cats = buildCitation(args, seriesKey)&lt;br /&gt;
	if not out then&lt;br /&gt;
		return string.format(&lt;br /&gt;
			&amp;#039;&amp;lt;strong class=&amp;quot;error&amp;quot;&amp;gt;EpisodeCite: no episode title given &amp;#039; ..&lt;br /&gt;
			&amp;#039;(usage: &amp;lt;code&amp;gt;&amp;amp;#123;&amp;amp;#123;%s|Episode Title&amp;amp;#125;&amp;amp;#125;&amp;lt;/code&amp;gt;)&amp;lt;/strong&amp;gt;&amp;#039;,&lt;br /&gt;
			(seriesKey and seriesKey ~= &amp;#039;&amp;#039; and seriesKey) or &amp;#039;Ep&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
	return out .. cats&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- {{#invoke:EpisodeCite|video|series=TRS}}&lt;br /&gt;
-- Replaces {{TRS video}} / {{TOS video}}: prose-form single-episode&lt;br /&gt;
-- citation with a timestamp, for use inside &amp;lt;ref&amp;gt; tags.&lt;br /&gt;
function p.video(frame)&lt;br /&gt;
	local args = getArgs(frame)&lt;br /&gt;
	local seriesKey = frame.args.series or args.series&lt;br /&gt;
&lt;br /&gt;
	local citeArgs = { args[1], prose = &amp;#039;y&amp;#039; }&lt;br /&gt;
	local out, cats = buildCitation(citeArgs, seriesKey)&lt;br /&gt;
	if not out then&lt;br /&gt;
		return &amp;#039;&amp;lt;strong class=&amp;quot;error&amp;quot;&amp;gt;EpisodeCite: no episode title given&amp;lt;/strong&amp;gt;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local stamp = args[2] and mw.text.trim(args[2]) or &amp;#039;&amp;#039;&lt;br /&gt;
	if stamp == &amp;#039;&amp;#039; then&lt;br /&gt;
		return out .. cats .. &amp;#039;, at an unspecified time index&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	return out .. cats .. &amp;#039;, at time index &amp;#039; .. stamp&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- {{#invoke:EpisodeCite|resolve|series=TOS|Title}}&lt;br /&gt;
-- Direct replacement for {{Diswitch}}, for any other templates that&lt;br /&gt;
-- transclude it outside the citation family.&lt;br /&gt;
function p.resolve(frame)&lt;br /&gt;
	local args = getArgs(frame)&lt;br /&gt;
	local title = args[1]&lt;br /&gt;
	if not title then&lt;br /&gt;
		return &amp;#039;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	title = mw.text.trim(title)&lt;br /&gt;
	local seriesArg = args.series&lt;br /&gt;
	local key = (seriesArg and mw.text.trim(seriesArg) == &amp;#039;TOS&amp;#039;) and &amp;#039;TOS&amp;#039; or &amp;#039;default&amp;#039;&lt;br /&gt;
	return resolveTitle(title, key)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- p.count — episode counts, for infoboxes/stats pages.&lt;br /&gt;
--&lt;br /&gt;
--   {{#invoke:EpisodeCite|count|series=TRS}}   → 78&lt;br /&gt;
--   {{#invoke:EpisodeCite|count}}              → sum across all franchise&lt;br /&gt;
--                                                 series (BC included, RDMep&lt;br /&gt;
--                                                 excluded — it&amp;#039;s not a&lt;br /&gt;
--                                                 series, just a format)&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
function p.count(frame)&lt;br /&gt;
	local args = getArgs(frame)&lt;br /&gt;
	local seriesKey = frame.args.series or args.series&lt;br /&gt;
	if seriesKey and seriesKey ~= &amp;#039;&amp;#039; then&lt;br /&gt;
		local list = data.episodes[seriesKey]&lt;br /&gt;
		if not list then&lt;br /&gt;
			error(string.format(&amp;#039;EpisodeCite: unknown series %q for count&amp;#039;, seriesKey), 0)&lt;br /&gt;
		end&lt;br /&gt;
		return #list&lt;br /&gt;
	end&lt;br /&gt;
	local total = 0&lt;br /&gt;
	for _, sk in ipairs(data.seriesOrder) do&lt;br /&gt;
		total = total + #(data.episodes[sk] or {})&lt;br /&gt;
	end&lt;br /&gt;
	return total&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- p.adjacent — previous/next episode within a series&amp;#039; locked (ordered!)&lt;br /&gt;
-- list, keyed off the same title-matching rules as citations.&lt;br /&gt;
--&lt;br /&gt;
--   {{#invoke:EpisodeCite|adjacent|33|which=next}}   → &amp;quot;Water&amp;quot;&lt;br /&gt;
--   {{#invoke:EpisodeCite|adjacent|33|which=prev}}   → &amp;quot;&amp;quot; (first episode)&lt;br /&gt;
--   {{#invoke:EpisodeCite|adjacent|33|series=TRS}}   → forces series&lt;br /&gt;
--     instead of auto-detecting (same override rule as p.cite)&lt;br /&gt;
--&lt;br /&gt;
-- Returns the ADJACENT EPISODE&amp;#039;S LOCKED ARTICLE TITLE (not the typed&lt;br /&gt;
-- short form) — callers building a nav link should wrap it themselves,&lt;br /&gt;
-- e.g. [[{{#invoke:EpisodeCite|adjacent|...}}|Next episode →]], so this&lt;br /&gt;
-- stays a plain data lookup usable by infoboxes, navboxes, or anything&lt;br /&gt;
-- else, not just one hardcoded link shape.&lt;br /&gt;
--&lt;br /&gt;
-- Returns empty string at either end of a series (no wraparound) or if&lt;br /&gt;
-- the title/series can&amp;#039;t be resolved — never errors, since this is meant&lt;br /&gt;
-- to sit unattended inside hundreds of infobox transclusions.&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
function p.adjacent(frame)&lt;br /&gt;
	local args = getArgs(frame)&lt;br /&gt;
	local title = args[1] and mw.text.trim(args[1])&lt;br /&gt;
	if not title or title == &amp;#039;&amp;#039; then&lt;br /&gt;
		return &amp;#039;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Normalize direction. Case-insensitive, with common synonyms. Empty&lt;br /&gt;
	-- or absent defaults to &amp;quot;next&amp;quot;. An unrecognized NON-EMPTY value returns&lt;br /&gt;
	-- &amp;#039;&amp;#039; rather than silently falling through to &amp;quot;next&amp;quot; — a navbox that&lt;br /&gt;
	-- says which=&amp;#039;Prev&amp;#039; (now handled) or has a real typo must not quietly&lt;br /&gt;
	-- produce a forward link labeled &amp;quot;previous&amp;quot;.&lt;br /&gt;
	local rawWhich = args.which and mw.text.trim(args.which):lower() or &amp;#039;&amp;#039;&lt;br /&gt;
	if rawWhich == &amp;#039;&amp;#039; then&lt;br /&gt;
		rawWhich = &amp;#039;next&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	local delta&lt;br /&gt;
	if rawWhich == &amp;#039;next&amp;#039; or rawWhich == &amp;#039;n&amp;#039; or rawWhich == &amp;#039;forward&amp;#039; then&lt;br /&gt;
		delta = 1&lt;br /&gt;
	elseif rawWhich == &amp;#039;prev&amp;#039; or rawWhich == &amp;#039;previous&amp;#039; or rawWhich == &amp;#039;p&amp;#039; or rawWhich == &amp;#039;back&amp;#039; then&lt;br /&gt;
		delta = -1&lt;br /&gt;
	else&lt;br /&gt;
		return &amp;#039;&amp;#039; -- unrecognized direction; refuse to guess&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local seriesKey = args.series and mw.text.trim(args.series)&lt;br /&gt;
	if not seriesKey or seriesKey == &amp;#039;&amp;#039; then&lt;br /&gt;
		local detected, ambiguous = detectSeries(title)&lt;br /&gt;
		if ambiguous or not detected then&lt;br /&gt;
			return &amp;#039;&amp;#039; -- can&amp;#039;t safely guess; caller should pass series= explicitly&lt;br /&gt;
		end&lt;br /&gt;
		seriesKey = detected&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local cfg = data.series[seriesKey]&lt;br /&gt;
	local list = data.episodes[seriesKey]&lt;br /&gt;
	if not cfg or not list then&lt;br /&gt;
		return &amp;#039;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local article = resolveTitle(title, cfg.diswitchKey)&lt;br /&gt;
	local pos&lt;br /&gt;
	for i, ep in ipairs(list) do&lt;br /&gt;
		if ep == article then&lt;br /&gt;
			pos = i&lt;br /&gt;
			break&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if not pos then&lt;br /&gt;
		return &amp;#039;&amp;#039; -- title isn&amp;#039;t in the locked list at all&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return list[pos + delta] or &amp;#039;&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- p.audit — internal data-integrity self-check, NOT meant for wiki&lt;br /&gt;
-- transclusion. Verifies every diswitch entry&amp;#039;s resolved article actually&lt;br /&gt;
-- appears in the episode list of the series that owns it, per the same&lt;br /&gt;
-- ownership rule buildReverseIndex uses. Catches transcription mistakes&lt;br /&gt;
-- in a data file that&amp;#039;s supposed to be permanently correct (the &amp;quot;Occupation&lt;br /&gt;
-- /Precipice mislabeled as webisodes&amp;quot; class of bug from the last audit —&lt;br /&gt;
-- that one was a comment error, not a data error, but a resolved-article&lt;br /&gt;
-- typo would be exactly this kind of silent breakage: the citation would&lt;br /&gt;
-- still render, just linking a title that doesn&amp;#039;t exist in the locked&lt;br /&gt;
-- list, invisible unless someone checks).&lt;br /&gt;
--&lt;br /&gt;
-- Run via p._audit() in tests, or temporarily wire to a debug entry point&lt;br /&gt;
-- if a live check is ever wanted.&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
local function audit()&lt;br /&gt;
	local problems = {}&lt;br /&gt;
	local owner = {}&lt;br /&gt;
	for _, sk in ipairs(data.seriesOrder) do&lt;br /&gt;
		for _, article in ipairs(data.episodes[sk] or {}) do&lt;br /&gt;
			owner[article] = owner[article] and true or sk&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	for mapName, map in pairs(data.diswitch) do&lt;br /&gt;
		for typed, resolved in pairs(map) do&lt;br /&gt;
			if owner[resolved] == nil then&lt;br /&gt;
				problems[#problems + 1] = string.format(&lt;br /&gt;
					&amp;#039;diswitch.%s[%q] resolves to %q, which is not in ANY locked episode list&amp;#039;,&lt;br /&gt;
					mapName, typed, resolved)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return problems&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Expose internals for testing.&lt;br /&gt;
p._buildCitation = buildCitation&lt;br /&gt;
p._resolveTitle = resolveTitle&lt;br /&gt;
p._displayTitle = displayTitle&lt;br /&gt;
p._joinCitations = joinCitations&lt;br /&gt;
p._detectSeries = detectSeries&lt;br /&gt;
p._audit = audit&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Joe Beaudoin Jr.</name></author>
	</entry>
</feed>