<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://cellan.joemonson.com/index.php?action=history&amp;feed=atom&amp;title=Module%3ATemplatePar%2Fsandbox</id>
	<title>Module:TemplatePar/sandbox - Revision history</title>
	<link rel="self" type="application/atom+xml" href="http://cellan.joemonson.com/index.php?action=history&amp;feed=atom&amp;title=Module%3ATemplatePar%2Fsandbox"/>
	<link rel="alternate" type="text/html" href="http://cellan.joemonson.com/index.php?title=Module:TemplatePar/sandbox&amp;action=history"/>
	<updated>2026-10-25T20:00:16Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.39.0</generator>
	<entry>
		<id>http://cellan.joemonson.com/index.php?title=Module:TemplatePar/sandbox&amp;diff=4474&amp;oldid=prev</id>
		<title>Cellan3: create</title>
		<link rel="alternate" type="text/html" href="http://cellan.joemonson.com/index.php?title=Module:TemplatePar/sandbox&amp;diff=4474&amp;oldid=prev"/>
		<updated>2023-09-06T20:37:55Z</updated>

		<summary type="html">&lt;p&gt;create&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;--[=[ TemplatePar 2015-02-14&lt;br /&gt;
Template parameter utility&lt;br /&gt;
* assert&lt;br /&gt;
* check&lt;br /&gt;
* count&lt;br /&gt;
* countNotEmpty&lt;br /&gt;
* downcase()&lt;br /&gt;
* match&lt;br /&gt;
* valid&lt;br /&gt;
* verify()&lt;br /&gt;
* TemplatePar()&lt;br /&gt;
]=]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Module globals&lt;br /&gt;
local TemplatePar = { }&lt;br /&gt;
local MessagePrefix = &amp;quot;lua-module-TemplatePar-&amp;quot;&lt;br /&gt;
local L10nDef = {}&lt;br /&gt;
L10nDef.en = {&lt;br /&gt;
	badPattern  = &amp;quot;&amp;amp;#35;invoke:TemplatePar pattern syntax error&amp;quot;,&lt;br /&gt;
	dupOpt	  = &amp;quot;&amp;amp;#35;invoke:TemplatePar repeated optional parameter&amp;quot;,&lt;br /&gt;
	dupRule	 = &amp;quot;&amp;amp;#35;invoke:TemplatePar conflict key/pattern&amp;quot;,&lt;br /&gt;
	empty	   = &amp;quot;Error in template * undefined value for mandatory&amp;quot;,&lt;br /&gt;
	invalid	 = &amp;quot;Error in template * invalid parameter&amp;quot;,&lt;br /&gt;
	invalidPar  = &amp;quot;&amp;amp;#35;invoke:TemplatePar invalid parameter&amp;quot;,&lt;br /&gt;
	minmax	  = &amp;quot;&amp;amp;#35;invoke:TemplatePar min &amp;gt; max&amp;quot;,&lt;br /&gt;
	missing	 = &amp;quot;&amp;amp;#35;invoke:TemplatePar missing library&amp;quot;,&lt;br /&gt;
	multiSpell  = &amp;quot;Error in template * multiple spelling of parameter&amp;quot;,&lt;br /&gt;
	noMSGnoCAT  = &amp;quot;&amp;amp;#35;invoke:TemplatePar neither message nor category&amp;quot;,&lt;br /&gt;
	noname	  = &amp;quot;&amp;amp;#35;invoke:TemplatePar missing parameter name&amp;quot;,&lt;br /&gt;
	notFound	= &amp;quot;Error in template * missing page&amp;quot;,&lt;br /&gt;
	tooLong	 = &amp;quot;Error in template * parameter too long&amp;quot;,&lt;br /&gt;
	tooShort	= &amp;quot;Error in template * parameter too short&amp;quot;,&lt;br /&gt;
	undefined   = &amp;quot;Error in template * mandatory parameter missing&amp;quot;,&lt;br /&gt;
	unknown	 = &amp;quot;Error in template * unknown parameter name&amp;quot;,&lt;br /&gt;
	unknownRule = &amp;quot;&amp;amp;#35;invoke:TemplatePar unknown rule&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
L10nDef.de  = {&lt;br /&gt;
	badPattern  = &amp;quot;&amp;amp;#35;invoke:TemplatePar Syntaxfehler des pattern&amp;quot;,&lt;br /&gt;
	dupOpt	  = &amp;quot;&amp;amp;#35;invoke:TemplatePar Optionsparameter wiederholt&amp;quot;,&lt;br /&gt;
	dupRule	 = &amp;quot;&amp;amp;#35;invoke:TemplatePar Konflikt key/pattern&amp;quot;,&lt;br /&gt;
	empty	   = &amp;quot;Fehler bei Vorlage * Pflichtparameter ohne Wert&amp;quot;,&lt;br /&gt;
	invalid	 = &amp;quot;Fehler bei Vorlage * Parameter ungültig&amp;quot;,&lt;br /&gt;
	invalidPar  = &amp;quot;&amp;amp;#35;invoke:TemplatePar Ungültiger Parameter&amp;quot;,&lt;br /&gt;
	minmax	  = &amp;quot;&amp;amp;#35;invoke:TemplatePar min &amp;gt; max&amp;quot;,&lt;br /&gt;
	multiSpell  = &amp;quot;Fehler bei Vorlage * Mehrere Parameter-Schreibweisen&amp;quot;,&lt;br /&gt;
	noMSGnoCAT  = &amp;quot;&amp;amp;#35;invoke:TemplatePar weder Meldung noch Kategorie&amp;quot;,&lt;br /&gt;
	noname	  = &amp;quot;&amp;amp;#35;invoke:TemplatePar Parameter nicht angegeben&amp;quot;,&lt;br /&gt;
	notFound	= &amp;quot;Fehler bei Vorlage * Seite fehlt&amp;quot;,&lt;br /&gt;
	tooLong	 = &amp;quot;Fehler bei Vorlage * Parameter zu lang&amp;quot;,&lt;br /&gt;
	tooShort	= &amp;quot;Fehler bei Vorlage * Parameter zu kurz&amp;quot;,&lt;br /&gt;
	undefined   = &amp;quot;Fehler bei Vorlage * Pflichtparameter fehlt&amp;quot;,&lt;br /&gt;
	unknown	 = &amp;quot;Fehler bei Vorlage * Parametername unbekannt&amp;quot;,&lt;br /&gt;
	unknownRule = &amp;quot;&amp;amp;#35;invoke:TemplatePar Unbekannte Regel&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
local Patterns = {&lt;br /&gt;
	[ &amp;quot;ASCII&amp;quot; ]	= &amp;quot;^[ -~]*$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;ASCII+&amp;quot; ]   = &amp;quot;^[ -~]+$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;ASCII+1&amp;quot; ]  = &amp;quot;^[!-~]+$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;n&amp;quot; ]		= &amp;quot;^[%-]?[0-9]*$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;n&amp;gt;0&amp;quot; ]	  = &amp;quot;^[0-9]*[1-9][0-9]*$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;N+&amp;quot; ]	   = &amp;quot;^[%-]?[1-9][0-9]*$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;N&amp;gt;0&amp;quot; ]	  = &amp;quot;^[1-9][0-9]*$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;x&amp;quot; ]		= &amp;quot;^[0-9A-Fa-f]*$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;x+&amp;quot; ]	   = &amp;quot;^[0-9A-Fa-f]+$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;X&amp;quot; ]		= &amp;quot;^[0-9A-F]*$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;X+&amp;quot; ]	   = &amp;quot;^[0-9A-F]+$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;0,0&amp;quot; ]	  = &amp;quot;^[%-]?[0-9]*,?[0-9]*$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;0,0+&amp;quot; ]	 = &amp;quot;^[%-]?[0-9]+,[0-9]+$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;0,0+?&amp;quot; ]	= &amp;quot;^[%-]?[0-9]+,?[0-9]*$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;0.0&amp;quot; ]	  = &amp;quot;^[%-]?[0-9]*[%.]?[0-9]*$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;0.0+&amp;quot; ]	 = &amp;quot;^[%-]?[0-9]+%.[0-9]+$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;0.0+?&amp;quot; ]	= &amp;quot;^[%-]?[0-9]+[%.]?[0-9]*$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;.0+&amp;quot; ]	  = &amp;quot;^[%-]?[0-9]*[%.]?[0-9]+$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;ID&amp;quot; ]	   = &amp;quot;^[A-Za-z]?[A-Za-z_0-9]*$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;ID+&amp;quot; ]	  = &amp;quot;^[A-Za-z][A-Za-z_0-9]*$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;ABC&amp;quot; ]	  = &amp;quot;^[A-Z]*$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;ABC+&amp;quot; ]	 = &amp;quot;^[A-Z]+$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;Abc&amp;quot; ]	  = &amp;quot;^[A-Z]*[a-z]*$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;Abc+&amp;quot; ]	 = &amp;quot;^[A-Z][a-z]+$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;abc&amp;quot; ]	  = &amp;quot;^[a-z]*$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;abc+&amp;quot; ]	 = &amp;quot;^[a-z]+$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;aBc+&amp;quot; ]	 = &amp;quot;^[a-z]+[A-Z][A-Za-z]*$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;w&amp;quot; ]		= &amp;quot;^%S*$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;w+&amp;quot; ]	   = &amp;quot;^%S+$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;base64&amp;quot; ]   = &amp;quot;^[A-Za-z0-9%+/]*$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;base64+&amp;quot; ]  = &amp;quot;^[A-Za-z0-9%+/]+$&amp;quot;,&lt;br /&gt;
	[ &amp;quot;aa&amp;quot; ]	   = &amp;quot;[%a%a].*[%a%a]&amp;quot;,&lt;br /&gt;
	[ &amp;quot;pagename&amp;quot; ] = string.format( &amp;quot;^[^#&amp;lt;&amp;gt;%%[%%]|{}%c-%c%c]+$&amp;quot;,&lt;br /&gt;
									1, 31, 127 ),&lt;br /&gt;
	[ &amp;quot;+&amp;quot; ]		= &amp;quot;%S&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
local patternCJK = false&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function containsCJK( s )&lt;br /&gt;
	-- Is any CJK character present?&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 s  -- string&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return false iff no CJK present&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 &amp;gt;&amp;lt; patternCJK&lt;br /&gt;
	--	 mw.ustring.char()&lt;br /&gt;
	--	 mw.ustring.match()&lt;br /&gt;
	local r = false&lt;br /&gt;
	patternCJK = patternCJK or mw.ustring.char(91,&lt;br /&gt;
									   13312, 45,  40959,&lt;br /&gt;
									  131072, 45, 178207,&lt;br /&gt;
									  93 )&lt;br /&gt;
	if mw.ustring.match( s, patternCJK ) then&lt;br /&gt;
		r = true&lt;br /&gt;
	end&lt;br /&gt;
	return r&lt;br /&gt;
end -- containsCJK()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function facility( accept, attempt )&lt;br /&gt;
	-- Check string as possible file name or other source page&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 accept   -- string; requirement&lt;br /&gt;
	--						 file&lt;br /&gt;
	--						 file+&lt;br /&gt;
	--						 file:&lt;br /&gt;
	--						 file:+&lt;br /&gt;
	--						 image&lt;br /&gt;
	--						 image+&lt;br /&gt;
	--						 image:&lt;br /&gt;
	--						 image:+&lt;br /&gt;
	--	 attempt  -- string; to be tested&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return error keyword, or false&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 Module:FileMedia&lt;br /&gt;
	--	 FileMedia.isType()&lt;br /&gt;
	local r&lt;br /&gt;
	if attempt and attempt ~= &amp;quot;&amp;quot; then&lt;br /&gt;
		local lucky, FileMedia = pcall( require, &amp;quot;Module:FileMedia&amp;quot; )&lt;br /&gt;
		if type( FileMedia ) == &amp;quot;table&amp;quot; then&lt;br /&gt;
			FileMedia = FileMedia.FileMedia()&lt;br /&gt;
			local s, live = accept:match( &amp;quot;^([a-z]+)(:?)%+?$&amp;quot; )&lt;br /&gt;
			if live then&lt;br /&gt;
				if FileMedia.isType( attempt, s ) then&lt;br /&gt;
					if FileMedia.isFile( attempt ) then&lt;br /&gt;
						r = false&lt;br /&gt;
					else&lt;br /&gt;
						r = &amp;quot;notFound&amp;quot;&lt;br /&gt;
					end&lt;br /&gt;
				else&lt;br /&gt;
					r = &amp;quot;invalid&amp;quot;&lt;br /&gt;
				end&lt;br /&gt;
			elseif FileMedia.isType( attempt, s ) then&lt;br /&gt;
				r = false&lt;br /&gt;
			else&lt;br /&gt;
				r = &amp;quot;invalid&amp;quot;&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			r = &amp;quot;missing&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
	elseif accept:match( &amp;quot;%+$&amp;quot; ) then&lt;br /&gt;
		r = &amp;quot;empty&amp;quot;&lt;br /&gt;
	else&lt;br /&gt;
		r = false&lt;br /&gt;
	end&lt;br /&gt;
	return r&lt;br /&gt;
end -- facility()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function factory( say )&lt;br /&gt;
	-- Retrieve localized message string in content language&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 say  -- string; message ID&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return some message string&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 &amp;gt;  MessagePrefix&lt;br /&gt;
	--	 &amp;gt;  L10nDef&lt;br /&gt;
	--	 mw.language.getContentLanguage()&lt;br /&gt;
	--	 mw.message.new()&lt;br /&gt;
	local c = mw.language.getContentLanguage():getCode()&lt;br /&gt;
	local m = mw.message.new( MessagePrefix .. say )&lt;br /&gt;
	local r = false&lt;br /&gt;
	if m:isBlank() then&lt;br /&gt;
		local l10n = L10nDef[ c ] or L10nDef[ &amp;quot;en&amp;quot; ]&lt;br /&gt;
		r = l10n[ say ]&lt;br /&gt;
	else&lt;br /&gt;
		m:inLanguage( c )&lt;br /&gt;
		r = m:plain()&lt;br /&gt;
	end&lt;br /&gt;
	r = r or string.format( &amp;quot;(((%s)))&amp;quot;, say )&lt;br /&gt;
	return r&lt;br /&gt;
end -- factory()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function failsafe( story, scan )&lt;br /&gt;
	-- Test for match (possibly user-defined with syntax error)&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 story  -- string; parameter value&lt;br /&gt;
	--	 scan   -- string; pattern&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return nil, if not matching, else non-nil&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 mw.ustring.match()&lt;br /&gt;
	return  mw.ustring.match( story, scan )&lt;br /&gt;
end -- failsafe()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function failure( spec, suspect, options )&lt;br /&gt;
	-- Submit localized error message&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 spec	 -- string; message ID&lt;br /&gt;
	--	 suspect  -- string or nil; additional information&lt;br /&gt;
	--	 options  -- table or nil; optional details&lt;br /&gt;
	--				 options.template&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return string&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 factory()&lt;br /&gt;
	local r = factory( spec )&lt;br /&gt;
	if type( options ) == &amp;quot;table&amp;quot; then&lt;br /&gt;
		if type( options.template ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
			if #options.template &amp;gt; 0 then&lt;br /&gt;
				r = string.format( &amp;quot;%s (%s)&amp;quot;, r, options.template )&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if suspect then&lt;br /&gt;
		r = string.format( &amp;quot;%s: %s&amp;quot;, r, suspect )&lt;br /&gt;
	end&lt;br /&gt;
	return r&lt;br /&gt;
end -- failure()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function fault( store, key )&lt;br /&gt;
	-- Add key to collection string and insert separator&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 store  -- string or nil or false; collection string&lt;br /&gt;
	--	 key	-- string or number; to be appended&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return string; extended&lt;br /&gt;
	local r&lt;br /&gt;
	local s&lt;br /&gt;
	if type( key ) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		s = tostring( key )&lt;br /&gt;
	else&lt;br /&gt;
		s = key&lt;br /&gt;
	end&lt;br /&gt;
	if store then&lt;br /&gt;
		r = string.format( &amp;quot;%s; %s&amp;quot;, store, s )&lt;br /&gt;
	else&lt;br /&gt;
		r = s&lt;br /&gt;
	end&lt;br /&gt;
	return r&lt;br /&gt;
end -- fault()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function feasible( analyze, options, abbr )&lt;br /&gt;
	-- Check content of a value&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 analyze  -- string to be analyzed&lt;br /&gt;
	--	 options  -- table or nil; optional details&lt;br /&gt;
	--				 options.pattern&lt;br /&gt;
	--				 options.key&lt;br /&gt;
	--				 options.say&lt;br /&gt;
	--	 abbr	 -- true: abbreviated error message&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return string with error message as configured;&lt;br /&gt;
	--			false if valid or no answer permitted&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 &amp;gt;  Patterns&lt;br /&gt;
	--	 failure()&lt;br /&gt;
	--	 mw.text.trim()&lt;br /&gt;
	--	 facility()&lt;br /&gt;
	--	 failsafe()&lt;br /&gt;
	--	 containsCJK()&lt;br /&gt;
	local r	= false&lt;br /&gt;
	local s	= false&lt;br /&gt;
	local show = nil&lt;br /&gt;
	local scan = false&lt;br /&gt;
	if type( options.pattern ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
		if options.key then&lt;br /&gt;
			r = failure( &amp;quot;dupRule&amp;quot;, false, options )&lt;br /&gt;
		else&lt;br /&gt;
			scan = options.pattern&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		if type( options.key ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
			s = mw.text.trim( options.key )&lt;br /&gt;
		else&lt;br /&gt;
			s = &amp;quot;+&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
		if s ~= &amp;quot;*&amp;quot; then&lt;br /&gt;
			scan = Patterns[ s ]&lt;br /&gt;
		end&lt;br /&gt;
		if type( scan ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
			if s == &amp;quot;n&amp;quot; or s == &amp;quot;0,0&amp;quot; or s == &amp;quot;0.0&amp;quot; then&lt;br /&gt;
				if not analyze:match( &amp;quot;[0-9]&amp;quot; )  and&lt;br /&gt;
				   not analyze:match( &amp;quot;^%s*$&amp;quot; ) then&lt;br /&gt;
					scan = false&lt;br /&gt;
					if options.say then&lt;br /&gt;
						show = string.format( &amp;quot;&amp;#039;%s&amp;#039;&amp;quot;, options.say )&lt;br /&gt;
					end&lt;br /&gt;
					if abbr then&lt;br /&gt;
						r = show&lt;br /&gt;
					else&lt;br /&gt;
						r = failure( &amp;quot;invalid&amp;quot;, show, options )&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		elseif s ~= &amp;quot;*&amp;quot; then&lt;br /&gt;
			local op, n, plus = s:match( &amp;quot;([&amp;lt;!=&amp;gt;]=?)([-0-9][%S]*)(+?)&amp;quot; )&lt;br /&gt;
			if op then&lt;br /&gt;
				n = tonumber( n )&lt;br /&gt;
				if n then&lt;br /&gt;
					local i = tonumber( analyze )&lt;br /&gt;
					if i then&lt;br /&gt;
						if op == &amp;quot;&amp;lt;&amp;quot; then&lt;br /&gt;
							i = ( i &amp;lt; n )&lt;br /&gt;
						elseif op == &amp;quot;&amp;lt;=&amp;quot; then&lt;br /&gt;
							i = ( i &amp;lt;= n )&lt;br /&gt;
						elseif op == &amp;quot;&amp;gt;&amp;quot; then&lt;br /&gt;
							i = ( i &amp;gt; n )&lt;br /&gt;
						elseif op == &amp;quot;&amp;gt;=&amp;quot; then&lt;br /&gt;
							i = ( i &amp;gt;= n )&lt;br /&gt;
						elseif op == &amp;quot;==&amp;quot; then&lt;br /&gt;
							i = ( i == n )&lt;br /&gt;
						elseif op == &amp;quot;!=&amp;quot; then&lt;br /&gt;
							i = ( i ~= n )&lt;br /&gt;
						else&lt;br /&gt;
							n = false&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
					if not i then&lt;br /&gt;
						r = &amp;quot;invalid&amp;quot;&lt;br /&gt;
					end&lt;br /&gt;
				elseif plus then&lt;br /&gt;
					r = &amp;quot;undefined&amp;quot;&lt;br /&gt;
				end&lt;br /&gt;
			elseif s:match( &amp;quot;^image%+?:?$&amp;quot; )  or&lt;br /&gt;
				   s:match( &amp;quot;^file%+?:?$&amp;quot; ) then&lt;br /&gt;
				r = facility( s, analyze )&lt;br /&gt;
				n = true&lt;br /&gt;
			elseif s:match( &amp;quot;langW?%+?&amp;quot; ) then&lt;br /&gt;
				n = &amp;quot;lang&amp;quot;&lt;br /&gt;
-- lang lang+&lt;br /&gt;
-- langW langW+&lt;br /&gt;
			end&lt;br /&gt;
			if not n and not r then&lt;br /&gt;
				r = &amp;quot;unknownRule&amp;quot;&lt;br /&gt;
			end&lt;br /&gt;
			if r then&lt;br /&gt;
				if options.say then&lt;br /&gt;
					show = string.format( &amp;quot;&amp;#039;%s&amp;#039; %s&amp;quot;, options.say, s )&lt;br /&gt;
				else&lt;br /&gt;
					show = s&lt;br /&gt;
				end&lt;br /&gt;
				if abbr then&lt;br /&gt;
					r = show&lt;br /&gt;
				else&lt;br /&gt;
					r = failure( r, show, options )&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if scan then&lt;br /&gt;
		local legal, got = pcall( failsafe, analyze, scan )&lt;br /&gt;
		if legal then&lt;br /&gt;
			if not got then&lt;br /&gt;
				if s == &amp;quot;aa&amp;quot; then&lt;br /&gt;
					got = containsCJK( analyze )&lt;br /&gt;
				end&lt;br /&gt;
				if not got then&lt;br /&gt;
					if options.say then&lt;br /&gt;
						show = string.format( &amp;quot;&amp;#039;%s&amp;#039;&amp;quot;, options.say )&lt;br /&gt;
					end&lt;br /&gt;
					if abbr then&lt;br /&gt;
						r = show&lt;br /&gt;
					else&lt;br /&gt;
						r = failure( &amp;quot;invalid&amp;quot;, show, options )&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			r = failure( &amp;quot;badPattern&amp;quot;,&lt;br /&gt;
						 string.format( &amp;quot;%s *** %s&amp;quot;, scan, got ),&lt;br /&gt;
						 options )&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return r&lt;br /&gt;
end -- feasible()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function fed( haystack, needle )&lt;br /&gt;
	-- Find needle in haystack map&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 haystack  -- table; map of key values&lt;br /&gt;
	--	 needle	-- any; identifier&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return true iff found&lt;br /&gt;
	local k, v&lt;br /&gt;
	for k, v in pairs( haystack ) do&lt;br /&gt;
		if k == needle then&lt;br /&gt;
			return true&lt;br /&gt;
		end&lt;br /&gt;
	end -- for k, v&lt;br /&gt;
	return false&lt;br /&gt;
end -- fed()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function fetch( light, options )&lt;br /&gt;
	-- Return regular table with all parameters&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 light	-- true: template transclusion;  false: #invoke&lt;br /&gt;
	--	 options  -- table; optional details&lt;br /&gt;
	--				 options.low&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return table; whitespace-only values as false&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 TemplatePar.downcase()&lt;br /&gt;
	--	 mw.getCurrentFrame()&lt;br /&gt;
	--	 frame:getParent()&lt;br /&gt;
	local g, k, v&lt;br /&gt;
	local r = { }&lt;br /&gt;
	if options.low then&lt;br /&gt;
		g = TemplatePar.downcase( options )&lt;br /&gt;
	else&lt;br /&gt;
		g = mw.getCurrentFrame()&lt;br /&gt;
		if light then&lt;br /&gt;
			g = g:getParent()&lt;br /&gt;
		end&lt;br /&gt;
		g = g.args&lt;br /&gt;
	end&lt;br /&gt;
	if type( g ) == &amp;quot;table&amp;quot;  then&lt;br /&gt;
		r = { }&lt;br /&gt;
		for k, v in pairs( g ) do&lt;br /&gt;
			if type( v ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
				if v:match( &amp;quot;^%s*$&amp;quot; ) then&lt;br /&gt;
					v = false&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				v = false&lt;br /&gt;
			end&lt;br /&gt;
			if type( k ) == &amp;quot;number&amp;quot; then&lt;br /&gt;
				k = tostring( k )&lt;br /&gt;
			end&lt;br /&gt;
			r[ k ] = v&lt;br /&gt;
		end -- for k, v&lt;br /&gt;
	else&lt;br /&gt;
		r = g&lt;br /&gt;
	end&lt;br /&gt;
	return r&lt;br /&gt;
end -- fetch()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function figure( append, options )&lt;br /&gt;
	-- Extend options by rule from #invoke strings&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 append   -- string or nil; requested rule&lt;br /&gt;
	--	 options  --  table; details&lt;br /&gt;
	--				  ++ .key&lt;br /&gt;
	--				  ++ .pattern&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return sequence table&lt;br /&gt;
	local r = options&lt;br /&gt;
	if type( append ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
		local story = mw.text.trim( append )&lt;br /&gt;
		local sub   = story:match( &amp;quot;^/(.*%S)/$&amp;quot; )&lt;br /&gt;
		if type( sub ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
			sub			 = sub:gsub( &amp;quot;%%!&amp;quot;, &amp;quot;|&amp;quot; )&lt;br /&gt;
			sub			 = sub:gsub( &amp;quot;%%%(%(&amp;quot;, &amp;quot;{{&amp;quot; )&lt;br /&gt;
			sub			 = sub:gsub( &amp;quot;%%%)%)&amp;quot;, &amp;quot;}}&amp;quot; )&lt;br /&gt;
			options.pattern = sub&lt;br /&gt;
			options.key	 = nil&lt;br /&gt;
		else&lt;br /&gt;
			options.key	 = story&lt;br /&gt;
			options.pattern = nil&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return r&lt;br /&gt;
end -- figure()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function fill( specified )&lt;br /&gt;
	-- Split requirement string separated by &amp;#039;=&amp;#039;&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 specified  -- string or nil; requested parameter set&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return sequence table&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 mw.text.split()&lt;br /&gt;
	local r&lt;br /&gt;
	if specified then&lt;br /&gt;
		local i, s&lt;br /&gt;
		r = mw.text.split( specified, &amp;quot;%s*=%s*&amp;quot; )&lt;br /&gt;
		for i = #r, 1, -1 do&lt;br /&gt;
			s = r[ i ]&lt;br /&gt;
			if #s == 0 then&lt;br /&gt;
				table.remove( r, i )&lt;br /&gt;
			end&lt;br /&gt;
		end -- for i, -1&lt;br /&gt;
	else&lt;br /&gt;
		r = { }&lt;br /&gt;
	end&lt;br /&gt;
	return r&lt;br /&gt;
end -- fill()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function finalize( submit, options, frame )&lt;br /&gt;
	-- Finalize message&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 submit   -- string or false or nil; non-empty error message&lt;br /&gt;
	--	 options  -- table or nil; optional details&lt;br /&gt;
	--				 options.format&lt;br /&gt;
	--				 options.preview&lt;br /&gt;
	--				 options.cat&lt;br /&gt;
	--				 options.template&lt;br /&gt;
	--	 frame	-- object, or false&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return string or false&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 factory()&lt;br /&gt;
	local r = false&lt;br /&gt;
	if submit then&lt;br /&gt;
		local opt, s&lt;br /&gt;
		local lazy = false&lt;br /&gt;
		local show = false&lt;br /&gt;
		if type( options ) == &amp;quot;table&amp;quot; then&lt;br /&gt;
			opt  = options&lt;br /&gt;
			show = opt.format&lt;br /&gt;
			lazy = ( show == &amp;quot;&amp;quot;  or  show == &amp;quot;0&amp;quot;  or  show == &amp;quot;-&amp;quot; )&lt;br /&gt;
			s	= opt.preview&lt;br /&gt;
			if type( s ) == &amp;quot;string&amp;quot;  and&lt;br /&gt;
				s ~= &amp;quot;&amp;quot;  and  s ~= &amp;quot;0&amp;quot;  and  s ~= &amp;quot;-&amp;quot; then&lt;br /&gt;
				if lazy then&lt;br /&gt;
					show = &amp;quot;&amp;quot;&lt;br /&gt;
					lazy = false&lt;br /&gt;
				end&lt;br /&gt;
				frame = frame or mw.getCurrentFrame()&lt;br /&gt;
				if frame:preprocess( &amp;quot;{{REVISIONID}}&amp;quot; ) == &amp;quot;&amp;quot; then&lt;br /&gt;
					if s == &amp;quot;1&amp;quot; then&lt;br /&gt;
						show = &amp;quot;*&amp;quot;&lt;br /&gt;
					else&lt;br /&gt;
						show = s&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			opt = { }&lt;br /&gt;
		end&lt;br /&gt;
		if lazy then&lt;br /&gt;
			if not opt.cat then&lt;br /&gt;
				r = string.format( &amp;quot;%s %s&amp;quot;,&lt;br /&gt;
								   submit,  factory( &amp;quot;noMSGnoCAT&amp;quot; ) )&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			r = submit&lt;br /&gt;
		end&lt;br /&gt;
		if r  and  not lazy then&lt;br /&gt;
			local i&lt;br /&gt;
			if not show  or  show == &amp;quot;*&amp;quot; then&lt;br /&gt;
				show = &amp;quot;&amp;lt;span class=\&amp;quot;error\&amp;quot;&amp;gt;@@@&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
			end&lt;br /&gt;
			i = show:find( &amp;quot;@@@&amp;quot;, 1, true )&lt;br /&gt;
			if i then&lt;br /&gt;
				-- No gsub() since r might contain &amp;quot;%3&amp;quot; (e.g. URL)&lt;br /&gt;
				r = string.format( &amp;quot;%s%s%s&amp;quot;,&lt;br /&gt;
								   show:sub( 1,  i - 1 ),&lt;br /&gt;
								   r,&lt;br /&gt;
								   show:sub( i + 3 ) )&lt;br /&gt;
			else&lt;br /&gt;
				r = show&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		s = opt.cat&lt;br /&gt;
		if type( s ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
			if opt.errNS then&lt;br /&gt;
				local ns = mw.title.getCurrentTitle().namespace&lt;br /&gt;
				local st = type( opt.errNS )&lt;br /&gt;
				if st == &amp;quot;string&amp;quot; then&lt;br /&gt;
					local space  = string.format( &amp;quot;.*%%s%d%%s.*&amp;quot;, ns )&lt;br /&gt;
					local spaces = string.format( &amp;quot; %s &amp;quot;, opt.errNS )&lt;br /&gt;
					if spaces:match( space ) then&lt;br /&gt;
						opt.errNS = false&lt;br /&gt;
					end&lt;br /&gt;
				elseif st == &amp;quot;table&amp;quot; then&lt;br /&gt;
					for i = 1, #opt.errNS do&lt;br /&gt;
						if opt.errNS[ i ] == ns then&lt;br /&gt;
							opt.errNS = false&lt;br /&gt;
							break	-- for i&lt;br /&gt;
						end&lt;br /&gt;
					end -- for i&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			if opt.errNS then&lt;br /&gt;
				r = &amp;quot;&amp;quot;&lt;br /&gt;
			else&lt;br /&gt;
				r = r or &amp;quot;&amp;quot;&lt;br /&gt;
				if s:find( &amp;quot;@@@&amp;quot; ) then&lt;br /&gt;
					if type( opt.template ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
						s = s:gsub( &amp;quot;@@@&amp;quot;, opt.template )&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
				local i&lt;br /&gt;
				local cats = mw.text.split( s, &amp;quot;%s*#%s*&amp;quot; )&lt;br /&gt;
				for i = 1, #cats do&lt;br /&gt;
					s = mw.text.trim( cats[ i ] )&lt;br /&gt;
					if #s &amp;gt; 0 then&lt;br /&gt;
						r = string.format( &amp;quot;%s[[Category:%s]]&amp;quot;, r, s )&lt;br /&gt;
					end&lt;br /&gt;
				end -- for i&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return r&lt;br /&gt;
end -- finalize()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function finder( haystack, needle )&lt;br /&gt;
	-- Find needle in haystack sequence&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 haystack  -- table; sequence of key names, downcased if low&lt;br /&gt;
	--	 needle	-- any; key name&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return true iff found&lt;br /&gt;
	local i&lt;br /&gt;
	for i = 1, #haystack do&lt;br /&gt;
		if haystack[ i ] == needle then&lt;br /&gt;
			return true&lt;br /&gt;
		end&lt;br /&gt;
	end -- for i&lt;br /&gt;
	return false&lt;br /&gt;
end -- finder()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function fix( valid, duty, got, options )&lt;br /&gt;
	-- Perform parameter analysis&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 valid	-- table; unique sequence of known parameters&lt;br /&gt;
	--	 duty	 -- table; sequence of mandatory parameters&lt;br /&gt;
	--	 got	  -- table; sequence of current parameters&lt;br /&gt;
	--	 options  -- table or nil; optional details&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return string as configured; empty if valid&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 finder()&lt;br /&gt;
	--	 fault()&lt;br /&gt;
	--	 failure()&lt;br /&gt;
	--	 fed()&lt;br /&gt;
	local k, v&lt;br /&gt;
	local r = false&lt;br /&gt;
	for k, v in pairs( got ) do&lt;br /&gt;
		if not finder( valid, k ) then&lt;br /&gt;
			r = fault( r, k )&lt;br /&gt;
		end&lt;br /&gt;
	end -- for k, v&lt;br /&gt;
	if r then&lt;br /&gt;
		r = failure( &amp;quot;unknown&amp;quot;,&lt;br /&gt;
					 string.format( &amp;quot;&amp;#039;%s&amp;#039;&amp;quot;, r ),&lt;br /&gt;
					 options )&lt;br /&gt;
	else -- all names valid&lt;br /&gt;
		local i, s&lt;br /&gt;
		for i = 1, #duty do&lt;br /&gt;
			s = duty[ i ]&lt;br /&gt;
			if not fed( got, s ) then&lt;br /&gt;
				r = fault( r, s )&lt;br /&gt;
			end&lt;br /&gt;
		end -- for i&lt;br /&gt;
		if r then&lt;br /&gt;
			r = failure( &amp;quot;undefined&amp;quot;, r, options )&lt;br /&gt;
		else -- all mandatory present&lt;br /&gt;
			for i = 1, #duty do&lt;br /&gt;
				s = duty[ i ]&lt;br /&gt;
				if not got[ s ] then&lt;br /&gt;
					r = fault( r, s )&lt;br /&gt;
				end&lt;br /&gt;
			end -- for i&lt;br /&gt;
			if r then&lt;br /&gt;
				r = failure( &amp;quot;empty&amp;quot;, r, options )&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return r&lt;br /&gt;
end -- fix()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function flat( collection, options )&lt;br /&gt;
	-- Return all table elements with downcased string&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 collection  -- table; k=v pairs&lt;br /&gt;
	--	 options	 -- table or nil; optional messaging details&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return table, may be empty; or string with error message.&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 mw.ustring.lower()&lt;br /&gt;
	--	 fault()&lt;br /&gt;
	--	 failure()&lt;br /&gt;
	local k, v&lt;br /&gt;
	local r = { }&lt;br /&gt;
	local e = false&lt;br /&gt;
	for k, v in pairs( collection ) do&lt;br /&gt;
		if type ( k ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
			k = mw.ustring.lower( k )&lt;br /&gt;
			if r[ k ] then&lt;br /&gt;
				e = fault( e, k )&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		r[ k ] = v&lt;br /&gt;
	end -- for k, v&lt;br /&gt;
	if e then&lt;br /&gt;
		r = failure( &amp;quot;multiSpell&amp;quot;, e, options )&lt;br /&gt;
	end&lt;br /&gt;
	return r&lt;br /&gt;
end -- flat()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function fold( options )&lt;br /&gt;
	-- Merge two tables, create new sequence if both not empty&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 options  -- table; details&lt;br /&gt;
	--				 options.mandatory   sequence to keep unchanged&lt;br /&gt;
	--				 options.optional	sequence to be appended&lt;br /&gt;
	--				 options.low		 downcased expected&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return merged table, or message string if error&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 finder()&lt;br /&gt;
	--	 fault()&lt;br /&gt;
	--	 failure()&lt;br /&gt;
	--	 flat()&lt;br /&gt;
	local i, e, r, s&lt;br /&gt;
	local base   = options.mandatory&lt;br /&gt;
	local extend = options.optional&lt;br /&gt;
	if #base == 0 then&lt;br /&gt;
		if #extend == 0 then&lt;br /&gt;
			r = { }&lt;br /&gt;
		else&lt;br /&gt;
			r = extend&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		if #extend == 0 then&lt;br /&gt;
			r = base&lt;br /&gt;
		else&lt;br /&gt;
			e = false&lt;br /&gt;
			for i = 1, #extend do&lt;br /&gt;
				s = extend[ i ]&lt;br /&gt;
				if finder( base, s ) then&lt;br /&gt;
					e = fault( e, s )&lt;br /&gt;
				end&lt;br /&gt;
			end -- for i&lt;br /&gt;
			if e then&lt;br /&gt;
				r = failure( &amp;quot;dupOpt&amp;quot;, e, options )&lt;br /&gt;
			else&lt;br /&gt;
				r = { }&lt;br /&gt;
				for i = 1, #base do&lt;br /&gt;
					table.insert( r, base[ i ] )&lt;br /&gt;
				end -- for i&lt;br /&gt;
				for i = 1, #extend do&lt;br /&gt;
					table.insert( r, extend[ i ] )&lt;br /&gt;
				end -- for i&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if options.low  and  type( r ) == &amp;quot;table&amp;quot; then&lt;br /&gt;
		r = flat( r, options )&lt;br /&gt;
	end&lt;br /&gt;
	return r&lt;br /&gt;
end -- fold()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function form( light, options, frame )&lt;br /&gt;
	-- Run parameter analysis on current environment&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 light	-- true: template transclusion;  false: #invoke&lt;br /&gt;
	--	 options  -- table or nil; optional details&lt;br /&gt;
	--				 options.mandatory&lt;br /&gt;
	--				 options.optional&lt;br /&gt;
	--	 frame	-- object, or false&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return string with error message as configured;&lt;br /&gt;
	--			false if valid&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 fold()&lt;br /&gt;
	--	 fetch()&lt;br /&gt;
	--	 fix()&lt;br /&gt;
	--	 finalize()&lt;br /&gt;
	local duty, r&lt;br /&gt;
	if type( options ) == &amp;quot;table&amp;quot; then&lt;br /&gt;
		if type( options.mandatory ) ~= &amp;quot;table&amp;quot; then&lt;br /&gt;
			options.mandatory = { }&lt;br /&gt;
		end&lt;br /&gt;
		duty = options.mandatory&lt;br /&gt;
		if type( options.optional ) ~= &amp;quot;table&amp;quot; then&lt;br /&gt;
			options.optional = { }&lt;br /&gt;
		end&lt;br /&gt;
		r = fold( options )&lt;br /&gt;
	else&lt;br /&gt;
		options = { }&lt;br /&gt;
		duty	= { }&lt;br /&gt;
		r	   = { }&lt;br /&gt;
	end&lt;br /&gt;
	if type( r ) == &amp;quot;table&amp;quot; then&lt;br /&gt;
		local got = fetch( light, options )&lt;br /&gt;
		if type( got ) == &amp;quot;table&amp;quot; then&lt;br /&gt;
			r = fix( r, duty, got, options )&lt;br /&gt;
		else&lt;br /&gt;
			r = got&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return finalize( r, options, frame )&lt;br /&gt;
end -- form()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function format( analyze, options )&lt;br /&gt;
	-- Check validity of a value&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 analyze  -- string to be analyzed&lt;br /&gt;
	--	 options  -- table or nil; optional details&lt;br /&gt;
	--				 options.say&lt;br /&gt;
	--				 options.min&lt;br /&gt;
	--				 options.max&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return string with error message as configured;&lt;br /&gt;
	--			false if valid or no answer permitted&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 feasible()&lt;br /&gt;
	--	 failure()&lt;br /&gt;
	local r = feasible( analyze, options, false )&lt;br /&gt;
	local show&lt;br /&gt;
	if options.min  and  not r then&lt;br /&gt;
		if type( options.min ) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			if type( options.max ) == &amp;quot;number&amp;quot; then&lt;br /&gt;
				if options.max &amp;lt; options.min then&lt;br /&gt;
					r = failure( &amp;quot;minmax&amp;quot;,&lt;br /&gt;
								 string.format( &amp;quot;%d &amp;gt; %d&amp;quot;,&lt;br /&gt;
												options.min,&lt;br /&gt;
												options.max ),&lt;br /&gt;
								 options )&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			if #analyze &amp;lt; options.min  and  not r then&lt;br /&gt;
				show = &amp;quot; &amp;lt;&amp;quot; .. options.min&lt;br /&gt;
				if options.say then&lt;br /&gt;
					show = string.format( &amp;quot;%s &amp;#039;%s&amp;#039;&amp;quot;, show, options.say )&lt;br /&gt;
				end&lt;br /&gt;
				r = failure( &amp;quot;tooShort&amp;quot;, show, options )&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			r = failure( &amp;quot;invalidPar&amp;quot;, &amp;quot;min&amp;quot;, options )&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if options.max  and  not r then&lt;br /&gt;
		if type( options.max ) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			if #analyze &amp;gt; options.max then&lt;br /&gt;
				show = &amp;quot; &amp;gt;&amp;quot; .. options.max&lt;br /&gt;
				if options.say then&lt;br /&gt;
					show = string.format( &amp;quot;%s &amp;#039;%s&amp;#039;&amp;quot;, show, options.say )&lt;br /&gt;
				end&lt;br /&gt;
				r = failure( &amp;quot;tooLong&amp;quot;, show, options )&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			r = failure( &amp;quot;invalidPar&amp;quot;, &amp;quot;max&amp;quot;, options )&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return r&lt;br /&gt;
end -- format()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function formatted( assignment, access, options )&lt;br /&gt;
	-- Check validity of one particular parameter in a collection&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 assignment  -- collection&lt;br /&gt;
	--	 access	  -- id of parameter in collection&lt;br /&gt;
	--	 options	 -- table or nil; optional details&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return string with error message as configured;&lt;br /&gt;
	--			false if valid or no answer permitted&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 mw.text.trim() &lt;br /&gt;
	--	 format()&lt;br /&gt;
	--	 failure()&lt;br /&gt;
	local r = false&lt;br /&gt;
	if type( assignment ) == &amp;quot;table&amp;quot; then&lt;br /&gt;
		local story = assignment.args[ access ] or &amp;quot;&amp;quot;&lt;br /&gt;
		if type( access ) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			story = mw.text.trim( story ) &lt;br /&gt;
		end&lt;br /&gt;
		if type( options ) ~= &amp;quot;table&amp;quot; then&lt;br /&gt;
			options = { }&lt;br /&gt;
		end&lt;br /&gt;
		options.say = access&lt;br /&gt;
		r = format( story, options )&lt;br /&gt;
	end&lt;br /&gt;
	return r&lt;br /&gt;
end -- formatted()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function furnish( frame, action )&lt;br /&gt;
	-- Prepare #invoke evaluation of .assert() or .valid()&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 frame	-- object; #invoke environment&lt;br /&gt;
	--	 action   -- &amp;quot;assert&amp;quot; or &amp;quot;valid&amp;quot;&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return string with error message or &amp;quot;&amp;quot;&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 form()&lt;br /&gt;
	--	 failure()&lt;br /&gt;
	--	 finalize()&lt;br /&gt;
	--	 TemplatePar.valid()&lt;br /&gt;
	--	 TemplatePar.assert()&lt;br /&gt;
	local options = { mandatory = { &amp;quot;1&amp;quot; },&lt;br /&gt;
					  optional  = { &amp;quot;2&amp;quot;,&lt;br /&gt;
									&amp;quot;cat&amp;quot;,&lt;br /&gt;
									&amp;quot;errNS&amp;quot;,&lt;br /&gt;
									&amp;quot;low&amp;quot;,&lt;br /&gt;
									&amp;quot;max&amp;quot;,&lt;br /&gt;
									&amp;quot;min&amp;quot;,&lt;br /&gt;
									&amp;quot;format&amp;quot;,&lt;br /&gt;
									&amp;quot;preview&amp;quot;,&lt;br /&gt;
									&amp;quot;template&amp;quot; },&lt;br /&gt;
					  template  = string.format( &amp;quot;&amp;amp;#35;invoke:%s|%s|&amp;quot;,&lt;br /&gt;
												 &amp;quot;TemplatePar&amp;quot;,&lt;br /&gt;
												 action )&lt;br /&gt;
					}&lt;br /&gt;
	local r	   = form( false, options, frame )&lt;br /&gt;
	if not r then&lt;br /&gt;
		local s&lt;br /&gt;
		options = { cat	  = frame.args.cat,&lt;br /&gt;
					errNS	= frame.args.errNS,&lt;br /&gt;
					low	  = frame.args.low,&lt;br /&gt;
					format   = frame.args.format,&lt;br /&gt;
					preview  = frame.args.preview,&lt;br /&gt;
					template = frame.args.template&lt;br /&gt;
				  }&lt;br /&gt;
		options = figure( frame.args[ 2 ], options )&lt;br /&gt;
		if type( frame.args.min ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
			s = frame.args.min:match( &amp;quot;^%s*([0-9]+)%s*$&amp;quot; )&lt;br /&gt;
			if s then&lt;br /&gt;
				options.min = tonumber( s )&lt;br /&gt;
			else&lt;br /&gt;
				r = failure( &amp;quot;invalidPar&amp;quot;,&lt;br /&gt;
							 &amp;quot;min=&amp;quot; .. frame.args.min,&lt;br /&gt;
							 options )&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if type( frame.args.max ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
			s = frame.args.max:match( &amp;quot;^%s*([1-9][0-9]*)%s*$&amp;quot; )&lt;br /&gt;
			if s then&lt;br /&gt;
				options.max = tonumber( s )&lt;br /&gt;
			else&lt;br /&gt;
				r = failure( &amp;quot;invalidPar&amp;quot;,&lt;br /&gt;
							 &amp;quot;max=&amp;quot; .. frame.args.max,&lt;br /&gt;
							 options )&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if r then&lt;br /&gt;
			r = finalize( r, options, frame )&lt;br /&gt;
		else&lt;br /&gt;
			s = frame.args[ 1 ] or &amp;quot;&amp;quot;&lt;br /&gt;
			r = tonumber( s )&lt;br /&gt;
			if ( r ) then&lt;br /&gt;
				s = r&lt;br /&gt;
			end&lt;br /&gt;
			if action == &amp;quot;valid&amp;quot; then&lt;br /&gt;
				r = TemplatePar.valid( s, options, frame )&lt;br /&gt;
			elseif action == &amp;quot;assert&amp;quot; then&lt;br /&gt;
				r = TemplatePar.assert( s, &amp;quot;&amp;quot;, options )&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return r or &amp;quot;&amp;quot;&lt;br /&gt;
end -- furnish()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
TemplatePar.assert = function ( analyze, append, options )&lt;br /&gt;
	-- Perform parameter analysis on a single string&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 analyze  -- string to be analyzed&lt;br /&gt;
	--	 append   -- string: append error message, prepending &amp;lt;br /&amp;gt;&lt;br /&gt;
	--				 false or nil: throw error with message&lt;br /&gt;
	--	 options  -- table; optional details&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return string with error message as configured;&lt;br /&gt;
	--			false if valid&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 format()&lt;br /&gt;
	local r = format( analyze, options )&lt;br /&gt;
	if ( r ) then&lt;br /&gt;
		if ( type( append ) == &amp;quot;string&amp;quot; ) then&lt;br /&gt;
			if ( append ~= &amp;quot;&amp;quot; ) then&lt;br /&gt;
				r = string.format( &amp;quot;%s&amp;lt;br /&amp;gt;%s&amp;quot;, append, r )&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			error( r, 0 )&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return r&lt;br /&gt;
end -- TemplatePar.assert()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
TemplatePar.check = function ( options )&lt;br /&gt;
	-- Run parameter analysis on current template environment&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 options  -- table or nil; optional details&lt;br /&gt;
	--				 options.mandatory&lt;br /&gt;
	--				 options.optional&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return string with error message as configured;&lt;br /&gt;
	--			false if valid&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 form()&lt;br /&gt;
	return form( true, options, false )&lt;br /&gt;
end -- TemplatePar.check()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
TemplatePar.count = function ()&lt;br /&gt;
	-- Return number of template parameters&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return number, starting at 0&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 mw.getCurrentFrame()&lt;br /&gt;
	--	 frame:getParent()&lt;br /&gt;
	local k, v&lt;br /&gt;
	local r = 0&lt;br /&gt;
	local t = mw.getCurrentFrame():getParent()&lt;br /&gt;
	local o = t.args&lt;br /&gt;
	for k, v in pairs( o ) do&lt;br /&gt;
		r = r + 1&lt;br /&gt;
	end -- for k, v&lt;br /&gt;
	return r&lt;br /&gt;
end -- TemplatePar.count()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
TemplatePar.countNotEmpty = function ()&lt;br /&gt;
	-- Return number of template parameters with more than whitespace&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return number, starting at 0&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 mw.getCurrentFrame()&lt;br /&gt;
	--	 frame:getParent()&lt;br /&gt;
	local k, v&lt;br /&gt;
	local r = 0&lt;br /&gt;
	local t = mw.getCurrentFrame():getParent()&lt;br /&gt;
	local o = t.args&lt;br /&gt;
	for k, v in pairs( o ) do&lt;br /&gt;
		if not v:match( &amp;quot;^%s*$&amp;quot; ) then&lt;br /&gt;
			r = r + 1&lt;br /&gt;
		end&lt;br /&gt;
	end -- for k, v&lt;br /&gt;
	return r&lt;br /&gt;
end -- TemplatePar.countNotEmpty()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
TemplatePar.downcase = function ( options )&lt;br /&gt;
	-- Return all template parameters with downcased name&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 options  -- table or nil; optional messaging details&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return table, may be empty; or string with error message.&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 mw.getCurrentFrame()&lt;br /&gt;
	--	 frame:getParent()&lt;br /&gt;
	--	 flat()&lt;br /&gt;
	local t = mw.getCurrentFrame():getParent()&lt;br /&gt;
	return flat( t.args, options )&lt;br /&gt;
end -- TemplatePar.downcase()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
TemplatePar.valid = function ( access, options, frame )&lt;br /&gt;
	-- Check validity of one particular template parameter&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 access   -- id of parameter in template transclusion&lt;br /&gt;
	--				 string or number&lt;br /&gt;
	--	 options  -- table or nil; optional details&lt;br /&gt;
	--	 frame	-- object; #invoke environment&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return string with error message as configured;&lt;br /&gt;
	--			false if valid or no answer permitted&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 mw.text.trim()&lt;br /&gt;
	--	 TemplatePar.downcase()&lt;br /&gt;
	--	 frame:getParent()&lt;br /&gt;
	--	 formatted()&lt;br /&gt;
	--	 failure()&lt;br /&gt;
	--	 finalize()&lt;br /&gt;
	local r = type( access )&lt;br /&gt;
	if r == &amp;quot;string&amp;quot; then&lt;br /&gt;
		r = mw.text.trim( access )&lt;br /&gt;
		if #r == 0 then&lt;br /&gt;
			r = false&lt;br /&gt;
		end&lt;br /&gt;
	elseif r == &amp;quot;number&amp;quot; then&lt;br /&gt;
		r = access&lt;br /&gt;
	else&lt;br /&gt;
		r = false&lt;br /&gt;
	end&lt;br /&gt;
	if r then&lt;br /&gt;
		local params&lt;br /&gt;
		if type( options ) ~= &amp;quot;table&amp;quot; then&lt;br /&gt;
			options = { }&lt;br /&gt;
		end&lt;br /&gt;
		if options.low then&lt;br /&gt;
			params = TemplatePar.downcase( options )&lt;br /&gt;
		else&lt;br /&gt;
			params = frame:getParent()&lt;br /&gt;
		end&lt;br /&gt;
		r = formatted( params, access, options )&lt;br /&gt;
	else&lt;br /&gt;
		r = failure( &amp;quot;noname&amp;quot;, false, options )&lt;br /&gt;
	end&lt;br /&gt;
	return finalize( r, options, frame )&lt;br /&gt;
end -- TemplatePar.valid()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
TemplatePar.verify = function ( options )&lt;br /&gt;
	-- Perform #invoke parameter analysis&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 options  -- table or nil; optional details&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return string with error message as configured;&lt;br /&gt;
	--			false if valid&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 form()&lt;br /&gt;
	return form( false, options, false )&lt;br /&gt;
end -- TemplatePar.verify()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Provide external access&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function p.assert( frame )&lt;br /&gt;
	-- Perform parameter analysis on some single string&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 frame  -- object; #invoke environment&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return string with error message or &amp;quot;&amp;quot;&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 furnish()&lt;br /&gt;
	return furnish( frame, &amp;quot;assert&amp;quot; )&lt;br /&gt;
end -- .assert()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function p.check( frame )&lt;br /&gt;
	-- Check validity of template parameters&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 frame  -- object; #invoke environment&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return string with error message or &amp;quot;&amp;quot;&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 form()&lt;br /&gt;
	--	 fill()&lt;br /&gt;
	local options = { optional  = { &amp;quot;all&amp;quot;,&lt;br /&gt;
									&amp;quot;opt&amp;quot;,&lt;br /&gt;
									&amp;quot;cat&amp;quot;,&lt;br /&gt;
									&amp;quot;errNS&amp;quot;,&lt;br /&gt;
									&amp;quot;low&amp;quot;,&lt;br /&gt;
									&amp;quot;format&amp;quot;,&lt;br /&gt;
									&amp;quot;preview&amp;quot;,&lt;br /&gt;
									&amp;quot;template&amp;quot; },&lt;br /&gt;
					  template  = &amp;quot;&amp;amp;#35;invoke:TemplatePar|check|&amp;quot;&lt;br /&gt;
					}&lt;br /&gt;
	local r = form( false, options, frame )&lt;br /&gt;
	if not r then&lt;br /&gt;
		options = { mandatory = fill( frame.args.all ),&lt;br /&gt;
					optional  = fill( frame.args.opt ),&lt;br /&gt;
					cat	   = frame.args.cat,&lt;br /&gt;
					errNS	 = frame.args.errNS,&lt;br /&gt;
					low	   = frame.args.low,&lt;br /&gt;
					format	= frame.args.format,&lt;br /&gt;
					preview   = frame.args.preview,&lt;br /&gt;
					template  = frame.args.template&lt;br /&gt;
				  }&lt;br /&gt;
		r	   = form( true, options, frame )&lt;br /&gt;
	end&lt;br /&gt;
	return r or &amp;quot;&amp;quot;&lt;br /&gt;
end -- .check()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function p.count( frame )&lt;br /&gt;
	-- Count number of template parameters&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return string with digits including &amp;quot;0&amp;quot;&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 TemplatePar.count()&lt;br /&gt;
	return tostring( TemplatePar.count() )&lt;br /&gt;
end -- .count()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function p.countNotEmpty( frame )&lt;br /&gt;
	-- Count number of template parameters which are not empty&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return string with digits including &amp;quot;0&amp;quot;&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 TemplatePar.countNotEmpty()&lt;br /&gt;
	return tostring( TemplatePar.countNotEmpty() )&lt;br /&gt;
end -- .countNotEmpty()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function p.match( frame )&lt;br /&gt;
	-- Combined analysis of parameters and their values&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return string with error message or &amp;quot;&amp;quot;&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 mw.text.trim()&lt;br /&gt;
	--	 mw.ustring.lower()&lt;br /&gt;
	--	 failure()&lt;br /&gt;
	--	 form()&lt;br /&gt;
	--	 TemplatePar.downcase()&lt;br /&gt;
	--	 figure()&lt;br /&gt;
	--	 feasible()&lt;br /&gt;
	--	 fault()&lt;br /&gt;
	--	 finalize()&lt;br /&gt;
	local r = false&lt;br /&gt;
	local options = { cat	  = frame.args.cat,&lt;br /&gt;
					  errNS	= frame.args.errNS,&lt;br /&gt;
					  low	  = frame.args.low,&lt;br /&gt;
					  format   = frame.args.format,&lt;br /&gt;
					  preview  = frame.args.preview,&lt;br /&gt;
					  template = frame.args.template&lt;br /&gt;
					}&lt;br /&gt;
	local k, v, s&lt;br /&gt;
	local params = { }&lt;br /&gt;
	for k, v in pairs( frame.args ) do&lt;br /&gt;
		if type( k ) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			s, v = v:match( &amp;quot;^ *([^=]+) *= *(%S.*%S*) *$&amp;quot; )&lt;br /&gt;
			if s then&lt;br /&gt;
				s = mw.text.trim( s )&lt;br /&gt;
				if s == &amp;quot;&amp;quot; then&lt;br /&gt;
					s = false&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			if s then&lt;br /&gt;
				if options.low then&lt;br /&gt;
					s = mw.ustring.lower( s )&lt;br /&gt;
				end&lt;br /&gt;
				if params[ s ] then&lt;br /&gt;
					s = params[ s ]&lt;br /&gt;
					s[ #s + 1 ] = v&lt;br /&gt;
				else&lt;br /&gt;
					params[ s ] = { v }&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				r = failure( &amp;quot;invalidPar&amp;quot;,  tostring( k ),  options )&lt;br /&gt;
				break -- for k, v&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end -- for k, v&lt;br /&gt;
	if not r then&lt;br /&gt;
		s = { }&lt;br /&gt;
		for k, v in pairs( params ) do&lt;br /&gt;
			s[ #s + 1 ] = k&lt;br /&gt;
		end -- for k, v&lt;br /&gt;
		options.optional = s&lt;br /&gt;
		r = form( true, options, frame )&lt;br /&gt;
	end&lt;br /&gt;
	if not r then&lt;br /&gt;
		local errMiss, errValues, lack, rule&lt;br /&gt;
		local targs = frame:getParent().args&lt;br /&gt;
		options.optional = nil&lt;br /&gt;
		if options.low then&lt;br /&gt;
			targs = TemplatePar.downcase()&lt;br /&gt;
		else&lt;br /&gt;
			targs = frame:getParent().args&lt;br /&gt;
		end&lt;br /&gt;
		errMiss   = false&lt;br /&gt;
		errValues = false&lt;br /&gt;
		for k, v in pairs( params ) do&lt;br /&gt;
			options.say = k&lt;br /&gt;
			errValue	= false&lt;br /&gt;
			s = targs[ k ]&lt;br /&gt;
			if s then&lt;br /&gt;
				if s == &amp;quot;&amp;quot; then&lt;br /&gt;
					lack = true&lt;br /&gt;
				else&lt;br /&gt;
					lack = false&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				s	= &amp;quot;&amp;quot;&lt;br /&gt;
				lack = true&lt;br /&gt;
			end&lt;br /&gt;
			for r, rule in pairs( v ) do&lt;br /&gt;
				options = figure( rule, options )&lt;br /&gt;
				r	   = feasible( s, options, true )&lt;br /&gt;
				if r then&lt;br /&gt;
					if lack then&lt;br /&gt;
						if errMiss then&lt;br /&gt;
							errMiss = string.format( &amp;quot;%s, &amp;#039;%s&amp;#039;&amp;quot;,&lt;br /&gt;
													 errMiss, k )&lt;br /&gt;
						else&lt;br /&gt;
							errMiss = string.format( &amp;quot;&amp;#039;%s&amp;#039;&amp;quot;, k )&lt;br /&gt;
						end&lt;br /&gt;
					elseif not errMiss then&lt;br /&gt;
						errValues = fault( errValues, r )&lt;br /&gt;
					end&lt;br /&gt;
					break -- for r, rule&lt;br /&gt;
				end&lt;br /&gt;
			end -- for s, rule&lt;br /&gt;
		end -- for k, v&lt;br /&gt;
		r = ( errMiss or errValues )&lt;br /&gt;
		if r then&lt;br /&gt;
			if errMiss then&lt;br /&gt;
				r = failure( &amp;quot;undefined&amp;quot;, errMiss, options )&lt;br /&gt;
			else&lt;br /&gt;
				r = failure( &amp;quot;invalid&amp;quot;, errValues, options )&lt;br /&gt;
			end&lt;br /&gt;
			r = finalize( r, options, frame )&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return r or &amp;quot;&amp;quot;&lt;br /&gt;
end -- .match()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function p.valid( frame )&lt;br /&gt;
	-- Check validity of one particular template parameter&lt;br /&gt;
	-- Precondition:&lt;br /&gt;
	--	 frame  -- object; #invoke environment&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return string with error message or &amp;quot;&amp;quot;&lt;br /&gt;
	-- Uses:&lt;br /&gt;
	--	 furnish()&lt;br /&gt;
	return furnish( frame, &amp;quot;valid&amp;quot; )&lt;br /&gt;
end -- .valid()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function p.TemplatePar()&lt;br /&gt;
	-- Retrieve function access for modules&lt;br /&gt;
	-- Postcondition:&lt;br /&gt;
	--	 Return table with functions&lt;br /&gt;
	return TemplatePar&lt;br /&gt;
end -- .TemplatePar()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Cellan3</name></author>
	</entry>
</feed>