dup_aliases_check (param, alias, aliases_t, out)
local alias_i = alias:gsub ('%d+', '#'); -- in case an enumerated parameter, convert the enumerate digits to a single '#' character
if not validate_basic_param (alias_i) and not validate_id_alias (param, alias) then -- for isbn13 (while still supported) must not mask the digits
table.insert (out, alias_error_msg (param, alias));
elseif cfg_aliases_t[param_i:gsub ('#', *)] ~= cfg_aliases_t[alias_i:gsub ('#', *)] then -- is 'alias' known to be an alias of 'param'?
table.insert (out, alias_error_msg (param, alias));
end
end
end
else -- here when param not valid
table.insert (out, param_error_msg (param))
end
end
end
end  
---------- this emits errors when page/pages/at listed in templatedata of templates that don't support those parameters ----------
-- if json_t then
-- if ({['citeavmedia']=true, ['citeepisode']=true, ['citemailinglist']=true, ['citenewsgroup']=true, ['citepodcast']=true, ['citeserial']=true, ['citesign']=true, ['citespeech']=true})[template_idx] then
-- local insource_params_t = {}; -- build sequence of pagination params not supported by these templates
-- for _, meta_param in ipairs ({'At', 'Page', 'Pages', 'QuotePage', 'QuotePages'}) do
-- if 'table' == type (cfg.aliases[meta_param]) then
-- for _, alias in ipairs (cfg.aliases[meta_param]) do -- metaparameter is a sequence
-- table.insert (insource_params_t, alias); -- add the aliases from the metaparameter sequence to the table
-- end
-- else -- metaparameter is plain text
-- table.insert (insource_params_t, cfg.aliases[meta_param]); -- add the alias to the table
-- end
-- end
---
-- for _, param in ipairs (insource_params_t) do
-- if json_t.params[param] then
-- table.insert (out, param_error_msg (param)); -- error; this parameter not supported by this template
-- end
-- end
-- end
-- end
---------- end page/pages/at error detection ----------  
if 0 ~= #out then
table.sort (out);
out[1] = '*' .. out[1]; -- add a splat to the first error message  
-- return table.concat ({'' .. template_doc .. ' TemplateData has errors:<div>\n', table.concat (out, '\n*'), '</div>'});
return table.concat ({
'[[Template:' .. args_t[1] .. ']] uses ',
whitelist.preprint_arguments_t[template_t[2]] and 'preprint and limited parameter sets' or (whitelist.unique_arguments_t[template_t[2]] and 'unique and standard parameter sets' or 'standard parameter set'),
'; TemplateData has errors:\n',
'<div>\n', table.concat (out, '\n*'), '</div>'
});
else
return; -- no errors detected; return nothing
end
end  
----------------------------< E R R O R _ C A T _ P A G E _ T A L L Y >--------------------------------------  
loop through Module:Citation/CS1/Configuration error_conditions {} fetching error category names. For each error
category add the number of pages in the category to the tally. Render the number when done.  
local function error_cat_page_tally
local error_conditions_t = cfg.error_conditions; -- get the table of error conditions
local tally = 0;
local cat_t = {}; -- some error message share a category; save tallied cats here so we don't recount the already counted
local i = 0; -- number of categories  
for k, v_t in pairs (error_conditions_t) do
if k:match ('^err') then
if not cat_t[v_t.category] then
cat_t[v_t.category] = true;
tally = tally + mw.site.stats.pagesInCategory (v_t.category, 'pages'); -- get category page count; ignore subcats and files
i = i + 1;
end
end
end  
return mw.language.getContentLanguage:formatNum (tally)
end  
----------------------------< M A I N T _ C A T _ P A G E _ T A L L Y >--------------------------------------  
loop through Module:Citation/CS1/Configuration error_conditions {} fetching error category names. For each error
category add the number of pages in the category to the tally. Render the number when done.  
Dynamic subcats of CS1 maint: DOI inactive not counted because these names come and go as time goes by.  
local function maint_cat_page_tally
local error_conditions_t = cfg.error_conditions; -- get the table of error conditions
local tally = 0;
local cat_t = {}; -- some error message share a category; save tallied cats here so we don't recount the already counted
local i = 0; -- number of categories  
for k, v_t in pairs (error_conditions_t) do
if not k:match ('^err') then -- if not an error key its a maint key
if not cat_t[v_t.category] then
cat_t[v_t.category] = true;
if 'maint_mult_names' == k or 'maint_numeric_names' == k then
local special_case_translation_t = cfg.special_case_translation;
for _, name in ipairs ({'AuthorList', 'ContributorList', 'EditorList', 'InterviewerList', 'TranslatorList'}) do
local cat_name = v_t.category:gsub ('$1', special_case_translation_t[name]); -- replace $1 with translated list name
tally = tally + mw.site.stats.pagesInCategory (cat_name, 'pages'); -- get category page count; ignore subcats and files
i = i + 1;
end
else
tally = tally + mw.site.stats.pagesInCategory (v_t.category, 'pages'); -- get category page count; ignore subcats and files
i = i + 1;
end
end
end
end  
return mw.language.getContentLanguage:formatNum (tally)
end  
--2 does not categorize.  
For convenience,  
returns a list of all namespace names and identifiers used on the current wiki. Any namespace with an
identifier less than 1, currently Mainspace (0), Special (-1), and Media (-2), is excluded from the list.  
local function uncategorized_namespace_lister
local list_t = {};
local function compare (a, b) -- local function to sort namespaces numerically by the identifiers
local a_num = tonumber (a:match ('%d+')); -- get identifiers and convert to numbers
local b_num = tonumber (b:match ('%d+'));
return a_num < b_num; -- do the comparison
end  
for i, _ in pairs (mw.site.namespaces) do -- for each namespace in the table
if '' == .args.all or not .args.all then -- when |all= not set, make a list of uncategorized namespaces
if cfg.uncategorized_namespaces[i] then -- if the identifier is listed in our uncategorized namespace list
table.insert (list_t, table.concat ({mw.site.namespaces[i].name, ' (', i, ')'})) -- add name and identifier to our local list
end
elseif 0 < i then -- |all=<anything>: all namespace names and identifiers; ignore identifiers less than 1
table.insert (list_t, table.concat ({'*', mw.site.namespaces[i].name, ' (', i, ')'})) -- add name and identifier as an unordered list item
end
end  
table.sort (list_t, compare); -- ascending numerical sort by identifier  
if not .args.all then -- when |all= not set, format list of uncategorized namespaces and identifiers
list_t[#list_t] = 'and ' .. list_t[#list_t]; -- add 'and ' to the last name/identifier pair
return table.concat (list_t, ', '); -- make a big string and done
else -- make list of all namespaces and identifiers
return table.concat (list_t, '\n'); -- make a big string and done
end
end  
----------------------------< S I N G L E _ L T R _ 2 N D _ L V L _ D O M A I N _ L I S T E R >-------------  
for Help:CS1_errors#bad_url, list the supported top level domains that support single-letter 2nd level names  
local function single_ltr_2nd_lvl_domain_lister
local out_t = {}; -- output goes here
for _, tld in ipairs (cfg.single_letter_2nd_lvl_domains_t) do -- fetch each tld
table.insert (out_t, '.' .. tld); -- prefix with a dot and save in out_t{}
end
return table.concat (out_t, ', '); -- make a big string and done
end  
--[[--------------------------< C O D E _ N A M E _ P A I R _ E X I S T S >----------------------------------------  
Returns language code if pair exists, nil if either code doesn't exist or the name doesn't match.
Intended for use by Template:CS1 language sources/core  
args[1] is language code
args[2] is language name  
local function code_name_pair_exists
local wiki_language = mw.getContentLanguage:getCode
local source_list = mw.language.fetchLanguageNames(wiki_language, 'all');
local code_list = {};
local name_list = {};
local override = cfg.lang_tag_remap;  
for code, name in pairs(source_list) do