<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://themidnight.wiki/index.php?action=history&amp;feed=atom&amp;title=Module%3ATemplate_test_case</id>
	<title>Module:Template test case - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://themidnight.wiki/index.php?action=history&amp;feed=atom&amp;title=Module%3ATemplate_test_case"/>
	<link rel="alternate" type="text/html" href="https://themidnight.wiki/index.php?title=Module:Template_test_case&amp;action=history"/>
	<updated>2026-04-03T19:47:22Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.41.1</generator>
	<entry>
		<id>https://themidnight.wiki/index.php?title=Module:Template_test_case&amp;diff=9258&amp;oldid=prev</id>
		<title>Timothy: 1 revision imported</title>
		<link rel="alternate" type="text/html" href="https://themidnight.wiki/index.php?title=Module:Template_test_case&amp;diff=9258&amp;oldid=prev"/>
		<updated>2023-07-09T01:13:40Z</updated>

		<summary type="html">&lt;p&gt;1 revision imported&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 21:13, 8 July 2023&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&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;/table&gt;</summary>
		<author><name>Timothy</name></author>
	</entry>
	<entry>
		<id>https://themidnight.wiki/index.php?title=Module:Template_test_case&amp;diff=9257&amp;oldid=prev</id>
		<title>wikipedia&gt;Izno: add a clear</title>
		<link rel="alternate" type="text/html" href="https://themidnight.wiki/index.php?title=Module:Template_test_case&amp;diff=9257&amp;oldid=prev"/>
		<updated>2023-03-01T04:07:34Z</updated>

		<summary type="html">&lt;p&gt;add a clear&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;--[[&lt;br /&gt;
   A module for generating test case templates.&lt;br /&gt;
&lt;br /&gt;
   This module incorporates code from the English Wikipedia&amp;#039;s &amp;quot;Testcase table&amp;quot;&lt;br /&gt;
   module,[1] written by Frietjes [2] with contributions by Mr. Stradivarius [3]&lt;br /&gt;
   and Jackmcbarn,[4] and the English Wikipedia&amp;#039;s &amp;quot;Testcase rows&amp;quot; module,[5]&lt;br /&gt;
   written by Mr. Stradivarius.&lt;br /&gt;
&lt;br /&gt;
   The &amp;quot;Testcase table&amp;quot; and &amp;quot;Testcase rows&amp;quot; modules are released under the&lt;br /&gt;
   CC BY-SA 3.0 License [6] and the GFDL.[7]&lt;br /&gt;
&lt;br /&gt;
   License: CC BY-SA 3.0 and the GFDL&lt;br /&gt;
   Author: Mr. Stradivarius&lt;br /&gt;
&lt;br /&gt;
   [1] https://en.wikipedia.org/wiki/Module:Testcase_table&lt;br /&gt;
   [2] https://en.wikipedia.org/wiki/User:Frietjes&lt;br /&gt;
   [3] https://en.wikipedia.org/wiki/User:Mr._Stradivarius&lt;br /&gt;
   [4] https://en.wikipedia.org/wiki/User:Jackmcbarn&lt;br /&gt;
   [5] https://en.wikipedia.org/wiki/Module:Testcase_rows&lt;br /&gt;
   [6] https://en.wikipedia.org/wiki/Wikipedia:Text_of_Creative_Commons_Attribution-ShareAlike_3.0_Unported_License&lt;br /&gt;
   [7] https://en.wikipedia.org/wiki/Wikipedia:Text_of_the_GNU_Free_Documentation_License&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
-- Load required modules&lt;br /&gt;
local yesno = require(&amp;#039;Module:Yesno&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
-- Set constants&lt;br /&gt;
local DATA_MODULE = &amp;#039;Module:Template test case/data&amp;#039;&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
-- Shared methods&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local function message(self, key, ...)&lt;br /&gt;
	-- This method is added to classes that need to deal with messages from the&lt;br /&gt;
	-- config module.&lt;br /&gt;
	local msg = self.cfg.msg[key]&lt;br /&gt;
	if select(1, ...) then&lt;br /&gt;
		return mw.message.newRawMessage(msg, ...):plain()&lt;br /&gt;
	else&lt;br /&gt;
		return msg&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
-- Template class&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local Template = {}&lt;br /&gt;
&lt;br /&gt;
Template.memoizedMethods = {&lt;br /&gt;
	-- Names of methods to be memoized in each object. This table should only&lt;br /&gt;
	-- hold methods with no parameters.&lt;br /&gt;
	getFullPage = true,&lt;br /&gt;
	getName = true,&lt;br /&gt;
	makeHeader = true,&lt;br /&gt;
	getOutput = true&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function Template.new(invocationObj, options)&lt;br /&gt;
	local obj = {}&lt;br /&gt;
&lt;br /&gt;
	-- Set input&lt;br /&gt;
	for k, v in pairs(options or {}) do&lt;br /&gt;
		if not Template[k] then&lt;br /&gt;
			obj[k] = v&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	obj._invocation = invocationObj&lt;br /&gt;
&lt;br /&gt;
	-- Validate input&lt;br /&gt;
	if not obj.template and not obj.title then&lt;br /&gt;
		error(&amp;#039;no template or title specified&amp;#039;, 2)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Memoize expensive method calls&lt;br /&gt;
	local memoFuncs = {}&lt;br /&gt;
	return setmetatable(obj, {&lt;br /&gt;
		__index = function (t, key)&lt;br /&gt;
			if Template.memoizedMethods[key] then&lt;br /&gt;
				local func = memoFuncs[key]&lt;br /&gt;
				if not func then&lt;br /&gt;
					local val = Template[key](t)&lt;br /&gt;
					func = function () return val end&lt;br /&gt;
					memoFuncs[key] = func&lt;br /&gt;
				end&lt;br /&gt;
				return func&lt;br /&gt;
			else&lt;br /&gt;
				return Template[key]&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	})&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Template:getFullPage()&lt;br /&gt;
	if not self.template then&lt;br /&gt;
		return self.title.prefixedText&lt;br /&gt;
	elseif self.template:sub(1, 7) == &amp;#039;#invoke&amp;#039; then&lt;br /&gt;
		return &amp;#039;Module&amp;#039; .. self.template:sub(8):gsub(&amp;#039;|.*&amp;#039;, &amp;#039;&amp;#039;)&lt;br /&gt;
	else&lt;br /&gt;
		local strippedTemplate, hasColon = self.template:gsub(&amp;#039;^:&amp;#039;, &amp;#039;&amp;#039;, 1)&lt;br /&gt;
		hasColon = hasColon &amp;gt; 0&lt;br /&gt;
		local ns = strippedTemplate:match(&amp;#039;^(.-):&amp;#039;)&lt;br /&gt;
		ns = ns and mw.site.namespaces[ns]&lt;br /&gt;
		if ns then&lt;br /&gt;
			return strippedTemplate&lt;br /&gt;
		elseif hasColon then&lt;br /&gt;
			return strippedTemplate -- Main namespace&lt;br /&gt;
		else&lt;br /&gt;
			return mw.site.namespaces[10].name .. &amp;#039;:&amp;#039; .. strippedTemplate&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Template:getName()&lt;br /&gt;
	if self.template then&lt;br /&gt;
		return self.template&lt;br /&gt;
	else&lt;br /&gt;
		return require(&amp;#039;Module:Template invocation&amp;#039;).name(self.title)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Template:makeLink(display)&lt;br /&gt;
	if display then&lt;br /&gt;
		return string.format(&amp;#039;[[:%s|%s]]&amp;#039;, self:getFullPage(), display)&lt;br /&gt;
	else&lt;br /&gt;
		return string.format(&amp;#039;[[:%s]]&amp;#039;, self:getFullPage())&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Template:makeBraceLink(display)&lt;br /&gt;
	display = display or self:getName()&lt;br /&gt;
	local link = self:makeLink(display)&lt;br /&gt;
	return mw.text.nowiki(&amp;#039;{{&amp;#039;) .. link .. mw.text.nowiki(&amp;#039;}}&amp;#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Template:makeHeader()&lt;br /&gt;
	return self.heading or self:makeBraceLink()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Template:getInvocation(format)&lt;br /&gt;
	local invocation = self._invocation:getInvocation{&lt;br /&gt;
		template = self:getName(),&lt;br /&gt;
		requireMagicWord = self.requireMagicWord,&lt;br /&gt;
	}&lt;br /&gt;
	if format == &amp;#039;code&amp;#039; then&lt;br /&gt;
		invocation = &amp;#039;&amp;lt;code&amp;gt;&amp;#039; .. mw.text.nowiki(invocation) .. &amp;#039;&amp;lt;/code&amp;gt;&amp;#039;&lt;br /&gt;
	elseif format == &amp;#039;kbd&amp;#039; then&lt;br /&gt;
		invocation = &amp;#039;&amp;lt;kbd&amp;gt;&amp;#039; .. mw.text.nowiki(invocation) .. &amp;#039;&amp;lt;/kbd&amp;gt;&amp;#039;&lt;br /&gt;
	elseif format == &amp;#039;plain&amp;#039; then&lt;br /&gt;
		invocation = mw.text.nowiki(invocation)&lt;br /&gt;
	else&lt;br /&gt;
		-- Default is pre tags&lt;br /&gt;
		invocation = mw.text.encode(invocation, &amp;#039;&amp;amp;&amp;#039;)&lt;br /&gt;
		invocation = &amp;#039;&amp;lt;pre style=&amp;quot;white-space: pre-wrap;&amp;quot;&amp;gt;&amp;#039; .. invocation .. &amp;#039;&amp;lt;/pre&amp;gt;&amp;#039;&lt;br /&gt;
		invocation = mw.getCurrentFrame():preprocess(invocation)&lt;br /&gt;
	end&lt;br /&gt;
	return invocation&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Template:getOutput()&lt;br /&gt;
	local protect = require(&amp;#039;Module:Protect&amp;#039;)&lt;br /&gt;
	-- calling self._invocation:getOutput{...}&lt;br /&gt;
	return protect(self._invocation.getOutput)(self._invocation, {&lt;br /&gt;
		template = self:getName(),&lt;br /&gt;
		requireMagicWord = self.requireMagicWord,&lt;br /&gt;
	})&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
-- TestCase class&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local TestCase = {}&lt;br /&gt;
TestCase.__index = TestCase&lt;br /&gt;
TestCase.message = message -- add the message method&lt;br /&gt;
&lt;br /&gt;
TestCase.renderMethods = {&lt;br /&gt;
	-- Keys in this table are values of the &amp;quot;format&amp;quot; option, values are the&lt;br /&gt;
	-- method for rendering that format.&lt;br /&gt;
	columns = &amp;#039;renderColumns&amp;#039;,&lt;br /&gt;
	rows = &amp;#039;renderRows&amp;#039;,&lt;br /&gt;
	tablerows = &amp;#039;renderRows&amp;#039;,&lt;br /&gt;
	inline = &amp;#039;renderInline&amp;#039;,&lt;br /&gt;
	cells = &amp;#039;renderCells&amp;#039;,&lt;br /&gt;
	default = &amp;#039;renderDefault&amp;#039;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function TestCase.new(invocationObj, options, cfg)&lt;br /&gt;
	local obj = setmetatable({}, TestCase)&lt;br /&gt;
	obj.cfg = cfg&lt;br /&gt;
&lt;br /&gt;
	-- Separate general options from template options. Template options are&lt;br /&gt;
	-- numbered, whereas general options are not.&lt;br /&gt;
	local generalOptions, templateOptions = {}, {}&lt;br /&gt;
	for k, v in pairs(options) do&lt;br /&gt;
		local prefix, num&lt;br /&gt;
		if type(k) == &amp;#039;string&amp;#039; then&lt;br /&gt;
			prefix, num = k:match(&amp;#039;^(.-)([1-9][0-9]*)$&amp;#039;)&lt;br /&gt;
		end&lt;br /&gt;
		if prefix then&lt;br /&gt;
			num = tonumber(num)&lt;br /&gt;
			templateOptions[num] = templateOptions[num] or {}&lt;br /&gt;
			templateOptions[num][prefix] = v&lt;br /&gt;
		else&lt;br /&gt;
			generalOptions[k] = v&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Set general options&lt;br /&gt;
	generalOptions.showcode = yesno(generalOptions.showcode)&lt;br /&gt;
	generalOptions.showheader = yesno(generalOptions.showheader) ~= false&lt;br /&gt;
	generalOptions.showcaption = yesno(generalOptions.showcaption) ~= false&lt;br /&gt;
	generalOptions.collapsible = yesno(generalOptions.collapsible)&lt;br /&gt;
	generalOptions.notcollapsed = yesno(generalOptions.notcollapsed)&lt;br /&gt;
	generalOptions.wantdiff = yesno(generalOptions.wantdiff) &lt;br /&gt;
	obj.options = generalOptions&lt;br /&gt;
&lt;br /&gt;
	-- Preprocess template args&lt;br /&gt;
	for num, t in pairs(templateOptions) do&lt;br /&gt;
		if t.showtemplate ~= nil then&lt;br /&gt;
			t.showtemplate = yesno(t.showtemplate)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Set up first two template options tables, so that if only the&lt;br /&gt;
	-- &amp;quot;template3&amp;quot; is specified it isn&amp;#039;t made the first template when the&lt;br /&gt;
	-- the table options array is compressed.&lt;br /&gt;
	templateOptions[1] = templateOptions[1] or {}&lt;br /&gt;
	templateOptions[2] = templateOptions[2] or {}&lt;br /&gt;
&lt;br /&gt;
	-- Allow the &amp;quot;template&amp;quot; option to override the &amp;quot;template1&amp;quot; option for&lt;br /&gt;
	-- backwards compatibility with [[Module:Testcase table]].&lt;br /&gt;
	if generalOptions.template then&lt;br /&gt;
		templateOptions[1].template = generalOptions.template&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Add default template options&lt;br /&gt;
	if templateOptions[1].template and not templateOptions[2].template then&lt;br /&gt;
		templateOptions[2].template = templateOptions[1].template ..&lt;br /&gt;
			&amp;#039;/&amp;#039; .. obj.cfg.sandboxSubpage&lt;br /&gt;
	end&lt;br /&gt;
	if not templateOptions[1].template then&lt;br /&gt;
		templateOptions[1].title = mw.title.getCurrentTitle().basePageTitle&lt;br /&gt;
	end&lt;br /&gt;
	if not templateOptions[2].template then&lt;br /&gt;
		templateOptions[2].title = templateOptions[1].title:subPageTitle(&lt;br /&gt;
			obj.cfg.sandboxSubpage&lt;br /&gt;
		)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Remove template options for any templates where the showtemplate&lt;br /&gt;
	-- argument is false. This prevents any output for that template.&lt;br /&gt;
	for num, t in pairs(templateOptions) do&lt;br /&gt;
		if t.showtemplate == false then&lt;br /&gt;
			templateOptions[num] = nil&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Check for missing template names.&lt;br /&gt;
	for num, t in pairs(templateOptions) do&lt;br /&gt;
		if not t.template and not t.title then&lt;br /&gt;
			error(obj:message(&lt;br /&gt;
				&amp;#039;missing-template-option-error&amp;#039;,&lt;br /&gt;
				num, num&lt;br /&gt;
			), 2)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Compress templateOptions table so we can iterate over it with ipairs.&lt;br /&gt;
	templateOptions = (function (t)&lt;br /&gt;
		local nums = {}&lt;br /&gt;
		for num in pairs(t) do&lt;br /&gt;
			nums[#nums + 1] = num&lt;br /&gt;
		end&lt;br /&gt;
		table.sort(nums)&lt;br /&gt;
		local ret = {}&lt;br /&gt;
		for i, num in ipairs(nums) do&lt;br /&gt;
			ret[i] = t[num]&lt;br /&gt;
		end&lt;br /&gt;
		return ret&lt;br /&gt;
	end)(templateOptions)&lt;br /&gt;
&lt;br /&gt;
	-- Don&amp;#039;t require the __TEMPLATENAME__ magic word for nowiki invocations if&lt;br /&gt;
	-- there is only one template being output.&lt;br /&gt;
	if #templateOptions &amp;lt;= 1 then&lt;br /&gt;
		templateOptions[1].requireMagicWord = false&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	mw.logObject(templateOptions)&lt;br /&gt;
&lt;br /&gt;
	-- Make the template objects&lt;br /&gt;
	obj.templates = {}&lt;br /&gt;
	for i, options in ipairs(templateOptions) do&lt;br /&gt;
		table.insert(obj.templates, Template.new(invocationObj, options))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Add tracking categories. At the moment we are only tracking templates&lt;br /&gt;
	-- that use any &amp;quot;heading&amp;quot; parameters or an &amp;quot;output&amp;quot; parameter.&lt;br /&gt;
	obj.categories = {}&lt;br /&gt;
	for k, v in pairs(options) do&lt;br /&gt;
		if type(k) == &amp;#039;string&amp;#039; and k:find(&amp;#039;heading&amp;#039;) then&lt;br /&gt;
			obj.categories[&amp;#039;Test cases using heading parameters&amp;#039;] = true&lt;br /&gt;
		elseif k == &amp;#039;output&amp;#039; then&lt;br /&gt;
			obj.categories[&amp;#039;Test cases using output parameter&amp;#039;] = true&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return obj&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function TestCase:getTemplateOutput(templateObj)&lt;br /&gt;
	local output = templateObj:getOutput()&lt;br /&gt;
	if self.options.resetRefs then&lt;br /&gt;
		mw.getCurrentFrame():extensionTag(&amp;#039;references&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
	return output&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function TestCase:templateOutputIsEqual()&lt;br /&gt;
	-- Returns a boolean showing whether all of the template outputs are equal.&lt;br /&gt;
	-- The random parts of strip markers (see [[Help:Strip markers]]) are&lt;br /&gt;
	-- removed before comparison. This means a strip marker can contain anything&lt;br /&gt;
	-- and still be treated as equal, but it solves the problem of otherwise&lt;br /&gt;
	-- identical wikitext not returning as exactly equal.&lt;br /&gt;
	local function normaliseOutput(obj)&lt;br /&gt;
		local out = obj:getOutput()&lt;br /&gt;
		-- Remove the random parts from strip markers.&lt;br /&gt;
		out = out:gsub(&amp;#039;(\127[^\127]*UNIQ%-%-%l+%-)%x+(%-%-?QINU[^\127]*\127)&amp;#039;, &amp;#039;%1%2&amp;#039;)&lt;br /&gt;
		return out&lt;br /&gt;
	end&lt;br /&gt;
	local firstOutput = normaliseOutput(self.templates[1])&lt;br /&gt;
	for i = 2, #self.templates do&lt;br /&gt;
		local output = normaliseOutput(self.templates[i])&lt;br /&gt;
		if output ~= firstOutput then&lt;br /&gt;
			return false&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function TestCase:makeCollapsible(s)&lt;br /&gt;
	local title = self.options.title or self.templates[1]:makeHeader()&lt;br /&gt;
	if self.options.titlecode then&lt;br /&gt;
		title = self.templates[1]:getInvocation(&amp;#039;kbd&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
	local isEqual = self:templateOutputIsEqual()&lt;br /&gt;
	local root = mw.html.create(&amp;#039;div&amp;#039;)&lt;br /&gt;
	root&lt;br /&gt;
		:addClass(&amp;#039;mw-collapsible&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;width&amp;#039;, &amp;#039;100%&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;border&amp;#039;, &amp;#039;solid silver 1px&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;padding&amp;#039;, &amp;#039;0.2em&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;clear&amp;#039;, &amp;#039;both&amp;#039;)&lt;br /&gt;
		:addClass(self.options.notcollapsed == false and &amp;#039;mw-collapsed&amp;#039; or nil)&lt;br /&gt;
	if self.options.wantdiff then&lt;br /&gt;
		root&lt;br /&gt;
			:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
				:css(&amp;#039;background-color&amp;#039;, isEqual and &amp;#039;yellow&amp;#039; or &amp;#039;#90a8ee&amp;#039;)&lt;br /&gt;
				:css(&amp;#039;font-weight&amp;#039;, &amp;#039;bold&amp;#039;)&lt;br /&gt;
				:css(&amp;#039;padding&amp;#039;, &amp;#039;0.2em&amp;#039;)&lt;br /&gt;
				:wikitext(title)&lt;br /&gt;
				:done()&lt;br /&gt;
	else&lt;br /&gt;
		if self.options.notcollapsed ~= true or false then&lt;br /&gt;
			root&lt;br /&gt;
				:addClass(isEqual and &amp;#039;mw-collapsed&amp;#039; or nil)&lt;br /&gt;
		end&lt;br /&gt;
		root&lt;br /&gt;
			:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
				:css(&amp;#039;background-color&amp;#039;, isEqual and &amp;#039;lightgreen&amp;#039; or &amp;#039;yellow&amp;#039;)&lt;br /&gt;
				:css(&amp;#039;font-weight&amp;#039;, &amp;#039;bold&amp;#039;)&lt;br /&gt;
				:css(&amp;#039;padding&amp;#039;, &amp;#039;0.2em&amp;#039;)&lt;br /&gt;
				:wikitext(title)&lt;br /&gt;
				:done()&lt;br /&gt;
	end&lt;br /&gt;
	root&lt;br /&gt;
		:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
			:addClass(&amp;#039;mw-collapsible-content&amp;#039;)&lt;br /&gt;
			:newline()&lt;br /&gt;
			:wikitext(s)&lt;br /&gt;
			:newline()&lt;br /&gt;
	return tostring(root)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function TestCase:renderColumns()&lt;br /&gt;
	local root = mw.html.create()&lt;br /&gt;
	if self.options.showcode then&lt;br /&gt;
		root&lt;br /&gt;
			:wikitext(self.templates[1]:getInvocation())&lt;br /&gt;
			:newline()&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local tableroot = root:tag(&amp;#039;table&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
	if self.options.showheader then&lt;br /&gt;
		-- Caption&lt;br /&gt;
		if self.options.showcaption then&lt;br /&gt;
			tableroot&lt;br /&gt;
				:addClass(self.options.class)&lt;br /&gt;
				:cssText(self.options.style)&lt;br /&gt;
				:tag(&amp;#039;caption&amp;#039;)&lt;br /&gt;
					:wikitext(self.options.caption or self:message(&amp;#039;columns-header&amp;#039;))&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		-- Headers&lt;br /&gt;
		local headerRow = tableroot:tag(&amp;#039;tr&amp;#039;)&lt;br /&gt;
		if self.options.rowheader then&lt;br /&gt;
			-- rowheader is correct here. We need to add another th cell if&lt;br /&gt;
			-- rowheader is set further down, even if heading0 is missing.&lt;br /&gt;
			headerRow:tag(&amp;#039;th&amp;#039;):wikitext(self.options.heading0)&lt;br /&gt;
		end&lt;br /&gt;
		local width&lt;br /&gt;
		if #self.templates &amp;gt; 0 then&lt;br /&gt;
			width = tostring(math.floor(100 / #self.templates)) .. &amp;#039;%&amp;#039;&lt;br /&gt;
		else&lt;br /&gt;
			width = &amp;#039;100%&amp;#039;&lt;br /&gt;
		end&lt;br /&gt;
		for i, obj in ipairs(self.templates) do&lt;br /&gt;
			headerRow&lt;br /&gt;
				:tag(&amp;#039;th&amp;#039;)&lt;br /&gt;
					:css(&amp;#039;width&amp;#039;, width)&lt;br /&gt;
					:wikitext(obj:makeHeader())&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Row header&lt;br /&gt;
	local dataRow = tableroot:tag(&amp;#039;tr&amp;#039;):css(&amp;#039;vertical-align&amp;#039;, &amp;#039;top&amp;#039;)&lt;br /&gt;
	if self.options.rowheader then&lt;br /&gt;
		dataRow:tag(&amp;#039;th&amp;#039;)&lt;br /&gt;
			:attr(&amp;#039;scope&amp;#039;, &amp;#039;row&amp;#039;)&lt;br /&gt;
			:wikitext(self.options.rowheader)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- Template output&lt;br /&gt;
	for i, obj in ipairs(self.templates) do&lt;br /&gt;
		if self.options.output == &amp;#039;nowiki+&amp;#039; then&lt;br /&gt;
			dataRow:tag(&amp;#039;td&amp;#039;)&lt;br /&gt;
				:newline()&lt;br /&gt;
				:wikitext(self.options.before)&lt;br /&gt;
				:wikitext(self:getTemplateOutput(obj))&lt;br /&gt;
				:wikitext(self.options.after)&lt;br /&gt;
				:wikitext(&amp;#039;&amp;lt;pre style=&amp;quot;white-space: pre-wrap;&amp;quot;&amp;gt;&amp;#039;)&lt;br /&gt;
				:wikitext(mw.text.nowiki(self.options.before or &amp;quot;&amp;quot;))&lt;br /&gt;
				:wikitext(mw.text.nowiki(self:getTemplateOutput(obj)))&lt;br /&gt;
				:wikitext(mw.text.nowiki(self.options.after or &amp;quot;&amp;quot;))&lt;br /&gt;
				:wikitext(&amp;#039;&amp;lt;/pre&amp;gt;&amp;#039;)&lt;br /&gt;
		elseif self.options.output == &amp;#039;nowiki&amp;#039; then&lt;br /&gt;
			dataRow:tag(&amp;#039;td&amp;#039;)&lt;br /&gt;
				:newline()&lt;br /&gt;
				:wikitext(mw.text.nowiki(self.options.before or &amp;quot;&amp;quot;))&lt;br /&gt;
				:wikitext(mw.text.nowiki(self:getTemplateOutput(obj)))&lt;br /&gt;
				:wikitext(mw.text.nowiki(self.options.after or &amp;quot;&amp;quot;))&lt;br /&gt;
		else&lt;br /&gt;
			dataRow:tag(&amp;#039;td&amp;#039;)&lt;br /&gt;
				:newline()&lt;br /&gt;
				:wikitext(self.options.before)&lt;br /&gt;
				:wikitext(self:getTemplateOutput(obj))&lt;br /&gt;
				:wikitext(self.options.after)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return tostring(root)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function TestCase:renderRows()&lt;br /&gt;
	local root = mw.html.create()&lt;br /&gt;
	if self.options.showcode then&lt;br /&gt;
		root&lt;br /&gt;
			:wikitext(self.templates[1]:getInvocation())&lt;br /&gt;
			:newline()&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local tableroot = root:tag(&amp;#039;table&amp;#039;)&lt;br /&gt;
	tableroot&lt;br /&gt;
		:addClass(self.options.class)&lt;br /&gt;
		:cssText(self.options.style)&lt;br /&gt;
&lt;br /&gt;
	if self.options.caption then&lt;br /&gt;
		tableroot&lt;br /&gt;
			:tag(&amp;#039;caption&amp;#039;)&lt;br /&gt;
				:wikitext(self.options.caption)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	for _, obj in ipairs(self.templates) do&lt;br /&gt;
		local dataRow = tableroot:tag(&amp;#039;tr&amp;#039;)&lt;br /&gt;
		&lt;br /&gt;
		-- Header&lt;br /&gt;
		if self.options.showheader then&lt;br /&gt;
			if self.options.format == &amp;#039;tablerows&amp;#039; then&lt;br /&gt;
				dataRow:tag(&amp;#039;th&amp;#039;)&lt;br /&gt;
					:attr(&amp;#039;scope&amp;#039;, &amp;#039;row&amp;#039;)&lt;br /&gt;
					:css(&amp;#039;vertical-align&amp;#039;, &amp;#039;top&amp;#039;)&lt;br /&gt;
					:css(&amp;#039;text-align&amp;#039;, &amp;#039;left&amp;#039;)&lt;br /&gt;
					:wikitext(obj:makeHeader())&lt;br /&gt;
				dataRow:tag(&amp;#039;td&amp;#039;)&lt;br /&gt;
					:css(&amp;#039;vertical-align&amp;#039;, &amp;#039;top&amp;#039;)&lt;br /&gt;
					:css(&amp;#039;padding&amp;#039;, &amp;#039;0 1em&amp;#039;)&lt;br /&gt;
					:wikitext(&amp;#039;→&amp;#039;)&lt;br /&gt;
			else&lt;br /&gt;
				dataRow:tag(&amp;#039;td&amp;#039;)&lt;br /&gt;
					:css(&amp;#039;text-align&amp;#039;, &amp;#039;center&amp;#039;)&lt;br /&gt;
					:css(&amp;#039;font-weight&amp;#039;, &amp;#039;bold&amp;#039;)&lt;br /&gt;
					:wikitext(obj:makeHeader())&lt;br /&gt;
				dataRow = tableroot:tag(&amp;#039;tr&amp;#039;)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		-- Template output&lt;br /&gt;
		if self.options.output == &amp;#039;nowiki+&amp;#039; then&lt;br /&gt;
			dataRow:tag(&amp;#039;td&amp;#039;)&lt;br /&gt;
				:newline()&lt;br /&gt;
                :wikitext(self.options.before)&lt;br /&gt;
                :wikitext(self:getTemplateOutput(obj))&lt;br /&gt;
                :wikitext(self.options.after)&lt;br /&gt;
                :wikitext(&amp;#039;&amp;lt;pre style=&amp;quot;white-space: pre-wrap;&amp;quot;&amp;gt;&amp;#039;)&lt;br /&gt;
                :wikitext(mw.text.nowiki(self.options.before or &amp;quot;&amp;quot;))&lt;br /&gt;
                :wikitext(mw.text.nowiki(self:getTemplateOutput(obj)))&lt;br /&gt;
                :wikitext(mw.text.nowiki(self.options.after or &amp;quot;&amp;quot;))&lt;br /&gt;
                :wikitext(&amp;#039;&amp;lt;/pre&amp;gt;&amp;#039;)&lt;br /&gt;
		elseif self.options.output == &amp;#039;nowiki&amp;#039; then&lt;br /&gt;
			dataRow:tag(&amp;#039;td&amp;#039;)&lt;br /&gt;
				:newline()&lt;br /&gt;
				:wikitext(mw.text.nowiki(self.options.before or &amp;quot;&amp;quot;))&lt;br /&gt;
				:wikitext(mw.text.nowiki(self:getTemplateOutput(obj)))&lt;br /&gt;
				:wikitext(mw.text.nowiki(self.options.after or &amp;quot;&amp;quot;))&lt;br /&gt;
		else&lt;br /&gt;
			dataRow:tag(&amp;#039;td&amp;#039;)&lt;br /&gt;
				:newline()&lt;br /&gt;
				:wikitext(self.options.before)&lt;br /&gt;
				:wikitext(self:getTemplateOutput(obj))&lt;br /&gt;
				:wikitext(self.options.after)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return tostring(root)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function TestCase:renderInline()&lt;br /&gt;
	local arrow = mw.language.getContentLanguage():getArrow(&amp;#039;forwards&amp;#039;)&lt;br /&gt;
	local ret = {}&lt;br /&gt;
	for i, obj in ipairs(self.templates) do&lt;br /&gt;
		local line = {}&lt;br /&gt;
		line[#line + 1] = self.options.prefix or &amp;#039;* &amp;#039;&lt;br /&gt;
		if self.options.showcode then&lt;br /&gt;
			line[#line + 1] = obj:getInvocation(&amp;#039;code&amp;#039;)&lt;br /&gt;
			line[#line + 1] = &amp;#039; &amp;#039;&lt;br /&gt;
			line[#line + 1] = arrow&lt;br /&gt;
			line[#line + 1] = &amp;#039; &amp;#039;&lt;br /&gt;
		end&lt;br /&gt;
		if self.options.output == &amp;#039;nowiki+&amp;#039; then&lt;br /&gt;
			line[#line + 1] = self.options.before or &amp;quot;&amp;quot;&lt;br /&gt;
			line[#line + 1] = self:getTemplateOutput(obj)&lt;br /&gt;
			line[#line + 1] = self.options.after or &amp;quot;&amp;quot;&lt;br /&gt;
			line[#line + 1] = &amp;#039;&amp;lt;pre style=&amp;quot;white-space: pre-wrap;&amp;quot;&amp;gt;&amp;#039;&lt;br /&gt;
			line[#line + 1] = mw.text.nowiki(self.options.before or &amp;quot;&amp;quot;)&lt;br /&gt;
			line[#line + 1] = mw.text.nowiki(self:getTemplateOutput(obj))&lt;br /&gt;
			line[#line + 1] = mw.text.nowiki(self.options.after or &amp;quot;&amp;quot;)&lt;br /&gt;
			line[#line + 1] = &amp;#039;&amp;lt;/pre&amp;gt;&amp;#039;&lt;br /&gt;
		elseif self.options.output == &amp;#039;nowiki&amp;#039; then&lt;br /&gt;
			line[#line + 1] = mw.text.nowiki(self.options.before or &amp;quot;&amp;quot;)&lt;br /&gt;
			line[#line + 1] = mw.text.nowiki(self:getTemplateOutput(obj))&lt;br /&gt;
			line[#line + 1] = mw.text.nowiki(self.options.after or &amp;quot;&amp;quot;)&lt;br /&gt;
		else&lt;br /&gt;
			line[#line + 1] = self.options.before or &amp;quot;&amp;quot;&lt;br /&gt;
			line[#line + 1] = self:getTemplateOutput(obj)&lt;br /&gt;
			line[#line + 1] = self.options.after or &amp;quot;&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
		ret[#ret + 1] = table.concat(line)&lt;br /&gt;
	end&lt;br /&gt;
	if self.options.addline then&lt;br /&gt;
		local line = {}&lt;br /&gt;
		line[#line + 1] = self.options.prefix or &amp;#039;* &amp;#039;&lt;br /&gt;
		line[#line + 1] = self.options.addline&lt;br /&gt;
		ret[#ret + 1] = table.concat(line)&lt;br /&gt;
	end&lt;br /&gt;
	return table.concat(ret, &amp;#039;\n&amp;#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function TestCase:renderCells()&lt;br /&gt;
	local root = mw.html.create()&lt;br /&gt;
	local dataRow = root:tag(&amp;#039;tr&amp;#039;)&lt;br /&gt;
	dataRow&lt;br /&gt;
		:css(&amp;#039;vertical-align&amp;#039;, &amp;#039;top&amp;#039;)&lt;br /&gt;
		:addClass(self.options.class)&lt;br /&gt;
		:cssText(self.options.style)&lt;br /&gt;
&lt;br /&gt;
	-- Row header&lt;br /&gt;
	if self.options.rowheader then&lt;br /&gt;
		dataRow:tag(&amp;#039;th&amp;#039;)&lt;br /&gt;
			:attr(&amp;#039;scope&amp;#039;, &amp;#039;row&amp;#039;)&lt;br /&gt;
			:newline()&lt;br /&gt;
			:wikitext(self.options.rowheader or self:message(&amp;#039;row-header&amp;#039;))&lt;br /&gt;
	end&lt;br /&gt;
	-- Caption&lt;br /&gt;
	if self.options.showcaption then&lt;br /&gt;
		dataRow:tag(&amp;#039;th&amp;#039;)&lt;br /&gt;
			:attr(&amp;#039;scope&amp;#039;, &amp;#039;row&amp;#039;)&lt;br /&gt;
			:newline()&lt;br /&gt;
			:wikitext(self.options.caption or self:message(&amp;#039;columns-header&amp;#039;))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Show code&lt;br /&gt;
	if self.options.showcode then&lt;br /&gt;
		dataRow:tag(&amp;#039;td&amp;#039;)&lt;br /&gt;
			:newline()&lt;br /&gt;
			:wikitext(self:getInvocation(&amp;#039;code&amp;#039;))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Template output&lt;br /&gt;
	for i, obj in ipairs(self.templates) do&lt;br /&gt;
		if self.options.output == &amp;#039;nowiki+&amp;#039; then&lt;br /&gt;
			dataRow:tag(&amp;#039;td&amp;#039;)&lt;br /&gt;
				:newline()&lt;br /&gt;
				:wikitext(self.options.before)&lt;br /&gt;
				:wikitext(self:getTemplateOutput(obj))&lt;br /&gt;
				:wikitext(self.options.after)&lt;br /&gt;
				:wikitext(&amp;#039;&amp;lt;pre style=&amp;quot;white-space: pre-wrap;&amp;quot;&amp;gt;&amp;#039;)&lt;br /&gt;
				:wikitext(mw.text.nowiki(self.options.before or &amp;quot;&amp;quot;))&lt;br /&gt;
				:wikitext(mw.text.nowiki(self:getTemplateOutput(obj)))&lt;br /&gt;
				:wikitext(mw.text.nowiki(self.options.after or &amp;quot;&amp;quot;))&lt;br /&gt;
				:wikitext(&amp;#039;&amp;lt;/pre&amp;gt;&amp;#039;)&lt;br /&gt;
		elseif self.options.output == &amp;#039;nowiki&amp;#039; then&lt;br /&gt;
			dataRow:tag(&amp;#039;td&amp;#039;)&lt;br /&gt;
				:newline()&lt;br /&gt;
				:wikitext(mw.text.nowiki(self.options.before or &amp;quot;&amp;quot;))&lt;br /&gt;
				:wikitext(mw.text.nowiki(self:getTemplateOutput(obj)))&lt;br /&gt;
				:wikitext(mw.text.nowiki(self.options.after or &amp;quot;&amp;quot;))&lt;br /&gt;
		else&lt;br /&gt;
			dataRow:tag(&amp;#039;td&amp;#039;)&lt;br /&gt;
				:newline()&lt;br /&gt;
				:wikitext(self.options.before)&lt;br /&gt;
				:wikitext(self:getTemplateOutput(obj))&lt;br /&gt;
				:wikitext(self.options.after)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return tostring(root)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function TestCase:renderDefault()&lt;br /&gt;
	local ret = {}&lt;br /&gt;
	if self.options.showcode then&lt;br /&gt;
		ret[#ret + 1] = self.templates[1]:getInvocation()&lt;br /&gt;
	end&lt;br /&gt;
	for i, obj in ipairs(self.templates) do&lt;br /&gt;
		ret[#ret + 1] = &amp;#039;&amp;lt;div style=&amp;quot;clear: both;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;#039;&lt;br /&gt;
		if self.options.showheader then&lt;br /&gt;
			ret[#ret + 1] = obj:makeHeader()&lt;br /&gt;
		end&lt;br /&gt;
		if self.options.output == &amp;#039;nowiki+&amp;#039; then&lt;br /&gt;
			ret[#ret + 1] = (self.options.before or &amp;quot;&amp;quot;) ..&lt;br /&gt;
			self:getTemplateOutput(obj) ..&lt;br /&gt;
			(self.options.after or &amp;quot;&amp;quot;) ..&lt;br /&gt;
			&amp;#039;&amp;lt;pre style=&amp;quot;white-space: pre-wrap;&amp;quot;&amp;gt;&amp;#039; ..&lt;br /&gt;
			mw.text.nowiki(self.options.before or &amp;quot;&amp;quot;) ..&lt;br /&gt;
			mw.text.nowiki(self:getTemplateOutput(obj)) ..&lt;br /&gt;
			mw.text.nowiki(self.options.after or &amp;quot;&amp;quot;) .. &amp;#039;&amp;lt;/pre&amp;gt;&amp;#039;&lt;br /&gt;
		elseif self.options.output == &amp;#039;nowiki&amp;#039; then&lt;br /&gt;
			ret[#ret + 1] = mw.text.nowiki(self.options.before or &amp;quot;&amp;quot;) ..&lt;br /&gt;
			mw.text.nowiki(self:getTemplateOutput(obj)) ..&lt;br /&gt;
			mw.text.nowiki(self.options.after or &amp;quot;&amp;quot;)&lt;br /&gt;
		else&lt;br /&gt;
			ret[#ret + 1] = (self.options.before or &amp;quot;&amp;quot;) ..&lt;br /&gt;
			self:getTemplateOutput(obj) ..&lt;br /&gt;
			(self.options.after or &amp;quot;&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return table.concat(ret, &amp;#039;\n\n&amp;#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function TestCase:__tostring()&lt;br /&gt;
	local format = self.options.format&lt;br /&gt;
	local method = format and TestCase.renderMethods[format] or &amp;#039;renderDefault&amp;#039;&lt;br /&gt;
	local ret = self[method](self)&lt;br /&gt;
	if self.options.collapsible then&lt;br /&gt;
		ret = self:makeCollapsible(ret)&lt;br /&gt;
	end&lt;br /&gt;
	for cat in pairs(self.categories) do&lt;br /&gt;
		ret = ret .. string.format(&amp;#039;[[Category:%s]]&amp;#039;, cat)&lt;br /&gt;
	end&lt;br /&gt;
	return ret&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
-- Nowiki invocation class&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local NowikiInvocation = {}&lt;br /&gt;
NowikiInvocation.__index = NowikiInvocation&lt;br /&gt;
NowikiInvocation.message = message -- Add the message method&lt;br /&gt;
&lt;br /&gt;
function NowikiInvocation.new(invocation, cfg)&lt;br /&gt;
	local obj = setmetatable({}, NowikiInvocation)&lt;br /&gt;
	obj.cfg = cfg&lt;br /&gt;
	invocation = mw.text.unstrip(invocation)&lt;br /&gt;
	-- Decode HTML entities for &amp;lt;, &amp;gt;, and &amp;quot;. This means that HTML entities in&lt;br /&gt;
	-- the original code must be escaped as e.g. &amp;amp;amp;lt;, which is unfortunate,&lt;br /&gt;
	-- but it is the best we can do as the distinction between &amp;lt;, &amp;gt;, &amp;quot; and &amp;amp;lt;,&lt;br /&gt;
	-- &amp;amp;gt;, &amp;amp;quot; is lost during the original nowiki operation.&lt;br /&gt;
	invocation = invocation:gsub(&amp;#039;&amp;amp;lt;&amp;#039;, &amp;#039;&amp;lt;&amp;#039;)&lt;br /&gt;
	invocation = invocation:gsub(&amp;#039;&amp;amp;gt;&amp;#039;, &amp;#039;&amp;gt;&amp;#039;)&lt;br /&gt;
	invocation = invocation:gsub(&amp;#039;&amp;amp;quot;&amp;#039;, &amp;#039;&amp;quot;&amp;#039;)&lt;br /&gt;
	obj.invocation = invocation&lt;br /&gt;
	return obj&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function NowikiInvocation:getInvocation(options)&lt;br /&gt;
	local template = options.template:gsub(&amp;#039;%%&amp;#039;, &amp;#039;%%%%&amp;#039;) -- Escape &amp;quot;%&amp;quot; with &amp;quot;%%&amp;quot;&lt;br /&gt;
	local invocation, count = self.invocation:gsub(&lt;br /&gt;
		self.cfg.templateNameMagicWordPattern,&lt;br /&gt;
		template&lt;br /&gt;
	)&lt;br /&gt;
	if options.requireMagicWord ~= false and count &amp;lt; 1 then&lt;br /&gt;
		error(self:message(&lt;br /&gt;
			&amp;#039;nowiki-magic-word-error&amp;#039;,&lt;br /&gt;
			self.cfg.templateNameMagicWord&lt;br /&gt;
		))&lt;br /&gt;
	end&lt;br /&gt;
	return invocation&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function NowikiInvocation:getOutput(options)&lt;br /&gt;
	local invocation = self:getInvocation(options)&lt;br /&gt;
	return mw.getCurrentFrame():preprocess(invocation)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
-- Table invocation class&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local TableInvocation = {}&lt;br /&gt;
TableInvocation.__index = TableInvocation&lt;br /&gt;
TableInvocation.message = message -- Add the message method&lt;br /&gt;
&lt;br /&gt;
function TableInvocation.new(invokeArgs, nowikiCode, cfg)&lt;br /&gt;
	local obj = setmetatable({}, TableInvocation)&lt;br /&gt;
	obj.cfg = cfg&lt;br /&gt;
	obj.invokeArgs = invokeArgs&lt;br /&gt;
	obj.code = nowikiCode&lt;br /&gt;
	return obj&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function TableInvocation:getInvocation(options)&lt;br /&gt;
	if self.code then&lt;br /&gt;
		local nowikiObj = NowikiInvocation.new(self.code, self.cfg)&lt;br /&gt;
		return nowikiObj:getInvocation(options)&lt;br /&gt;
	else&lt;br /&gt;
		return require(&amp;#039;Module:Template invocation&amp;#039;).invocation(&lt;br /&gt;
			options.template,&lt;br /&gt;
			self.invokeArgs&lt;br /&gt;
		)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function TableInvocation:getOutput(options)&lt;br /&gt;
	if (options.template:sub(1, 7) == &amp;#039;#invoke&amp;#039;) then&lt;br /&gt;
		local moduleCall = mw.text.split(options.template, &amp;#039;|&amp;#039;, true)&lt;br /&gt;
		local args = mw.clone(self.invokeArgs)&lt;br /&gt;
		table.insert(args, 1, moduleCall[2])&lt;br /&gt;
		return mw.getCurrentFrame():callParserFunction(moduleCall[1], args)&lt;br /&gt;
	end&lt;br /&gt;
	return mw.getCurrentFrame():expandTemplate{&lt;br /&gt;
		title = options.template,&lt;br /&gt;
		args = self.invokeArgs&lt;br /&gt;
	}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
-- Bridge functions&lt;br /&gt;
--&lt;br /&gt;
-- These functions translate template arguments into forms that can be accepted&lt;br /&gt;
-- by the different classes, and return the results.&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local bridge = {}&lt;br /&gt;
&lt;br /&gt;
function bridge.table(args, cfg)&lt;br /&gt;
	cfg = cfg or mw.loadData(DATA_MODULE)&lt;br /&gt;
&lt;br /&gt;
	local options, invokeArgs = {}, {}&lt;br /&gt;
	for k, v in pairs(args) do&lt;br /&gt;
		local optionKey = type(k) == &amp;#039;string&amp;#039; and k:match(&amp;#039;^_(.*)$&amp;#039;)&lt;br /&gt;
		if optionKey then&lt;br /&gt;
			if type(v) == &amp;#039;string&amp;#039; then&lt;br /&gt;
				v = v:match(&amp;#039;^%s*(.-)%s*$&amp;#039;) -- trim whitespace&lt;br /&gt;
			end&lt;br /&gt;
			if v ~= &amp;#039;&amp;#039; then&lt;br /&gt;
				options[optionKey] = v&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			invokeArgs[k] = v&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Allow passing a nowiki invocation as an option. While this means users&lt;br /&gt;
	-- have to pass in the code twice, whitespace is preserved and &amp;amp;lt; etc.&lt;br /&gt;
	-- will work as intended.&lt;br /&gt;
	local nowikiCode = options.code&lt;br /&gt;
	options.code = nil&lt;br /&gt;
&lt;br /&gt;
	local invocationObj = TableInvocation.new(invokeArgs, nowikiCode, cfg)&lt;br /&gt;
	local testCaseObj = TestCase.new(invocationObj, options, cfg)&lt;br /&gt;
	return tostring(testCaseObj)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function bridge.nowiki(args, cfg)&lt;br /&gt;
	cfg = cfg or mw.loadData(DATA_MODULE)&lt;br /&gt;
&lt;br /&gt;
	local code = args.code or args[1]&lt;br /&gt;
	local invocationObj = NowikiInvocation.new(code, cfg)&lt;br /&gt;
	args.code = nil&lt;br /&gt;
	args[1] = nil&lt;br /&gt;
	-- Assume we want to see the code as we already passed it in.&lt;br /&gt;
	args.showcode = args.showcode or true&lt;br /&gt;
	local testCaseObj = TestCase.new(invocationObj, args, cfg)&lt;br /&gt;
	return tostring(testCaseObj)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
-- Exports&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
function p.main(frame, cfg)&lt;br /&gt;
	cfg = cfg or mw.loadData(DATA_MODULE)&lt;br /&gt;
&lt;br /&gt;
	-- Load the wrapper config, if any.&lt;br /&gt;
	local wrapperConfig&lt;br /&gt;
	if frame.getParent then&lt;br /&gt;
		local title = frame:getParent():getTitle()&lt;br /&gt;
		local template = title:gsub(cfg.sandboxSubpagePattern, &amp;#039;&amp;#039;)&lt;br /&gt;
		wrapperConfig = cfg.wrappers[template]&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Work out the function we will call, use it to generate the config for&lt;br /&gt;
	-- Module:Arguments, and use Module:Arguments to find the arguments passed&lt;br /&gt;
	-- by the user.&lt;br /&gt;
	local func = wrapperConfig and wrapperConfig.func or &amp;#039;table&amp;#039;&lt;br /&gt;
	local userArgs = require(&amp;#039;Module:Arguments&amp;#039;).getArgs(frame, {&lt;br /&gt;
		parentOnly = wrapperConfig,&lt;br /&gt;
		frameOnly = not wrapperConfig,&lt;br /&gt;
		trim = func ~= &amp;#039;table&amp;#039;,&lt;br /&gt;
		removeBlanks = func ~= &amp;#039;table&amp;#039;&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	-- Get default args and build the args table. User-specified args overwrite&lt;br /&gt;
	-- default args.&lt;br /&gt;
	local defaultArgs = wrapperConfig and wrapperConfig.args or {}&lt;br /&gt;
	local args = {}&lt;br /&gt;
	for k, v in pairs(defaultArgs) do&lt;br /&gt;
		args[k] = v&lt;br /&gt;
	end&lt;br /&gt;
	for k, v in pairs(userArgs) do&lt;br /&gt;
		args[k] = v&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return bridge[func](args, cfg)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._exportClasses() -- For testing&lt;br /&gt;
	return {&lt;br /&gt;
		Template = Template,&lt;br /&gt;
		TestCase = TestCase,&lt;br /&gt;
		NowikiInvocation = NowikiInvocation,&lt;br /&gt;
		TableInvocation = TableInvocation&lt;br /&gt;
	}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>wikipedia&gt;Izno</name></author>
	</entry>
</feed>