<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://zoophilia.wiki/index.php?action=history&amp;feed=atom&amp;title=Module%3ACitation%2FCS1%2FUtilities</id>
	<title>Module:Citation/CS1/Utilities - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://zoophilia.wiki/index.php?action=history&amp;feed=atom&amp;title=Module%3ACitation%2FCS1%2FUtilities"/>
	<link rel="alternate" type="text/html" href="https://zoophilia.wiki/index.php?title=Module:Citation/CS1/Utilities&amp;action=history"/>
	<updated>2026-09-20T21:13:35Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.46.0</generator>
	<entry>
		<id>https://zoophilia.wiki/index.php?title=Module:Citation/CS1/Utilities&amp;diff=479&amp;oldid=prev</id>
		<title>imported&gt;SockyPaws: Update submodule</title>
		<link rel="alternate" type="text/html" href="https://zoophilia.wiki/index.php?title=Module:Citation/CS1/Utilities&amp;diff=479&amp;oldid=prev"/>
		<updated>2025-12-25T11:08:20Z</updated>

		<summary type="html">&lt;p&gt;Update submodule&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local z = {&lt;br /&gt;
    error_cats_t = {}, -- for categorizing citations that contain errors&lt;br /&gt;
    error_ids_t = {}, -- list of error identifiers; used to prevent duplication of certain errors; local to this module&lt;br /&gt;
    error_msgs_t = {}, -- sequence table of error messages&lt;br /&gt;
    maint_cats_t = {}, -- for categorizing citations that aren&amp;#039;t erroneous per se, but could use a little work&lt;br /&gt;
    prop_cats_t = {}, -- for categorizing citations based on certain properties, language of source for instance&lt;br /&gt;
    prop_keys_t = {} -- for adding classes to the citation&amp;#039;s &amp;lt;cite&amp;gt; tag&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&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;
local cfg  -- table of tables imported from selected Module:Citation/CS1/Configuration&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; I S _ S E T &amp;gt;------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Returns true if argument is set; false otherwise. Argument is &amp;#039;set&amp;#039; when it exists (not nil) or when it is not an empty string.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
local function is_set(var)&lt;br /&gt;
    return not (var == nil or var == &amp;quot;&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; I N _ A R R A Y &amp;gt;--------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Whether needle is in haystack&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
local function in_array(needle, haystack)&lt;br /&gt;
    if needle == nil then&lt;br /&gt;
        return false&lt;br /&gt;
    end&lt;br /&gt;
    for n, v in ipairs(haystack) do&lt;br /&gt;
        if v == needle then&lt;br /&gt;
            return n&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; H A S _ A C C E P T _ A S _ W R I T T E N &amp;gt;------------------------------------&lt;br /&gt;
&lt;br /&gt;
When &amp;lt;str&amp;gt; is wholly wrapped in accept-as-written markup, return &amp;lt;str&amp;gt; without markup and true; return &amp;lt;str&amp;gt; and false else&lt;br /&gt;
&lt;br /&gt;
with allow_empty = false, &amp;lt;str&amp;gt; must have at least one character inside the markup&lt;br /&gt;
with allow_empty = true, &amp;lt;str&amp;gt; the markup frame can be empty like (()) to distinguish an empty template parameter from the specific condition &amp;quot;has no applicable value&amp;quot; in citation-context.&lt;br /&gt;
&lt;br /&gt;
After further evaluation the two cases might be merged at a later stage, but should be kept separated for now.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
local function has_accept_as_written(str, allow_empty)&lt;br /&gt;
    if not is_set(str) then&lt;br /&gt;
        return str, false&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local count&lt;br /&gt;
&lt;br /&gt;
    if true == allow_empty then&lt;br /&gt;
        str, count = str:gsub(&amp;quot;^%(%((.*)%)%)$&amp;quot;, &amp;quot;%1&amp;quot;) -- allows (()) to be an empty set&lt;br /&gt;
    else&lt;br /&gt;
        str, count = str:gsub(&amp;quot;^%(%((.+)%)%)$&amp;quot;, &amp;quot;%1&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
    return str, 0 ~= count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; S U B S T I T U T E &amp;gt;----------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Populates numbered arguments in a message string using an argument table. &amp;lt;args&amp;gt; may be a single string or a&lt;br /&gt;
sequence table of multiple strings.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
local function substitute(msg, args)&lt;br /&gt;
    return args and mw.message.newRawMessage(msg, args):plain() or msg&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; E R R O R _ C O M M E N T &amp;gt;----------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Wraps error messages with CSS markup according to the state of hidden. &amp;lt;content&amp;gt; may be a single string or a&lt;br /&gt;
sequence table of multiple strings.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
local function error_comment(content, hidden)&lt;br /&gt;
    return substitute(hidden and cfg.presentation[&amp;quot;hidden-error&amp;quot;] or cfg.presentation[&amp;quot;visible-error&amp;quot;], content)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; H Y P H E N _ T O _ D A S H &amp;gt;--------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Converts a hyphen, endash, emdash to endash under certain conditions.  The hyphen/en/em must separate&lt;br /&gt;
like items; unlike items are returned unmodified.  These forms are modified:&lt;br /&gt;
	letter - letter (A-B)&lt;br /&gt;
	digit - digit (4-5)&lt;br /&gt;
	digit separator digit - digit separator digit (4.1-4.5 or 4-1-4-5)&lt;br /&gt;
	letterdigit - letterdigit (A1-A5) (an optional separator between letter and&lt;br /&gt;
		digit is supported – a.1-a.5 or a-1-a-5)&lt;br /&gt;
	digitletter - digitletter (5a-5d) (an optional separator between letter and&lt;br /&gt;
		digit is supported – 5.a-5.d or 5-a-5-d)&lt;br /&gt;
&lt;br /&gt;
any other forms are returned unmodified.&lt;br /&gt;
&lt;br /&gt;
str may be a comma- or semicolon-separated list of page ranges with/without single pages&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
local function hyphen_to_dash(str)&lt;br /&gt;
    if not is_set(str) then&lt;br /&gt;
        return str&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    str =&lt;br /&gt;
        str:gsub(&lt;br /&gt;
        &amp;quot;(%(%(.-%)%))&amp;quot;,&lt;br /&gt;
        function(m)&lt;br /&gt;
            return m:gsub(&amp;quot;,&amp;quot;, &amp;quot;，&amp;quot;):gsub(&amp;quot;;&amp;quot;, &amp;quot;；&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
    ) -- replace commas and semicolons in accept-as-written markup with similar unicode characters so they&amp;#039;ll be ignored during the split&lt;br /&gt;
    str = str:gsub(&amp;quot;&amp;amp;[nm]dash;&amp;quot;, {[&amp;quot;&amp;amp;ndash;&amp;quot;] = &amp;quot;–&amp;quot;, [&amp;quot;&amp;amp;mdash;&amp;quot;] = &amp;quot;—&amp;quot;}) -- replace &amp;amp;mdash; and &amp;amp;ndash; entities with their characters; semicolon mucks up the text.split&lt;br /&gt;
    str = str:gsub(&amp;quot;&amp;amp;#45;&amp;quot;, &amp;quot;-&amp;quot;) -- replace HTML numeric entity with hyphen character&lt;br /&gt;
    str = str:gsub(&amp;quot;&amp;amp;nbsp;&amp;quot;, &amp;quot; &amp;quot;) -- replace &amp;amp;nbsp; entity with generic keyboard space character&lt;br /&gt;
&lt;br /&gt;
    local out = {}&lt;br /&gt;
    local list = mw.text.split(str, &amp;quot;%s*[,;]%s*&amp;quot;) -- split str at comma or semicolon separators if there are any&lt;br /&gt;
&lt;br /&gt;
    local accept  -- boolean&lt;br /&gt;
&lt;br /&gt;
    for _, item in ipairs(list) do -- for each item in the list&lt;br /&gt;
        item, accept = has_accept_as_written(item) -- remove accept-this-as-written markup when it wraps all of item&lt;br /&gt;
        if not accept and mw.ustring.match(item, &amp;quot;^%w*[%.%-]?%w+%s*[—–-]%s*%w*[%.%-]?%w+$&amp;quot;) then -- if a hyphenated range or has endash or emdash separators&lt;br /&gt;
            if&lt;br /&gt;
                mw.ustring.match(item, &amp;quot;^%a+[%.%-]?%d+%s*[—–-]%s*%a+[%.%-]?%d+$&amp;quot;) or -- letterdigit hyphen letterdigit (optional separator between letter and digit)&lt;br /&gt;
                    mw.ustring.match(item, &amp;quot;^%d+[%.%-]?%a+%s*[—–-]%s*%d+[%.%-]?%a+$&amp;quot;) or -- digitletter hyphen digitletter (optional separator between digit and letter)&lt;br /&gt;
                    mw.ustring.match(item, &amp;quot;^%d+[%.%-]%d+%s*[—–-]%s*%d+[%.%-]%d+$&amp;quot;)&lt;br /&gt;
             then -- digit separator digit hyphen digit separator digit&lt;br /&gt;
                item =&lt;br /&gt;
                    mw.ustring.gsub(&lt;br /&gt;
                    item,&lt;br /&gt;
                    &amp;quot;(%w*[%.%-]?%w+)%s*[—–-]%s*(%w*[%.%-]?%w+)&amp;quot;,&lt;br /&gt;
                    &amp;#039;&amp;lt;span class=&amp;quot;nowrap&amp;quot;&amp;gt;%1 –&amp;lt;/span&amp;gt; &amp;lt;span class=&amp;quot;nowrap&amp;quot;&amp;gt;%2&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
                ) -- replace hyphen/dash, with spaced endash&lt;br /&gt;
            elseif&lt;br /&gt;
                mw.ustring.match(item, &amp;quot;^%d+%s*[—–-]%s*%d+$&amp;quot;) or mw.ustring.match(item, &amp;quot;^%a+%s*[—–-]%s*%a+$&amp;quot;) -- digit hyphen digit&lt;br /&gt;
             then -- letter hyphen letter&lt;br /&gt;
                item = mw.ustring.gsub(item, &amp;quot;(%w+)%s*[—–-]%s*(%w+)&amp;quot;, &amp;#039;&amp;lt;span class=&amp;quot;nowrap&amp;quot;&amp;gt;%1–&amp;lt;/span&amp;gt;%2&amp;#039;) -- replace hyphen/emdash with endash, remove extraneous space characters&lt;br /&gt;
            else&lt;br /&gt;
                --				item = mw.ustring.gsub (item, &amp;#039;%s*[—–-]%s*&amp;#039;, &amp;#039;–&amp;#039;);				-- disabled; here when &amp;#039;unlike&amp;#039; items so return &amp;lt;item&amp;gt; as is&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
        table.insert(out, item) -- add the (possibly modified) item to the output table&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local temp_str = &amp;quot;&amp;quot; -- concatenate the output table into a comma separated string&lt;br /&gt;
    temp_str, accept = has_accept_as_written(table.concat(out, &amp;quot;, &amp;quot;)) -- remove accept-this-as-written markup when it wraps all of concatenated out&lt;br /&gt;
    if accept then&lt;br /&gt;
        temp_str = has_accept_as_written(str) -- when global markup removed, return original str; do it this way to suppress boolean second return value&lt;br /&gt;
        return temp_str:gsub(&amp;quot;，&amp;quot;, &amp;quot;,&amp;quot;):gsub(&amp;quot;；&amp;quot;, &amp;quot;;&amp;quot;)&lt;br /&gt;
    else&lt;br /&gt;
        return temp_str:gsub(&amp;quot;，&amp;quot;, &amp;quot;,&amp;quot;):gsub(&amp;quot;；&amp;quot;, &amp;quot;;&amp;quot;) -- else, return assembled temp_str&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[=[-------------------------&amp;lt; M A K E _ W I K I L I N K &amp;gt;----------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Makes a wikilink; when both link and display text is provided, returns a wikilink in the form [[L|D]]; if only&lt;br /&gt;
link is provided (or link and display are the same), returns a wikilink in the form [[L]]; if neither are&lt;br /&gt;
provided or link is omitted, returns an empty string.&lt;br /&gt;
&lt;br /&gt;
]=]&lt;br /&gt;
&lt;br /&gt;
local function make_wikilink(link, display)&lt;br /&gt;
    if not is_set(link) then&lt;br /&gt;
        return &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if is_set(display) and link ~= display then&lt;br /&gt;
        return table.concat({&amp;quot;[[&amp;quot;, link, &amp;quot;|&amp;quot;, display, &amp;quot;]]&amp;quot;})&lt;br /&gt;
    else&lt;br /&gt;
        return table.concat({&amp;quot;[[&amp;quot;, link, &amp;quot;]]&amp;quot;})&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; S E T _ M E S S A G E &amp;gt;----------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Sets an error message using the ~/Configuration error_conditions{} table along with arguments supplied in the function&lt;br /&gt;
call, inserts the resulting message in z.error_msgs_t{} sequence table, and returns the error message.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;error_id&amp;gt; – key value for appropriate error handler in ~/Configuration error_conditions{} table &lt;br /&gt;
&amp;lt;arguments&amp;gt; – may be a single string or a sequence table of multiple strings to be subsititued into error_conditions[error_id].message&lt;br /&gt;
&amp;lt;raw&amp;gt; – boolean&lt;br /&gt;
	true –	causes this function to return the error message not wrapped in visible-error, hidden-error span tag;&lt;br /&gt;
			returns error_conditions[error_id].hidden as a second return value&lt;br /&gt;
			does not add message to z.error_msgs_t sequence table&lt;br /&gt;
	false, nil – adds message wrapped in visible-error, hidden-error span tag to z.error_msgs_t&lt;br /&gt;
			returns the error message wrapped in visible-error, hidden-error span tag; there is no second return value&lt;br /&gt;
&amp;lt;prefix&amp;gt; – string to be prepended to &amp;lt;message&amp;gt;									-- TODO: remove support for these unused(?) arguments?&lt;br /&gt;
&amp;lt;suffix&amp;gt; – string to be appended to &amp;lt;message&amp;gt;&lt;br /&gt;
&lt;br /&gt;
TODO: change z.error_cats_t and z.maint_cats_t to have the form cat_name = true?  this to avoid dups without having to have an extra table&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
local added_maint_cats = {} -- list of maintenance categories that have been added to z.maint_cats_t; TODO: figure out how to delete this table&lt;br /&gt;
&lt;br /&gt;
local function set_message(error_id, arguments, raw, prefix, suffix)&lt;br /&gt;
    local error_state = cfg.error_conditions[error_id]&lt;br /&gt;
&lt;br /&gt;
    prefix = prefix or &amp;quot;&amp;quot;&lt;br /&gt;
    suffix = suffix or &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    if error_state == nil then&lt;br /&gt;
        error(cfg.messages[&amp;quot;undefined_error&amp;quot;] .. &amp;quot;: &amp;quot; .. error_id) -- because missing error handler in Module:Citation/CS1/Configuration&lt;br /&gt;
    elseif is_set(error_state.category) then&lt;br /&gt;
        if error_state.message then -- when error_state.message defined, this is an error message&lt;br /&gt;
            table.insert(z.error_cats_t, error_state.category)&lt;br /&gt;
        else&lt;br /&gt;
            if not added_maint_cats[error_id] then&lt;br /&gt;
                added_maint_cats[error_id] = true -- note that we&amp;#039;ve added this category&lt;br /&gt;
                table.insert(z.maint_cats_t, substitute(error_state.category, arguments)) -- make cat name then add to table&lt;br /&gt;
            end&lt;br /&gt;
            return -- because no message, nothing more to do&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local message = substitute(error_state.message, arguments)&lt;br /&gt;
&lt;br /&gt;
    message =&lt;br /&gt;
        table.concat(&lt;br /&gt;
        {&lt;br /&gt;
            message,&lt;br /&gt;
            &amp;quot; (&amp;quot;,&lt;br /&gt;
            make_wikilink(&lt;br /&gt;
                table.concat(&lt;br /&gt;
                    {&lt;br /&gt;
                        cfg.messages[&amp;quot;help page link&amp;quot;],&lt;br /&gt;
                        &amp;quot;#&amp;quot;,&lt;br /&gt;
                        error_state.anchor&lt;br /&gt;
                    }&lt;br /&gt;
                ),&lt;br /&gt;
                cfg.messages[&amp;quot;help page label&amp;quot;]&lt;br /&gt;
            ),&lt;br /&gt;
            &amp;quot;)&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
    z.error_ids_t[error_id] = true&lt;br /&gt;
    if&lt;br /&gt;
        z.error_ids_t[&amp;quot;err_citation_missing_title&amp;quot;] and -- if missing-title error already noted&lt;br /&gt;
            in_array(error_id, {&amp;quot;err_bare_url_missing_title&amp;quot;, &amp;quot;err_trans_missing_title&amp;quot;})&lt;br /&gt;
     then -- and this error is one of these&lt;br /&gt;
        return &amp;quot;&amp;quot;, false -- don&amp;#039;t bother because one flavor of missing title is sufficient&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    message = table.concat({prefix, message, suffix})&lt;br /&gt;
&lt;br /&gt;
    if true == raw then&lt;br /&gt;
        return message, error_state.hidden -- return message not wrapped in visible-error, hidden-error span tag&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    message = error_comment(message, error_state.hidden) -- wrap message in visible-error, hidden-error span tag&lt;br /&gt;
    table.insert(z.error_msgs_t, message) -- add it to the messages sequence table&lt;br /&gt;
    return message -- and done; return value generally not used but is used as a flag in various functions of ~/Identifiers&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[-------------------------&amp;lt; I S _ A L I A S _ U S E D &amp;gt;-----------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
This function is used by select_one() to determine if one of a list of alias parameters is in the argument list&lt;br /&gt;
provided by the template.&lt;br /&gt;
&lt;br /&gt;
Input:&lt;br /&gt;
	args – pointer to the arguments table from calling template&lt;br /&gt;
	alias – one of the list of possible aliases in the aliases lists from Module:Citation/CS1/Configuration&lt;br /&gt;
	index – for enumerated parameters, identifies which one&lt;br /&gt;
	enumerated – true/false flag used to choose how enumerated aliases are examined&lt;br /&gt;
	value – value associated with an alias that has previously been selected; nil if not yet selected&lt;br /&gt;
	selected – the alias that has previously been selected; nil if not yet selected&lt;br /&gt;
	error_list – list of aliases that are duplicates of the alias already selected&lt;br /&gt;
&lt;br /&gt;
Returns:&lt;br /&gt;
	value – value associated with alias we selected or that was previously selected or nil if an alias not yet selected&lt;br /&gt;
	selected – the alias we selected or the alias that was previously selected or nil if an alias not yet selected&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
local function is_alias_used(args, alias, index, enumerated, value, selected, error_list)&lt;br /&gt;
    if enumerated then -- is this a test for an enumerated parameters?&lt;br /&gt;
        alias = alias:gsub(&amp;quot;#&amp;quot;, index) -- replace &amp;#039;#&amp;#039; with the value in index&lt;br /&gt;
    else&lt;br /&gt;
        alias = alias:gsub(&amp;quot;#&amp;quot;, &amp;quot;&amp;quot;) -- remove &amp;#039;#&amp;#039; if it exists&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if is_set(args[alias]) then -- alias is in the template&amp;#039;s argument list&lt;br /&gt;
        if value ~= nil and selected ~= alias then -- if we have already selected one of the aliases&lt;br /&gt;
            local skip&lt;br /&gt;
            for _, v in ipairs(error_list) do -- spin through the error list to see if we&amp;#039;ve added this alias&lt;br /&gt;
                if v == alias then&lt;br /&gt;
                    skip = true&lt;br /&gt;
                    break -- has been added so stop looking&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
            if not skip then -- has not been added so&lt;br /&gt;
                table.insert(error_list, alias) -- add error alias to the error list&lt;br /&gt;
            end&lt;br /&gt;
        else&lt;br /&gt;
            value = args[alias] -- not yet selected an alias, so select this one&lt;br /&gt;
            selected = alias&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return value, selected -- return newly selected alias, or previously selected alias&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; A D D _ M A I N T _ C A T &amp;gt;------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Adds a category to z.maint_cats_t using names from the configuration file with additional text if any.&lt;br /&gt;
To prevent duplication, the added_maint_cats table lists the categories by key that have been added to z.maint_cats_t.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
local function add_maint_cat(key, arguments)&lt;br /&gt;
    if not added_maint_cats[key] then&lt;br /&gt;
        added_maint_cats[key] = true -- note that we&amp;#039;ve added this category&lt;br /&gt;
        table.insert(z.maint_cats_t, substitute(cfg.maint_cats[key], arguments)) -- make name then add to table&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; A D D _ P R O P _ C A T &amp;gt;--------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Adds a category to z.prop_cats_t using names from the configuration file with additional text if any.&lt;br /&gt;
&lt;br /&gt;
foreign_lang_source and foreign_lang_source_2 keys have a language code appended to them so that multiple languages&lt;br /&gt;
may be categorized but multiples of the same language are not categorized.&lt;br /&gt;
&lt;br /&gt;
added_prop_cats is a table declared in page scope variables above&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
local added_prop_cats = {} -- list of property categories that have been added to z.prop_cats_t&lt;br /&gt;
&lt;br /&gt;
local function add_prop_cat(key, arguments, key_modifier)&lt;br /&gt;
    local key_modified = key .. ((key_modifier and key_modifier) or &amp;quot;&amp;quot;) -- modify &amp;lt;key&amp;gt; with &amp;lt;key_modifier&amp;gt; if present and not nil&lt;br /&gt;
&lt;br /&gt;
    if not added_prop_cats[key_modified] then&lt;br /&gt;
        added_prop_cats[key_modified] = true -- note that we&amp;#039;ve added this category&lt;br /&gt;
        table.insert(z.prop_cats_t, substitute(cfg.prop_cats[key], arguments)) -- make name then add to table&lt;br /&gt;
        table.insert(z.prop_keys_t, &amp;quot;cs1-prop-&amp;quot; .. key) -- convert key to class for use in the citation&amp;#039;s &amp;lt;cite&amp;gt; tag&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; S A F E _ F O R _ I T A L I C S &amp;gt;----------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Protects a string that will be wrapped in wiki italic markup &amp;#039;&amp;#039; ... &amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Note: We cannot use &amp;lt;i&amp;gt; for italics, as the expected behavior for italics specified by &amp;#039;&amp;#039;...&amp;#039;&amp;#039; in the title is that&lt;br /&gt;
they will be inverted (i.e. unitalicized) in the resulting references.  In addition, &amp;lt;i&amp;gt; and &amp;#039;&amp;#039; tend to interact&lt;br /&gt;
poorly under Mediawiki&amp;#039;s HTML tidy.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
local function safe_for_italics(str)&lt;br /&gt;
    if not is_set(str) then&lt;br /&gt;
        return str&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if str:sub(1, 1) == &amp;quot;&amp;#039;&amp;quot; then&lt;br /&gt;
        str = &amp;quot;&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;&amp;quot; .. str&lt;br /&gt;
    end&lt;br /&gt;
    if str:sub(-1, -1) == &amp;quot;&amp;#039;&amp;quot; then&lt;br /&gt;
        str = str .. &amp;quot;&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return str:gsub(&amp;quot;\n&amp;quot;, &amp;quot; &amp;quot;) -- Remove newlines as they break italics.&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; W R A P _ S T Y L E &amp;gt;----------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Applies styling to various parameters.  Supplied string is wrapped using a message_list configuration taking one&lt;br /&gt;
argument; protects italic styled parameters.  Additional text taken from citation_config.presentation - the reason&lt;br /&gt;
this function is similar to but separate from wrap_msg().&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
local function wrap_style(key, str)&lt;br /&gt;
    if not is_set(str) then&lt;br /&gt;
        return &amp;quot;&amp;quot;&lt;br /&gt;
    elseif in_array(key, {&amp;quot;italic-title&amp;quot;, &amp;quot;trans-italic-title&amp;quot;}) then&lt;br /&gt;
        str = safe_for_italics(str)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return substitute(cfg.presentation[key], {str})&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; M A K E _ S E P _ L I S T &amp;gt;------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
make a separated list of items using provided separators.&lt;br /&gt;
	&amp;lt;sep_list&amp;gt; - typically &amp;#039;&amp;lt;comma&amp;gt;&amp;lt;space&amp;gt;&amp;#039;&lt;br /&gt;
	&amp;lt;sep_list_pair&amp;gt; - typically &amp;#039;&amp;lt;space&amp;gt;and&amp;lt;space&amp;gt;&amp;#039;&lt;br /&gt;
	&amp;lt;sep_list_end&amp;gt; - typically &amp;#039;&amp;lt;comma&amp;gt;&amp;lt;space&amp;gt;and&amp;lt;space&amp;gt;&amp;#039; or &amp;#039;&amp;lt;comma&amp;gt;&amp;lt;space&amp;gt;&amp;amp;&amp;lt;space&amp;gt;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
defaults to cfg.presentation[&amp;#039;sep_list&amp;#039;], cfg.presentation[&amp;#039;sep_list_pair&amp;#039;], and cfg.presentation[&amp;#039;sep_list_end&amp;#039;]&lt;br /&gt;
if &amp;lt;sep_list_end&amp;gt; is specified, &amp;lt;sep_list&amp;gt; and &amp;lt;sep_list_pair&amp;gt; must also be supplied&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
local function make_sep_list(count, list_seq, sep_list, sep_list_pair, sep_list_end)&lt;br /&gt;
    local list = &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    if not sep_list then -- set the defaults&lt;br /&gt;
        sep_list = cfg.presentation[&amp;quot;sep_list&amp;quot;]&lt;br /&gt;
        sep_list_pair = cfg.presentation[&amp;quot;sep_list_pair&amp;quot;]&lt;br /&gt;
        sep_list_end = cfg.presentation[&amp;quot;sep_list_end&amp;quot;]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if 2 &amp;gt;= count then&lt;br /&gt;
        list = table.concat(list_seq, sep_list_pair) -- insert separator between two items; returns list_seq[1] then only one item&lt;br /&gt;
    elseif 2 &amp;lt; count then&lt;br /&gt;
        list = table.concat(list_seq, sep_list, 1, count - 1) -- concatenate all but last item with plain list separator&lt;br /&gt;
        list = table.concat({list, list_seq[count]}, sep_list_end) -- concatenate last item onto end of &amp;lt;list&amp;gt; with final separator&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return list&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; S E L E C T _ O N E &amp;gt;----------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Chooses one matching parameter from a list of parameters to consider.  The list of parameters to consider is just&lt;br /&gt;
names.  For parameters that may be enumerated, the position of the numerator in the parameter name is identified&lt;br /&gt;
by the &amp;#039;#&amp;#039; so |author-last1= and |author1-last= are represented as &amp;#039;author-last#&amp;#039; and &amp;#039;author#-last&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
Because enumerated parameter |&amp;lt;param&amp;gt;1= is an alias of |&amp;lt;param&amp;gt;= we must test for both possibilities.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Generates an error if more than one match is present.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
local function select_one(args, aliases_list, error_condition, index)&lt;br /&gt;
    local value = nil -- the value assigned to the selected parameter&lt;br /&gt;
    local selected = &amp;quot;&amp;quot; -- the name of the parameter we have chosen&lt;br /&gt;
    local error_list = {}&lt;br /&gt;
&lt;br /&gt;
    if index ~= nil then&lt;br /&gt;
        index = tostring(index)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    for _, alias in ipairs(aliases_list) do -- for each alias in the aliases list&lt;br /&gt;
        if alias:match(&amp;quot;#&amp;quot;) then -- if this alias can be enumerated&lt;br /&gt;
            if &amp;quot;1&amp;quot; == index then -- when index is 1 test for enumerated and non-enumerated aliases&lt;br /&gt;
                value, selected = is_alias_used(args, alias, index, false, value, selected, error_list) -- first test for non-enumerated alias&lt;br /&gt;
            end&lt;br /&gt;
            value, selected = is_alias_used(args, alias, index, true, value, selected, error_list) -- test for enumerated alias&lt;br /&gt;
        else&lt;br /&gt;
            value, selected = is_alias_used(args, alias, index, false, value, selected, error_list) -- test for non-enumerated alias&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if #error_list &amp;gt; 0 and &amp;quot;none&amp;quot; ~= error_condition then -- for cases where this code is used outside of extract_names()&lt;br /&gt;
        for i, v in ipairs(error_list) do&lt;br /&gt;
            error_list[i] = wrap_style(&amp;quot;parameter&amp;quot;, v)&lt;br /&gt;
        end&lt;br /&gt;
        table.insert(error_list, wrap_style(&amp;quot;parameter&amp;quot;, selected))&lt;br /&gt;
        set_message(error_condition, {make_sep_list(#error_list, error_list)})&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return value, selected&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[=[-------------------------&amp;lt; R E M O V E _ W I K I _ L I N K &amp;gt;----------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Gets the display text from a wikilink like [[A|B]] or [[B]] gives B&lt;br /&gt;
&lt;br /&gt;
The str:gsub() returns either A|B froma [[A|B]] or B from [[B]] or B from B (no wikilink markup).&lt;br /&gt;
&lt;br /&gt;
In l(), l:gsub() removes the link and pipe (if they exist); the second :gsub() trims whitespace from the label&lt;br /&gt;
if str was wrapped in wikilink markup.  Presumably, this is because without wikimarkup in str, there is no match&lt;br /&gt;
in the initial gsub, the replacement function l() doesn&amp;#039;t get called.&lt;br /&gt;
&lt;br /&gt;
]=]&lt;br /&gt;
&lt;br /&gt;
local function remove_wiki_link(str)&lt;br /&gt;
    return (str:gsub(&lt;br /&gt;
        &amp;quot;%[%[([^%[%]]*)%]%]&amp;quot;,&lt;br /&gt;
        function(l)&lt;br /&gt;
            return l:gsub(&amp;quot;^[^|]*|(.*)$&amp;quot;, &amp;quot;%1&amp;quot;):gsub(&amp;quot;^%s*(.-)%s*$&amp;quot;, &amp;quot;%1&amp;quot;)&lt;br /&gt;
        end&lt;br /&gt;
    ))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[=[-------------------------&amp;lt; I S _ W I K I L I N K &amp;gt;--------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Determines if str is a wikilink, extracts, and returns the wikilink type, link text, and display text parts.&lt;br /&gt;
If str is a complex wikilink ([[L|D]]):&lt;br /&gt;
	returns wl_type 2 and D and L from [[L|D]];&lt;br /&gt;
if str is a simple wikilink ([[D]])&lt;br /&gt;
	returns wl_type 1 and D from [[D]] and L as empty string;&lt;br /&gt;
if not a wikilink:&lt;br /&gt;
	returns wl_type 0, str as D, and L as empty string.&lt;br /&gt;
&lt;br /&gt;
trims leading and trailing whitespace and pipes from L and D ([[L|]] and [[|D]] are accepted by MediaWiki and&lt;br /&gt;
treated like [[D]]; while [[|D|]] is not accepted by MediaWiki, here, we accept it and return D without the pipes).&lt;br /&gt;
&lt;br /&gt;
]=]&lt;br /&gt;
&lt;br /&gt;
local function is_wikilink(str)&lt;br /&gt;
    local D, L&lt;br /&gt;
    local wl_type = 2 -- assume that str is a complex wikilink [[L|D]]&lt;br /&gt;
&lt;br /&gt;
    if not str:match(&amp;quot;^%[%[[^%]]+%]%]$&amp;quot;) then -- is str some sort of a wikilink (must have some sort of content)&lt;br /&gt;
        return 0, str, &amp;quot;&amp;quot; -- not a wikilink; return wl_type as 0, str as D, and empty string as L&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    L, D = str:match(&amp;quot;^%[%[([^|]+)|([^%]]+)%]%]$&amp;quot;) -- get L and D from [[L|D]]&lt;br /&gt;
&lt;br /&gt;
    if not is_set(D) then -- if no separate display&lt;br /&gt;
        D = str:match(&amp;quot;^%[%[([^%]]*)|*%]%]$&amp;quot;) -- get D from [[D]] or [[D|]]&lt;br /&gt;
        wl_type = 1&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    D = mw.text.trim(D, &amp;quot;%s|&amp;quot;) -- trim white space and pipe characters&lt;br /&gt;
    return wl_type, D, L or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; S T R I P _ A P O S T R O P H E _ M A R K U P &amp;gt;--------------------------------&lt;br /&gt;
&lt;br /&gt;
Strip wiki italic and bold markup from argument so that it doesn&amp;#039;t contaminate COinS metadata.&lt;br /&gt;
This function strips common patterns of apostrophe markup.  We presume that editors who have taken the time to&lt;br /&gt;
markup a title have, as a result, provided valid markup. When they don&amp;#039;t, some single apostrophes are left behind.&lt;br /&gt;
&lt;br /&gt;
Returns the argument without wiki markup and a number; the number is more-or-less meaningless except as a flag&lt;br /&gt;
to indicate that markup was replaced; do not rely on it as an indicator of how many of any kind of markup was&lt;br /&gt;
removed; returns the argument and nil when no markup removed&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
local function strip_apostrophe_markup(argument)&lt;br /&gt;
    if not is_set(argument) then&lt;br /&gt;
        return argument, nil -- no argument, nothing to do&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if nil == argument:find(&amp;quot;&amp;#039;&amp;#039;&amp;quot;, 1, true) then -- Is there at least one double apostrophe?  If not, exit.&lt;br /&gt;
        return argument, nil&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local flag&lt;br /&gt;
    while true do&lt;br /&gt;
        if argument:find(&amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;quot;, 1, true) then -- bold italic (5)&lt;br /&gt;
            argument, flag = argument:gsub(&amp;quot;%&amp;#039;%&amp;#039;%&amp;#039;%&amp;#039;%&amp;#039;&amp;quot;, &amp;quot;&amp;quot;) -- remove all instances of it&lt;br /&gt;
        elseif argument:find(&amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;quot;, 1, true) then -- italic start and end without content (4)&lt;br /&gt;
            argument, flag = argument:gsub(&amp;quot;%&amp;#039;%&amp;#039;%&amp;#039;%&amp;#039;&amp;quot;, &amp;quot;&amp;quot;)&lt;br /&gt;
        elseif argument:find(&amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;quot;, 1, true) then -- bold (3)&lt;br /&gt;
            argument, flag = argument:gsub(&amp;quot;%&amp;#039;%&amp;#039;%&amp;#039;&amp;quot;, &amp;quot;&amp;quot;)&lt;br /&gt;
        elseif argument:find(&amp;quot;&amp;#039;&amp;#039;&amp;quot;, 1, true) then -- italic (2)&lt;br /&gt;
            argument, flag = argument:gsub(&amp;quot;%&amp;#039;%&amp;#039;&amp;quot;, &amp;quot;&amp;quot;)&lt;br /&gt;
        else&lt;br /&gt;
            break&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return argument, flag -- done&lt;br /&gt;
end&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 to same (live or sandbox) as that used by the other modules.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
local function set_selected_modules(cfg_table_ptr)&lt;br /&gt;
    cfg = cfg_table_ptr&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; E X P O R T S &amp;gt;----------------------------------------------------------------&lt;br /&gt;
]]&lt;br /&gt;
return {&lt;br /&gt;
    add_maint_cat = add_maint_cat, -- exported functions&lt;br /&gt;
    add_prop_cat = add_prop_cat,&lt;br /&gt;
    error_comment = error_comment,&lt;br /&gt;
    has_accept_as_written = has_accept_as_written,&lt;br /&gt;
    hyphen_to_dash = hyphen_to_dash,&lt;br /&gt;
    in_array = in_array,&lt;br /&gt;
    is_set = is_set,&lt;br /&gt;
    is_wikilink = is_wikilink,&lt;br /&gt;
    make_sep_list = make_sep_list,&lt;br /&gt;
    make_wikilink = make_wikilink,&lt;br /&gt;
    remove_wiki_link = remove_wiki_link,&lt;br /&gt;
    safe_for_italics = safe_for_italics,&lt;br /&gt;
    select_one = select_one,&lt;br /&gt;
    set_message = set_message,&lt;br /&gt;
    set_selected_modules = set_selected_modules,&lt;br /&gt;
    strip_apostrophe_markup = strip_apostrophe_markup,&lt;br /&gt;
    substitute = substitute,&lt;br /&gt;
    wrap_style = wrap_style,&lt;br /&gt;
    z = z -- exported table&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>imported&gt;SockyPaws</name></author>
	</entry>
</feed>