end
return id_list;
end  
--[[--------------------------< E X T R A C T _ I D _ A C C E S S _ L E V E L S >--------------------------------------  
Fetches custom id access levels from arguments using configuration settings. Parameters which have a predefined access
level (e.g. arxiv) do not use this function as they are directly rendered as free without using an additional parameter.  
returns a table of k/v pairs where k is same as the identifier's key in cfg.id_handlers and v is the assigned (valid) keyword  
access-level values must match the case used in cfg.keywords_lists['id-access'] (lowercase unless there is some special reason for something else)  
local function extract_id_access_levels (args, id_list)
local id_accesses_list = {};
for k, v in pairs (cfg.id_handlers) do
local access_param = v.custom_access; -- name of identifier's access-level parameter
if is_set (access_param) then
local access_level = args[access_param]; -- get the assigned value if there is one
if is_set (access_level) then
if not in_array (access_level, cfg.keywords_lists['id-access']) then -- exact match required
set_message ('err_invalid_param_val', {access_param, access_level});
access_level = nil; -- invalid so unset
end
if not is_set (id_list[k]) then -- identifier access-level must have a matching identifier
set_message ('err_param_access_requires_param', {k:lower}); -- parameter name is uppercase in cfg.id_handlers (k); lowercase for error message
end
id_accesses_list[k] = cfg.keywords_xlate[access_level]; -- get translated keyword
end
end
end
return id_accesses_list;
end  
----------------------------< B U I L D _ I D _ L I S T >----------------------------------------------------  
render the identifiers into a sorted sequence table  
<ID_list_coins_t> is a table of k/v pairs where k is same as key in cfg.id_handlers and v is the assigned value
<options_t> is a table of various k/v option pairs provided in the call to new_build_id_list;
modified by this function and passed to all identifier rendering functions
<access_levels_t> is a table of k/v pairs where k is same as key in cfg.id_handlers and v is the assigned value (if valid)  
returns a sequence table of sorted (by hkey - 'handler' key) rendered identifier strings  
local function build_id_list (ID_list_coins_t, options_t, access_levels_t)
local ID_list_t = {};
local accept;
local func_map = { --function map points to functions associated with hkey identifier
['ARXIV'] = arxiv,
['ASIN'] = asin,
['BIBCODE'] = bibcode,
['BIORXIV'] = biorxiv,
['CITESEERX'] = citeseerx,
['DOI'] = doi,
['EISSN'] = issn,
['HDL'] = hdl,
['ISBN'] = isbn,
['ISMN'] = ismn,
['ISSN'] = issn,
['JFM'] = jfm,
['JSTOR'] = jstor,
['LCCN'] = lccn,
['MEDRXIV'] = medrxiv,
['MR'] = mr,
['OCLC'] = oclc,
['OL'] = openlibrary,
['OSTI'] = osti,
['PMC'] = pmc,
['PMID'] = pmid,
['RFC'] = rfc,
['S2CID'] = s2cid,
['SBN'] = sbn,
['SSRN'] = ssrn,
['USENETID'] = usenet_id,
['ZBL'] = zbl,
}  
for hkey, v in pairs (ID_list_coins_t) do
v, accept = has_accept_as_written (v); -- remove accept-as-written markup if present; accept is boolean true when markup removed; false else
-- every function gets the options table with value v and accept boolean
options_t.hkey = hkey; -- ~/Configuration handler key
options_t.id = v; -- add that identifier value to the options table
options_t.accept = accept; -- add the accept boolean flag
options_t.access = access_levels_t[hkey]; -- add the access level for those that have an |<identifier-access= parameter
options_t.handler = cfg.id_handlers[hkey];
options_t.coins_list_t = ID_list_coins_t; -- pointer to ID_list_coins_t; for |asin= and |ol=; also to keep erroneous values out of the citation's metadata
options_t.coins_list_t[hkey] = v; -- id value without accept-as-written markup for metadata  
if options_t.handler.access and not in_array (options_t.handler.access, cfg.keywords_lists['id-access']) then
error (cfg.messages['unknown_ID_access'] .. options_t.handler.access); -- here when handler access key set to a value not listed in list of allowed id access keywords
end  
if func_map[hkey] then
local id_text = func_map[hkey] (options_t); -- call the function to get identifier text and any error message
table.insert (ID_list_t, {hkey, id_text}); -- add identifier text to the output sequence table
else
error (cfg.messages['unknown_ID_key'] .. hkey); -- here when func_map doesn't have a function for hkey
end
end  
local function comp (a, b) -- used by following table.sort
return a[1]:lower < b[1]:lower; -- sort by hkey
end  
table.sort (ID_list_t, comp); -- sequence table of tables sort
for k, v in ipairs (ID_list_t) do -- convert sequence table of tables to simple sequence table of strings
ID_list_t[k] = v[2]; -- v[2] is the identifier rendering from the call to the various functions in func_map{}
end  
return ID_list_t;
end  
--[[--------------------------< O P T I O N S _ C H E C K >----------------------------------------------------  
check that certain option parameters have their associated identifier parameters with values  
<ID_list_coins_t> is a table of k/v pairs where k is same as key in cfg.id_handlers and v is the assigned value
<ID_support_t> is a sequence table of tables created in citation0 where each subtable has four elements:
[1] is the support parameter's assigned value; empty string if not set
[2] is a text string same as key in cfg.id_handlers
[3] is cfg.error_conditions key used to create error message
[4] is original ID support parameter name used to create error message  
returns nothing; on error emits an appropriate error message  
local function options_check (ID_list_coins_t, ID_support_t)
for _, v in ipairs (ID_support_t) do
if is_set (v[1]) and not ID_list_coins_t[v[2]] then -- when support parameter has a value but matching identifier parameter is missing or empty
set_message (v[3], (v[4])); -- emit the appropriate error message
end
end
end  
----------------------------< I D E N T I F I E R _ L I S T S _ G E T >--------------------------------------  
Creates two identifier lists: a k/v table of identifiers and their values to be used locally and for use in the
COinS metadata, and a sequence table of the rendered identifier strings that will be included in the rendered
citation.  
local function identifier_lists_get (args_t, options_t, ID_support_t)
local ID_list_coins_t = extract_ids (args_t); -- get a table of identifiers and their values for use locally and for use in COinS
options_check (ID_list_coins_t, ID_support_t); -- ID support parameters must have matching identifier parameters
local ID_access_levels_t = extract_id_access_levels (args_t, ID_list_coins_t); -- get a table of identifier access levels
local ID_list_t = build_id_list (ID_list_coins_t, options_t, ID_access_levels_t); -- get a sequence table of rendered identifier strings  
return ID_list_t, ID_list_coins_t; -- return the tables
end  
----------------------------< S E T _ S E L E C T E D _ M O D U L E S >--------------------------------------  
Sets local cfg table and imported functions table to same (live or sandbox) as that used by the other modules.  
local function set_selected_modules (cfg_table_ptr, utilities_page_ptr)
cfg = cfg_table_ptr;  
has_accept_as_written = utilities_page_ptr.has_accept_as_written; -- import functions from select Module:Citation/CS1/Utilities module
is_set = utilities_page_ptr.is_set;
in_array = utilities_page_ptr.in_array;
set_message = utilities_page_ptr.set_message;
select_one = utilities_page_ptr.select_one;
substitute = utilities_page_ptr.substitute;
make_wikilink = utilities_page_ptr.make_wikilink;  
z = utilities_page_ptr.z; -- table of tables in Module:Citation/CS1/Utilities
end  
----------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------  
return {
auto_link_urls = auto_link_urls, -- table of identifier URLs to be used when auto-linking |title=