<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://stockhub.co/index.php?action=history&amp;feed=atom&amp;title=Module%3ASandbox%2Ftrappist_the_monk%2FParameters</id>
	<title>Module:Sandbox/trappist the monk/Parameters - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://stockhub.co/index.php?action=history&amp;feed=atom&amp;title=Module%3ASandbox%2Ftrappist_the_monk%2FParameters"/>
	<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Sandbox/trappist_the_monk/Parameters&amp;action=history"/>
	<updated>2026-04-22T00:29:00Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://stockhub.co/index.php?title=Module:Sandbox/trappist_the_monk/Parameters&amp;diff=146598&amp;oldid=prev</id>
		<title>imported&gt;Trappist the monk at 19:03, 8 February 2021</title>
		<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Sandbox/trappist_the_monk/Parameters&amp;diff=146598&amp;oldid=prev"/>
		<updated>2021-02-08T19:03:59Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;--[[--------------------------&amp;lt; F O R W A R D   D E C L A R A T I O N S &amp;gt;--------------------------------------&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local in_array, is_set, is_wikilink, make_sep_list, select_one, set_message,&lt;br /&gt;
		substitute, wrap_style;			-- functions in Module:Citation/CS1/Utilities&lt;br /&gt;
&lt;br /&gt;
local z;																		-- table of tables defined in Module:Citation/CS1/Utilities&lt;br /&gt;
&lt;br /&gt;
local cfg;																		-- table of configuration tables that are defined in Module:Citation/CS1/Configuration&lt;br /&gt;
local suggestions;&lt;br /&gt;
local whitelist;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; P A G E   S C O P E   V A R I A B L E S &amp;gt;--------------------------------------&lt;br /&gt;
&lt;br /&gt;
declare variables here that have page-wide scope that are not brought in from other modules; that are created&lt;br /&gt;
here and used here&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local added_deprecated_cat;														-- boolean flag so that the category is added only once&lt;br /&gt;
local added_vanc_errs;															-- boolean flag so we only emit one Vancouver error / category&lt;br /&gt;
local Frame;																	-- holds the module&amp;#039;s frame table&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; I S _ V A L I D _ P A R A M E T E R _ V A L U E &amp;gt;------------------------------&lt;br /&gt;
&lt;br /&gt;
!!! TODO : MOVE from main to TO UTILITIES !!!&lt;br /&gt;
used here by namelists_get()&lt;br /&gt;
&lt;br /&gt;
This function is used to validate a parameter&amp;#039;s assigned value for those parameters that have only a limited number&lt;br /&gt;
of allowable values (yes, y, true, live, dead, etc.).  When the parameter value has not been assigned a value (missing&lt;br /&gt;
or empty in the source template) the function returns the value specified by ret_val.  If the parameter value is one&lt;br /&gt;
of the list of allowed values returns the translated value; else, emits an error message and returns the value&lt;br /&gt;
specified by ret_val.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function is_valid_parameter_value (value, name, possible, ret_val)&lt;br /&gt;
	if not is_set (value) then&lt;br /&gt;
		return ret_val;															-- an empty parameter is ok&lt;br /&gt;
	elseif in_array (value, possible) then&lt;br /&gt;
		return cfg.keywords_xlate[value];										-- return translation of parameter keyword&lt;br /&gt;
	else&lt;br /&gt;
		table.insert( z.message_tail, {set_message (&amp;#039;err_invalid_param_val&amp;#039;, {name, value}, true)});	-- not an allowed value so add error message&lt;br /&gt;
		return ret_val;&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; S E L E C T _ A U T H O R _ E D I T O R _ S O U R C E &amp;gt;------------------------&lt;br /&gt;
&lt;br /&gt;
Select one of |authors=, |authorn= / |lastn / firstn=, or |vauthors= as the source of the author name list or&lt;br /&gt;
select one of |editorn= / editor-lastn= / |editor-firstn= or |veditors= as the source of the editor name list.&lt;br /&gt;
&lt;br /&gt;
Only one of these appropriate three will be used.  The hierarchy is: |authorn= (and aliases) highest and |authors= lowest;&lt;br /&gt;
|editorn= (and aliases) highest and |veditors= lowest (support for |editors= withdrawn)&lt;br /&gt;
&lt;br /&gt;
When looking for |authorn= / |editorn= parameters, test |xxxxor1= and |xxxxor2= (and all of their aliases); stops after the second&lt;br /&gt;
test which mimicks the test used in extract_names() when looking for a hole in the author name list.  There may be a better&lt;br /&gt;
way to do this, I just haven&amp;#039;t discovered what that way is.&lt;br /&gt;
&lt;br /&gt;
Emits an error message when more than one xxxxor name source is provided.&lt;br /&gt;
&lt;br /&gt;
In this function, vxxxxors = vauthors or veditors; xxxxors = authors as appropriate.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function select_author_editor_source (vxxxxors, xxxxors, args, list_name)&lt;br /&gt;
	local lastfirst = false;&lt;br /&gt;
	if select_one ( args, cfg.aliases[list_name .. &amp;#039;-Last&amp;#039;], &amp;#039;none&amp;#039;, 1 ) or		-- do this twice in case we have a |first1= without a |last1=; this ...&lt;br /&gt;
		select_one ( args, cfg.aliases[list_name .. &amp;#039;-First&amp;#039;], &amp;#039;none&amp;#039;, 1 ) or		-- ... also catches the case where |first= is used with |vauthors=&lt;br /&gt;
		select_one ( args, cfg.aliases[list_name .. &amp;#039;-Last&amp;#039;], &amp;#039;none&amp;#039;, 2 ) or&lt;br /&gt;
		select_one ( args, cfg.aliases[list_name .. &amp;#039;-First&amp;#039;], &amp;#039;none&amp;#039;, 2 ) then&lt;br /&gt;
			lastfirst = true;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if (is_set (vxxxxors) and true == lastfirst) or					-- these are the three error conditions&lt;br /&gt;
		(is_set (vxxxxors) and is_set (xxxxors)) or&lt;br /&gt;
		(true == lastfirst and is_set (xxxxors)) then&lt;br /&gt;
			local err_name;&lt;br /&gt;
			if &amp;#039;AuthorList&amp;#039; == list_name then									-- figure out which name should be used in error message&lt;br /&gt;
				err_name = &amp;#039;author&amp;#039;;&lt;br /&gt;
			else&lt;br /&gt;
				err_name = &amp;#039;editor&amp;#039;;&lt;br /&gt;
			end&lt;br /&gt;
			table.insert( z.message_tail, {set_message ( &amp;#039;err_redundant_parameters&amp;#039;,&lt;br /&gt;
				{err_name .. &amp;#039;-name-list parameters&amp;#039;}, true ) } );				-- add error message&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if true == lastfirst then return 1 end;										-- return a number indicating which author name source to use&lt;br /&gt;
	if is_set (vxxxxors) then return 2 end;&lt;br /&gt;
	if is_set (xxxxors) then return 3 end;&lt;br /&gt;
	return 1;																	-- no authors so return 1; this allows missing author name test to run in case there is a first without last &lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; N A M E L I S T S _ G E T &amp;gt;----------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function namelists_get (params)&lt;br /&gt;
	local author_etal;&lt;br /&gt;
	local a	= {};																-- authors list from |lastn= / |firstn= pairs or |vauthors=&lt;br /&gt;
	local Authors;&lt;br /&gt;
&lt;br /&gt;
	local NameListStyle = is_valid_parameter_value (params[&amp;#039;NameListStyle&amp;#039;].value, params[&amp;#039;NameListStyle&amp;#039;].origin, cfg.keywords_lists[&amp;#039;name-list-style&amp;#039;], &amp;#039;&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
	do																			-- to limit scope of selected&lt;br /&gt;
		local selected = select_author_editor_source (A[&amp;#039;Vauthors&amp;#039;], A[&amp;#039;Authors&amp;#039;], args, &amp;#039;AuthorList&amp;#039;);&lt;br /&gt;
		if 1 == selected then&lt;br /&gt;
			a, author_etal = extract_names (args, &amp;#039;AuthorList&amp;#039;);				-- fetch author list from |authorn= / |lastn= / |firstn=, |author-linkn=, and |author-maskn=&lt;br /&gt;
		elseif 2 == selected then&lt;br /&gt;
			NameListStyle = &amp;#039;vanc&amp;#039;;											-- override whatever |name-list-style= might be&lt;br /&gt;
			a, author_etal = parse_vauthors_veditors (args, args.vauthors, &amp;#039;AuthorList&amp;#039;);	-- fetch author list from |vauthors=, |author-linkn=, and |author-maskn=&lt;br /&gt;
		elseif 3 == selected then&lt;br /&gt;
			Authors = A[&amp;#039;Authors&amp;#039;];												-- use content of |authors=&lt;br /&gt;
			if &amp;#039;authors&amp;#039; == A:ORIGIN(&amp;#039;Authors&amp;#039;) then							-- but add a maint cat if the parameter is |authors=&lt;br /&gt;
				set_message (&amp;#039;maint_authors&amp;#039;);						-- because use of this parameter is discouraged; what to do about the aliases is a TODO:&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if is_set (params[&amp;#039;Collaboration&amp;#039;].value) then&lt;br /&gt;
			author_etal = true;													-- so that |display-authors=etal not required&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local Others = A[&amp;#039;Others&amp;#039;];&lt;br /&gt;
&lt;br /&gt;
	local editor_etal;&lt;br /&gt;
	local e	= {};																-- editors list from |editor-lastn= / |editor-firstn= pairs or |veditors=&lt;br /&gt;
	local Editors;&lt;br /&gt;
&lt;br /&gt;
	do																			-- to limit scope of selected&lt;br /&gt;
		local selected = select_author_editor_source (A[&amp;#039;Veditors&amp;#039;], nil, args, &amp;#039;EditorList&amp;#039;);	-- support for |editors= withdrawn&lt;br /&gt;
		if 1 == selected then&lt;br /&gt;
			e, editor_etal = extract_names (args, &amp;#039;EditorList&amp;#039;);				-- fetch editor list from |editorn= / |editor-lastn= / |editor-firstn=, |editor-linkn=, and |editor-maskn=&lt;br /&gt;
		elseif 2 == selected then&lt;br /&gt;
			NameListStyle = &amp;#039;vanc&amp;#039;;												-- override whatever |name-list-style= might be&lt;br /&gt;
			e, editor_etal = parse_vauthors_veditors (args, args.veditors, &amp;#039;EditorList&amp;#039;);	-- fetch editor list from |veditors=, |editor-linkn=, and |editor-maskn=&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local translator_etal;&lt;br /&gt;
	local t = {};																-- translators list from |translator-lastn= / translator-firstn= pairs&lt;br /&gt;
	local Translators;															-- assembled translators name list&lt;br /&gt;
	t = extract_names (args, &amp;#039;TranslatorList&amp;#039;);									-- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn=&lt;br /&gt;
&lt;br /&gt;
	local interviewer_etal;&lt;br /&gt;
	local interviewers_list = {};												&lt;br /&gt;
	local Interviewers;															-- used later&lt;br /&gt;
	interviewers_list = extract_names (args, &amp;#039;InterviewerList&amp;#039;);				-- process preferred interviewers parameters&lt;br /&gt;
&lt;br /&gt;
	local contributor_etal;&lt;br /&gt;
	local c = {};																-- contributors list from |contributor-lastn= / contributor-firstn= pairs&lt;br /&gt;
	local Contributors;															-- assembled contributors name list&lt;br /&gt;
&lt;br /&gt;
	local Chapter = A[&amp;#039;Chapter&amp;#039;];												-- done here so that we have access to |contribution= from |chapter= aliases&lt;br /&gt;
	local Chapter_origin = A:ORIGIN (&amp;#039;Chapter&amp;#039;);&lt;br /&gt;
	local Contribution;															-- because contribution is required for contributor(s)&lt;br /&gt;
		if &amp;#039;contribution&amp;#039; == A:ORIGIN (&amp;#039;Chapter&amp;#039;) then&lt;br /&gt;
			Contribution = A[&amp;#039;Chapter&amp;#039;];										-- get the name of the contribution&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
	if in_array (config.CitationClass, {&amp;quot;book&amp;quot;, &amp;quot;citation&amp;quot;}) and not is_set (A[&amp;#039;Periodical&amp;#039;]) then	-- |contributor= and |contribution= only supported in book cites&lt;br /&gt;
		c = extract_names (args, &amp;#039;ContributorList&amp;#039;);							-- fetch contributor list from |contributorn= / |contributor-lastn=, -firstn=, -linkn=, -maskn=&lt;br /&gt;
		&lt;br /&gt;
		if 0 &amp;lt; #c then&lt;br /&gt;
			if not is_set (Contribution) then							-- |contributor= requires |contribution=&lt;br /&gt;
				table.insert( z.message_tail, {set_message ( &amp;#039;err_contributor_missing_required_param&amp;#039;, &amp;#039;contribution&amp;#039;)});	-- add missing contribution error message&lt;br /&gt;
				c = {};															-- blank the contributors&amp;#039; table; it is used as a flag later&lt;br /&gt;
			end&lt;br /&gt;
			if 0 == #a then														-- |contributor= requires |author=&lt;br /&gt;
				table.insert( z.message_tail, {set_message ( &amp;#039;err_contributor_missing_required_param&amp;#039;, &amp;#039;author&amp;#039;)});	-- add missing author error message&lt;br /&gt;
				c = {};															-- blank the contributors&amp;#039; table; it is used as a flag later&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	else																		-- if not a book cite&lt;br /&gt;
		if select_one (args, cfg.aliases[&amp;#039;ContributorList-Last&amp;#039;], &amp;#039;err_redundant_parameters&amp;#039;, 1 ) then	-- are there contributor name list parameters?&lt;br /&gt;
			table.insert( z.message_tail, {set_message ( &amp;#039;err_contributor_ignored&amp;#039;)});	-- add contributor ignored error message&lt;br /&gt;
		end&lt;br /&gt;
		Contribution = nil;														-- unset&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; D E P R E C A T E D _ P A R A M E T E R &amp;gt;--------------------------------------&lt;br /&gt;
&lt;br /&gt;
Categorize and emit an error message when the citation contains one or more deprecated parameters.  The function includes the&lt;br /&gt;
offending parameter name to the error message.  Only one error message is emitted regardless of the number of deprecated&lt;br /&gt;
parameters in the citation.&lt;br /&gt;
&lt;br /&gt;
added_deprecated_cat is a Boolean declared in page scope variables above&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function deprecated_parameter(name)&lt;br /&gt;
	if not added_deprecated_cat then&lt;br /&gt;
		added_deprecated_cat = true;											-- note that we&amp;#039;ve added this category&lt;br /&gt;
		table.insert (z.message_tail, {set_message (&amp;#039;err_deprecated_params&amp;#039;, {name}, true)});	-- add error message&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; B U I L D _ P A R A M _ L I S T &amp;gt;----------------------------------------------&lt;br /&gt;
&lt;br /&gt;
builds a k/v table where k is the metaparameter name (same as key in aliases{} table) and v is a k/v table&lt;br /&gt;
where:&lt;br /&gt;
	[&amp;#039;value&amp;#039;] = value assigned to the parameter&lt;br /&gt;
	[&amp;#039;origin&amp;#039;] = original parameter name&lt;br /&gt;
	[&amp;#039;render&amp;#039;] = empty string that will later hold parameter rendered value&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function build_param_list (args, params)&lt;br /&gt;
--	local params = {};&lt;br /&gt;
	local val;&lt;br /&gt;
	local selected;&lt;br /&gt;
	for mparam, aliases in pairs (cfg.aliases) do								-- spin through the aliases table (in ~/Configuration)&lt;br /&gt;
--error (mw.dumpObject (aliases))&lt;br /&gt;
&lt;br /&gt;
		if &amp;#039;table&amp;#039; == type (aliases) then										-- if there are multiple possible parameters&lt;br /&gt;
			val, selected = select_one (args, aliases, &amp;#039;err_redundant_parameters&amp;#039;, 1);	-- select one of them&lt;br /&gt;
			if not selected then												-- TODO: is this even possible?&lt;br /&gt;
				selected = &amp;#039;&amp;#039;;													 -- Empty string, not nil&lt;br /&gt;
			end&lt;br /&gt;
		elseif aliases ~= nil then												-- not nil so must be a single parameter name&lt;br /&gt;
			val = args[aliases];												-- get the assigned value&lt;br /&gt;
			selected = aliases;													-- and the parameter name&lt;br /&gt;
		else																	-- here when aliases is nil&lt;br /&gt;
			error( cfg.messages[&amp;#039;unknown_argument_map&amp;#039;] .. &amp;#039;: &amp;#039; .. k);			-- throw a major error because no key &lt;br /&gt;
		end&lt;br /&gt;
		if val then&lt;br /&gt;
			params[mparam] = {value=val, origin=selected, render=&amp;#039;&amp;#039;};			-- when parameter has a value, add it to params{} table&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
--error (mw.dumpObject (params))&lt;br /&gt;
	return params;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; H A S _ I N V I S I B L E _ C H A R S &amp;gt;----------------------------------------&lt;br /&gt;
&lt;br /&gt;
This function searches a parameter&amp;#039;s value for non-printable or invisible characters. The search stops at the&lt;br /&gt;
first match.&lt;br /&gt;
&lt;br /&gt;
This function will detect the visible replacement character when it is part of the Wikisource.&lt;br /&gt;
&lt;br /&gt;
Detects but ignores nowiki and math stripmarkers.  Also detects other named stripmarkers (gallery, math, pre, ref)&lt;br /&gt;
and identifies them with a slightly different error message. See also coins_cleanup().&lt;br /&gt;
&lt;br /&gt;
Output of this function is an error message that identifies the character or the Unicode group, or the stripmarker&lt;br /&gt;
that was detected along with its position (or, for multi-byte characters, the position of its first byte) in the&lt;br /&gt;
parameter value.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function has_invisible_chars (param, v)&lt;br /&gt;
	local position = &amp;#039;&amp;#039;;														-- position of invisible char or starting position of stripmarker&lt;br /&gt;
	local dummy;																-- end of matching string; not used but required to hold end position when a capture is returned&lt;br /&gt;
	local capture;																-- used by stripmarker detection to hold name of the stripmarker&lt;br /&gt;
	local i = 1;&lt;br /&gt;
	local stripmarker, apostrophe;&lt;br /&gt;
	&lt;br /&gt;
	capture = string.match (v, &amp;#039;[%w%p ]*&amp;#039;);										-- test for values that are simple ASCII text and bypass other tests if true&lt;br /&gt;
	if capture == v then														-- if same there are no Unicode characters&lt;br /&gt;
		return;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	while cfg.invisible_chars[i] do&lt;br /&gt;
		local char = cfg.invisible_chars[i][1]									-- the character or group name&lt;br /&gt;
		local pattern = cfg.invisible_chars[i][2]									-- the pattern used to find it&lt;br /&gt;
		position, dummy, capture = mw.ustring.find (v, pattern)					-- see if the parameter value contains characters that match the pattern&lt;br /&gt;
		&lt;br /&gt;
		if position and (char == &amp;#039;zero width joiner&amp;#039;) then						-- if we found a zero-width joiner character&lt;br /&gt;
			if mw.ustring.find (v, cfg.indic_script) then						-- it&amp;#039;s ok if one of the Indic scripts&lt;br /&gt;
				position = nil;													-- unset position&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		if position then&lt;br /&gt;
			if &amp;#039;nowiki&amp;#039; == capture or &amp;#039;math&amp;#039; == capture or						-- nowiki and math stripmarkers (not an error condition)&lt;br /&gt;
				(&amp;#039;templatestyles&amp;#039; == capture and in_array (param, {&amp;#039;id&amp;#039;, &amp;#039;quote&amp;#039;})) then	-- templatestyles stripmarker allowed in these parameters&lt;br /&gt;
					stripmarker = true;											-- set a flag&lt;br /&gt;
			elseif true == stripmarker and &amp;#039;delete&amp;#039; == char then				-- because stripmakers begin and end with the delete char, assume that we&amp;#039;ve found one end of a stripmarker&lt;br /&gt;
				position = nil;													-- unset&lt;br /&gt;
			else&lt;br /&gt;
				local err_msg;&lt;br /&gt;
				if capture then&lt;br /&gt;
					err_msg = capture .. &amp;#039; &amp;#039; .. char;&lt;br /&gt;
				else&lt;br /&gt;
					err_msg = char .. &amp;#039; &amp;#039; .. &amp;#039;character&amp;#039;;&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				table.insert (z.message_tail, {set_message (&amp;#039;err_invisible_char&amp;#039;, {err_msg, wrap_style (&amp;#039;parameter&amp;#039;, param), position}, true)});	-- add error message&lt;br /&gt;
				return;															-- and done with this parameter&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		i = i + 1;																-- bump our index&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; V A L I D A T E &amp;gt;--------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Looks for a parameter&amp;#039;s name in one of several whitelists.&lt;br /&gt;
&lt;br /&gt;
Parameters in the whitelist can have three values:&lt;br /&gt;
	true - active, supported parameters&lt;br /&gt;
	false - deprecated, supported parameters&lt;br /&gt;
	nil - unsupported parameters&lt;br /&gt;
	&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function validate (name, cite_class, empty)&lt;br /&gt;
	local name = tostring (name);&lt;br /&gt;
	local enum_name;															-- for enumerated parameters, is name with enumerator replaced with &amp;#039;#&amp;#039;&lt;br /&gt;
	local state;&lt;br /&gt;
	local function state_test (state, name)										-- local function to do testing of state values&lt;br /&gt;
		if true == state then return true; end									-- valid actively supported parameter&lt;br /&gt;
		if false == state then&lt;br /&gt;
			if empty then return nil; end										-- deprecated empty parameters are treated as unknowns&lt;br /&gt;
			deprecated_parameter (name);										-- parameter is deprecated but still supported&lt;br /&gt;
			return true;&lt;br /&gt;
		end&lt;br /&gt;
		return nil;&lt;br /&gt;
	end		&lt;br /&gt;
&lt;br /&gt;
	if name:find (&amp;#039;#&amp;#039;) then														-- # is a cs1|2 reserved character so parameters with # not permitted&lt;br /&gt;
		return nil;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if in_array (cite_class, whitelist.preprint_template_list) then	-- limited parameter sets allowed for these templates&lt;br /&gt;
		state = whitelist.limited_basic_arguments[name];&lt;br /&gt;
		if true == state_test (state, name) then return true; end&lt;br /&gt;
&lt;br /&gt;
		state = whitelist.preprint_arguments[cite_class][name];					-- look in the parameter-list for the template identified by cite_class&lt;br /&gt;
		if true == state_test (state, name) then return true; end&lt;br /&gt;
&lt;br /&gt;
																				-- limited enumerated parameters list&lt;br /&gt;
		enum_name = name:gsub (&amp;quot;%d+&amp;quot;, &amp;quot;#&amp;quot;);										-- replace digit(s) with # (last25 becomes last#) (mw.ustring because non-Western &amp;#039;local&amp;#039; digits)&lt;br /&gt;
		state = whitelist.limited_numbered_arguments[enum_name];&lt;br /&gt;
		if true == state_test (state, name) then return true; end&lt;br /&gt;
&lt;br /&gt;
		return false;															-- not supported because not found or name is set to nil&lt;br /&gt;
	end																			-- end limited parameter-set templates&lt;br /&gt;
&lt;br /&gt;
	if in_array (cite_class, whitelist.unique_param_template_list) then 	-- experiment for template-specific parameters for templates that accept parameters from the basic argument list&lt;br /&gt;
		state = whitelist.unique_arguments[cite_class][name];					-- look in the template-specific parameter-lists for the template identified by cite_class&lt;br /&gt;
		if true == state_test (state, name) then return true; end&lt;br /&gt;
	end																			-- if here, fall into general validation&lt;br /&gt;
		&lt;br /&gt;
	state = whitelist.basic_arguments[name];									-- all other templates; all normal parameters allowed&lt;br /&gt;
	if true == state_test (state, name) then return true; end&lt;br /&gt;
&lt;br /&gt;
																				-- all enumerated parameters allowed&lt;br /&gt;
	enum_name = name:gsub (&amp;quot;%d+&amp;quot;, &amp;quot;#&amp;quot;);											-- replace digit(s) with # (last25 becomes last#) (mw.ustring because non-Western &amp;#039;local&amp;#039; digits)&lt;br /&gt;
	state = whitelist.numbered_arguments[enum_name];&lt;br /&gt;
	if true == state_test (state, name) then return true; end&lt;br /&gt;
&lt;br /&gt;
	return false;																-- not supported because not found or name is set to nil&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[=[-------------------------&amp;lt; I N T E R _ W I K I _ C H E C K &amp;gt;----------------------------------------------&lt;br /&gt;
&lt;br /&gt;
check &amp;lt;value&amp;gt; for inter-language interwiki-link markup.  &amp;lt;prefix&amp;gt; must be a MediaWiki-recognized language&lt;br /&gt;
code.  when these values have the form (without leading colon):&lt;br /&gt;
	[[&amp;lt;prefix&amp;gt;:link|label]] return label as plain-text&lt;br /&gt;
	[[&amp;lt;prefix&amp;gt;:link]] return &amp;lt;prefix&amp;gt;:link as plain-text&lt;br /&gt;
&lt;br /&gt;
return value as is else&lt;br /&gt;
&lt;br /&gt;
]=]&lt;br /&gt;
&lt;br /&gt;
local function inter_wiki_check (parameter, value)&lt;br /&gt;
	local prefix = value:match (&amp;#039;%[%[(%a+):&amp;#039;);									-- get an interwiki prefix if one exists&lt;br /&gt;
	local _;&lt;br /&gt;
	&lt;br /&gt;
	if prefix and cfg.inter_wiki_map[prefix:lower()] then						-- if prefix is in the map, needs preceding colon so&lt;br /&gt;
		table.insert (z.message_tail, {set_message (&amp;#039;err_bad_paramlink&amp;#039;, parameter)});	-- emit an error message&lt;br /&gt;
		_, value, _ = is_wikilink (value);							-- extract label portion from wikilink&lt;br /&gt;
	end&lt;br /&gt;
	return value;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; M I S S I N G _ P I P E _ C H E C K &amp;gt;------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Look at the contents of a parameter. If the content has a string of characters and digits followed by an equal&lt;br /&gt;
sign, compare the alphanumeric string to the list of cs1|2 parameters.  If found, then the string is possibly a&lt;br /&gt;
parameter that is missing its pipe.  There are two tests made:&lt;br /&gt;
	{{cite ... |title=Title access-date=2016-03-17}}	-- the first parameter has a value and whitespace separates that value from the missing pipe parameter name&lt;br /&gt;
	{{cite ... |title=access-date=2016-03-17}}			-- the first parameter has no value (whitespace after the first = is trimmed by MediaWiki)&lt;br /&gt;
cs1|2 shares some parameter names with XML/HTML attributes: class=, title=, etc.  To prevent false positives XML/HTML&lt;br /&gt;
tags are removed before the search.&lt;br /&gt;
&lt;br /&gt;
If a missing pipe is detected, this function adds the missing pipe maintenance category.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function missing_pipe_check (parameter, value)&lt;br /&gt;
	local capture;&lt;br /&gt;
	value = value:gsub (&amp;#039;%b&amp;lt;&amp;gt;&amp;#039;, &amp;#039;&amp;#039;);											-- remove XML/HTML tags because attributes: class=, title=, etc.&lt;br /&gt;
&lt;br /&gt;
	capture = value:match (&amp;#039;%s+(%a[%w%-]+)%s*=&amp;#039;) or value:match (&amp;#039;^(%a[%w%-]+)%s*=&amp;#039;);	-- find and categorize parameters with possible missing pipes&lt;br /&gt;
	if capture and validate (capture) then										-- if the capture is a valid parameter name&lt;br /&gt;
		table.insert (z.message_tail, {set_message (&amp;#039;err_missing_pipe&amp;#039;, parameter)});&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; H A S _ E X T R A N E O U S _ P U N C T &amp;gt;--------------------------------------&lt;br /&gt;
&lt;br /&gt;
look for extraneous terminal punctuation in most parameter values; parameters listed in skip table are not checked&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function has_extraneous_punc (param, value)&lt;br /&gt;
	if &amp;#039;number&amp;#039; == type (param) then&lt;br /&gt;
		return;&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	param = param:gsub (&amp;#039;%d+&amp;#039;, &amp;#039;#&amp;#039;);											-- enumerated name-list mask params allow terminal punct; normalize &lt;br /&gt;
	if cfg.punct_skip[param] then&lt;br /&gt;
		return;																	-- parameter name found in the skip table so done&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	if value:match (&amp;#039;[,;:]$&amp;#039;) then&lt;br /&gt;
		set_message (&amp;#039;maint_extra_punct&amp;#039;);							-- has extraneous punctuation; add maint cat&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; A R G S _ G E T &amp;gt;--------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
get arguments from template frame, do validation and some error checking&lt;br /&gt;
&lt;br /&gt;
&amp;lt;args&amp;gt;				an empty k/v table where k is parameter name and v is its value; filled here&lt;br /&gt;
&amp;lt;pfargs&amp;gt;			args table from the parent frame (the template&amp;#039;s parameters)&lt;br /&gt;
&amp;lt;class&amp;gt;				config.CitationClass from #invoke: (frame)&lt;br /&gt;
&amp;lt;sandbox&amp;gt;			boolean; true when this function called from  ~/CS1/sandbox&lt;br /&gt;
&amp;lt;params&amp;gt;			an empty k/v table filled by build_param_list()&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function args_get (args, pfargs, class, sandbox, params)&lt;br /&gt;
	local suggestions = {};														-- table where we store suggestions if we need to loadData them&lt;br /&gt;
	local empty_unknowns = {};													-- sequence table of empty unknown parameter names&lt;br /&gt;
	local error_text, error_state;&lt;br /&gt;
&lt;br /&gt;
	local capture;																-- the single supported capture when matching unknown parameters using patterns&lt;br /&gt;
&lt;br /&gt;
	for k, v in pairs (pfargs) do												-- get parameters from the parent (template) frame&lt;br /&gt;
		v = mw.ustring.gsub (v, &amp;#039;^%s*(.-)%s*$&amp;#039;, &amp;#039;%1&amp;#039;);							-- trim leading/trailing whitespace; when v is only whitespace, becomes empty string&lt;br /&gt;
		if v ~= &amp;#039;&amp;#039; then&lt;br /&gt;
			if (&amp;#039;string&amp;#039; == type (k)) then&lt;br /&gt;
				k = mw.ustring.gsub (k, &amp;#039;%d&amp;#039;, cfg.date_names.local_digits);		-- for enumerated parameters, translate &amp;#039;local&amp;#039; digits to Western 0-9&lt;br /&gt;
			end&lt;br /&gt;
			if not validate (k, class) then			&lt;br /&gt;
				error_text = &amp;quot;&amp;quot;;&lt;br /&gt;
				if type (k) ~= &amp;#039;string&amp;#039; then&lt;br /&gt;
					-- exclude empty numbered parameters&lt;br /&gt;
					if v:match (&amp;quot;%S+&amp;quot;) ~= nil then&lt;br /&gt;
						error_text, error_state = set_message (&amp;#039;err_text_ignored&amp;#039;, {v}, true);&lt;br /&gt;
					end&lt;br /&gt;
				elseif validate (k:lower(), class) then &lt;br /&gt;
					error_text, error_state = set_message (&amp;#039;err_parameter_ignored_suggest&amp;#039;, {k, k:lower()}, true);	-- suggest the lowercase version of the parameter&lt;br /&gt;
				else&lt;br /&gt;
					if nil == suggestions.suggestions then						-- if this table is nil then we need to load it&lt;br /&gt;
--						if nil ~= string.find (frame:getTitle(), &amp;#039;sandbox&amp;#039;, 1, true) then			-- did the {{#invoke:}} use sandbox version?&lt;br /&gt;
						if sandbox then&lt;br /&gt;
							suggestions = mw.loadData (&amp;#039;Module:Citation/CS1/Suggestions/sandbox&amp;#039;);	-- use the sandbox version&lt;br /&gt;
						else&lt;br /&gt;
							suggestions = mw.loadData (&amp;#039;Module:Citation/CS1/Suggestions&amp;#039;);			-- use the live version&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
					for pattern, param in pairs (suggestions.patterns) do		-- loop through the patterns to see if we can suggest a proper parameter&lt;br /&gt;
						capture = k:match (pattern);							-- the whole match if no capture in pattern else the capture if a match&lt;br /&gt;
						if capture then											-- if the pattern matches &lt;br /&gt;
							param = substitute (param, capture);				-- add the capture to the suggested parameter (typically the enumerator)&lt;br /&gt;
							if validate (param, class) then		-- validate the suggestion to make sure that the suggestion is supported by this template (necessary for limited parameter lists)&lt;br /&gt;
								error_text, error_state = set_message (&amp;#039;err_parameter_ignored_suggest&amp;#039;, {k, param}, true);	-- set the suggestion error message&lt;br /&gt;
							else&lt;br /&gt;
								error_text, error_state = set_message (&amp;#039;err_parameter_ignored&amp;#039;, {param}, true);	-- suggested param not supported by this template&lt;br /&gt;
								v = &amp;#039;&amp;#039;;											-- unset&lt;br /&gt;
							end&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
					if not is_set (error_text) then					-- couldn&amp;#039;t match with a pattern, is there an explicit suggestion?&lt;br /&gt;
						if suggestions.suggestions[ k:lower() ] ~= nil then&lt;br /&gt;
							error_text, error_state = set_message (&amp;#039;err_parameter_ignored_suggest&amp;#039;, {k, suggestions.suggestions[ k:lower() ]}, true);&lt;br /&gt;
						else&lt;br /&gt;
							error_text, error_state = set_message (&amp;#039;err_parameter_ignored&amp;#039;, {k}, true);&lt;br /&gt;
							v = &amp;#039;&amp;#039;;												-- unset value assigned to unrecognized parameters (this for the limited parameter lists)&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
				end				  &lt;br /&gt;
				if error_text ~= &amp;#039;&amp;#039; then&lt;br /&gt;
					table.insert (z.message_tail, {error_text, error_state});&lt;br /&gt;
				end				&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			args[k] = v;														-- save this parameter and its value&lt;br /&gt;
&lt;br /&gt;
		elseif not is_set (v) then												-- for empty parameters&lt;br /&gt;
			if not validate (k, class, true) then				-- is this empty parameter a valid parameter&lt;br /&gt;
				k = (&amp;#039;&amp;#039; == k) and &amp;#039;(empty string)&amp;#039; or k;						-- when k is empty string (or was space(s) trimmed to empty string), replace with descriptive text; TODO: i18n&lt;br /&gt;
				table.insert (empty_unknowns, wrap_style (&amp;#039;parameter&amp;#039;, k));		-- format for error message and add to the list&lt;br /&gt;
			end&lt;br /&gt;
																				-- crude debug support that allows us to render a citation from module {{#invoke:}} TODO: keep?&lt;br /&gt;
	--	elseif args[k] ~= nil or (k == &amp;#039;postscript&amp;#039;) then						-- when args[k] has a value from {{#invoke}} frame (we don&amp;#039;t normally do that)&lt;br /&gt;
	--		args[k] = v;														-- overwrite args[k] with empty string from pframe.args[k] (template frame); v is empty string here&lt;br /&gt;
		end																		-- not sure about the postscript bit; that gets handled in parameter validation; historical artifact?&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if 0 ~= #empty_unknowns then												-- create empty unknown error message&lt;br /&gt;
		table.insert (z.message_tail, {set_message (&amp;#039;err_param_unknown_empty&amp;#039;, {&lt;br /&gt;
			1 == #empty_unknowns and &amp;#039;&amp;#039; or &amp;#039;s&amp;#039;,&lt;br /&gt;
			make_sep_list (#empty_unknowns, empty_unknowns)&lt;br /&gt;
			}, true)});&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	for k, v in pairs( args ) do&lt;br /&gt;
		if &amp;#039;string&amp;#039; == type (k) then											-- don&amp;#039;t evaluate positional parameters&lt;br /&gt;
			has_invisible_chars (k, v);											-- look for invisible characters&lt;br /&gt;
		end&lt;br /&gt;
		has_extraneous_punc (k, v);												-- look for extraneous terminal punctuation in parameter values&lt;br /&gt;
		missing_pipe_check (k, v);												-- do we think that there is a parameter that is missing a pipe?&lt;br /&gt;
		args[k] = inter_wiki_check (k, v);										-- when language interwiki-linked parameter missing leading colon replace with wiki-link label&lt;br /&gt;
	end&lt;br /&gt;
	params = build_param_list (args, params);&lt;br /&gt;
	return args, params;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; S E T _ S E L E C T E D _ M O D U L E S &amp;gt;--------------------------------------&lt;br /&gt;
&lt;br /&gt;
Sets local cfg table and imported functions table to same (live or sandbox) as that used by the other modules.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function set_selected_modules (cfg_table_ptr, utilities_page_ptr, whitelist_page_ptr)&lt;br /&gt;
	cfg = cfg_table_ptr;&lt;br /&gt;
	whitelist = whitelist_page_ptr;&lt;br /&gt;
	&lt;br /&gt;
--	has_accept_as_written = utilities_page_ptr.has_accept_as_written;			-- import functions from select Module:Citation/CS1/Utilities module&lt;br /&gt;
	in_array = utilities_page_ptr.in_array;&lt;br /&gt;
	is_set = utilities_page_ptr.is_set;&lt;br /&gt;
	is_wikilink = utilities_page_ptr.is_wikilink;&lt;br /&gt;
	make_sep_list = utilities_page_ptr.make_sep_list&lt;br /&gt;
	set_message = utilities_page_ptr.set_message;&lt;br /&gt;
	select_one = utilities_page_ptr.select_one;&lt;br /&gt;
	substitute = utilities_page_ptr.substitute;&lt;br /&gt;
--	make_wikilink = utilities_page_ptr.make_wikilink;&lt;br /&gt;
	wrap_style = utilities_page_ptr.wrap_style;&lt;br /&gt;
&lt;br /&gt;
	z = utilities_page_ptr.z;													-- table of tables in Module:Citation/CS1/Utilities&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; E X P O R T E D   F U N C T I O N S &amp;gt;------------------------------------------&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
return {&lt;br /&gt;
	args_get = args_get,&lt;br /&gt;
	has_extraneous_punc = has_extraneous_punc,&lt;br /&gt;
	has_invisible_chars = has_invisible_chars,&lt;br /&gt;
	inter_wiki_check = inter_wiki_check,&lt;br /&gt;
	missing_pipe_check = missing_pipe_check,&lt;br /&gt;
	set_selected_modules = set_selected_modules,&lt;br /&gt;
	validate = validate,&lt;br /&gt;
	}&lt;/div&gt;</summary>
		<author><name>imported&gt;Trappist the monk</name></author>
	</entry>
</feed>