<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://en.stargatewiki.noip.me/index.php?action=history&amp;feed=atom&amp;title=Module%3ACitation%2FCS1%2FIdentifiers</id>
	<title>Module:Citation/CS1/Identifiers - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://en.stargatewiki.noip.me/index.php?action=history&amp;feed=atom&amp;title=Module%3ACitation%2FCS1%2FIdentifiers"/>
	<link rel="alternate" type="text/html" href="https://en.stargatewiki.noip.me/index.php?title=Module:Citation/CS1/Identifiers&amp;action=history"/>
	<updated>2026-04-28T09:21:59Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.44.0</generator>
	<entry>
		<id>https://en.stargatewiki.noip.me/index.php?title=Module:Citation/CS1/Identifiers&amp;diff=122&amp;oldid=prev</id>
		<title>LIMAFOX76: Created page with &quot;local identifiers = {};   ----------------------------&lt; F O R W A R D   D E C L A R A T I O N S &gt;--------------------------------------   local is_set, in_array, set_error...&quot;</title>
		<link rel="alternate" type="text/html" href="https://en.stargatewiki.noip.me/index.php?title=Module:Citation/CS1/Identifiers&amp;diff=122&amp;oldid=prev"/>
		<updated>2016-01-30T21:51:44Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;local identifiers = {};   --[[--------------------------&amp;lt; F O R W A R D   D E C L A R A T I O N S &amp;gt;-------------------------------------- ]]  local is_set, in_array, set_error...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local identifiers = {};&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;
&lt;br /&gt;
local is_set, in_array, set_error, select_one, add_maint_cat;					-- 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;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; E X T E R N A L _ L I N K _ I D &amp;gt;----------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Formats a wiki style external link&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function external_link_id(options)&lt;br /&gt;
	local url_string = options.id;&lt;br /&gt;
	if options.encode == true or options.encode == nil then&lt;br /&gt;
		url_string = mw.uri.encode( url_string );&lt;br /&gt;
	end&lt;br /&gt;
	return mw.ustring.format( &amp;#039;[[%s|%s]]%s[%s%s%s %s]&amp;#039;,&lt;br /&gt;
		options.link, options.label, options.separator or &amp;quot;&amp;amp;nbsp;&amp;quot;,&lt;br /&gt;
		options.prefix, url_string, options.suffix or &amp;quot;&amp;quot;,&lt;br /&gt;
		mw.text.nowiki(options.id)&lt;br /&gt;
	);&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; I N T E R N A L _ L I N K _ I D &amp;gt;----------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Formats a wiki style internal link&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function internal_link_id(options)&lt;br /&gt;
	return mw.ustring.format( &amp;#039;[[%s|%s]]%s[[%s%s%s|%s]]&amp;#039;,&lt;br /&gt;
		options.link, options.label, options.separator or &amp;quot;&amp;amp;nbsp;&amp;quot;,&lt;br /&gt;
		options.prefix, options.id, options.suffix or &amp;quot;&amp;quot;,&lt;br /&gt;
		mw.text.nowiki(options.id)&lt;br /&gt;
	);&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; IS _ V A L I D _ I S X N &amp;gt;-----------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
ISBN-10 and ISSN validator code calculates checksum across all isbn/issn digits including the check digit.&lt;br /&gt;
ISBN-13 is checked in check_isbn().&lt;br /&gt;
&lt;br /&gt;
If the number is valid the result will be 0. Before calling this function, issbn/issn must be checked for length&lt;br /&gt;
and stripped of dashes, spaces and other non-isxn characters.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function is_valid_isxn (isxn_str, len)&lt;br /&gt;
	local temp = 0;&lt;br /&gt;
	isxn_str = { isxn_str:byte(1, len) };	-- make a table of byte values &amp;#039;0&amp;#039; → 0x30 .. &amp;#039;9&amp;#039;  → 0x39, &amp;#039;X&amp;#039; → 0x58&lt;br /&gt;
	len = len+1;							-- adjust to be a loop counter&lt;br /&gt;
	for i, v in ipairs( isxn_str ) do		-- loop through all of the bytes and calculate the checksum&lt;br /&gt;
		if v == string.byte( &amp;quot;X&amp;quot; ) then		-- if checkdigit is X (compares the byte value of &amp;#039;X&amp;#039; which is 0x58)&lt;br /&gt;
			temp = temp + 10*( len - i );	-- it represents 10 decimal&lt;br /&gt;
		else&lt;br /&gt;
			temp = temp + tonumber( string.char(v) )*(len-i);&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return temp % 11 == 0;					-- returns true if calculation result is zero&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; IS _ V A L I D _ I S X N  _ 1 3 &amp;gt;----------------------------------------------&lt;br /&gt;
&lt;br /&gt;
ISBN-13 and ISMN validator code calculates checksum across all 13 isbn/ismn digits including the check digit.&lt;br /&gt;
If the number is valid, the result will be 0. Before calling this function, isbn-13/ismn must be checked for length&lt;br /&gt;
and stripped of dashes, spaces and other non-isxn-13 characters.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function is_valid_isxn_13 (isxn_str)&lt;br /&gt;
	local temp=0;&lt;br /&gt;
	&lt;br /&gt;
	isxn_str = { isxn_str:byte(1, 13) };										-- make a table of byte values &amp;#039;0&amp;#039; → 0x30 .. &amp;#039;9&amp;#039;  → 0x39&lt;br /&gt;
	for i, v in ipairs( isxn_str ) do&lt;br /&gt;
		temp = temp + (3 - 2*(i % 2)) * tonumber( string.char(v) );				-- multiply odd index digits by 1, even index digits by 3 and sum; includes check digit&lt;br /&gt;
	end&lt;br /&gt;
	return temp % 10 == 0;														-- sum modulo 10 is zero when isbn-13/ismn is correct&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; C H E C K _ I S B N &amp;gt;------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Determines whether an ISBN string is valid&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function check_isbn( isbn_str )&lt;br /&gt;
	if nil ~= isbn_str:match(&amp;quot;[^%s-0-9X]&amp;quot;) then return false; end		-- fail if isbn_str contains anything but digits, hyphens, or the uppercase X&lt;br /&gt;
	isbn_str = isbn_str:gsub( &amp;quot;-&amp;quot;, &amp;quot;&amp;quot; ):gsub( &amp;quot; &amp;quot;, &amp;quot;&amp;quot; );	-- remove hyphens and spaces&lt;br /&gt;
	local len = isbn_str:len();&lt;br /&gt;
 &lt;br /&gt;
	if len ~= 10 and len ~= 13 then&lt;br /&gt;
		return false;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if len == 10 then&lt;br /&gt;
		if isbn_str:match( &amp;quot;^%d*X?$&amp;quot; ) == nil then return false; end&lt;br /&gt;
		return is_valid_isxn(isbn_str, 10);&lt;br /&gt;
	else&lt;br /&gt;
		local temp = 0;&lt;br /&gt;
		if isbn_str:match( &amp;quot;^97[89]%d*$&amp;quot; ) == nil then return false; end		-- isbn13 begins with 978 or 979; ismn begins with 979&lt;br /&gt;
		return is_valid_isxn_13 (isbn_str);&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; I S M N &amp;gt;----------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Determines whether an ISMN string is valid.  Similar to isbn-13, ismn is 13 digits begining 979-0-... and uses the&lt;br /&gt;
same check digit calculations.  See http://www.ismn-international.org/download/Web_ISMN_Users_Manual_2008-6.pdf&lt;br /&gt;
section 2, pages 9–12.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function ismn (id)&lt;br /&gt;
	local handler = cfg.id_handlers[&amp;#039;ISMN&amp;#039;];&lt;br /&gt;
	local text;&lt;br /&gt;
	local valid_ismn = true;&lt;br /&gt;
&lt;br /&gt;
	id=id:gsub( &amp;quot;[%s-–]&amp;quot;, &amp;quot;&amp;quot; );													-- strip spaces, hyphens, and endashes from the ismn&lt;br /&gt;
&lt;br /&gt;
	if 13 ~= id:len() or id:match( &amp;quot;^9790%d*$&amp;quot; ) == nil then					-- ismn must be 13 digits and begin 9790&lt;br /&gt;
		valid_ismn = false;&lt;br /&gt;
	else&lt;br /&gt;
		valid_ismn=is_valid_isxn_13 (id);										-- validate ismn&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
--	text = internal_link_id({link = handler.link, label = handler.label,		-- use this (or external version) when there is some place to link to&lt;br /&gt;
--		prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode})&lt;br /&gt;
 &lt;br /&gt;
	text=&amp;quot;[[&amp;quot; .. handler.link .. &amp;quot;|&amp;quot; .. handler.label .. &amp;quot;]]&amp;quot; .. handler.separator .. id;		-- because no place to link to yet&lt;br /&gt;
&lt;br /&gt;
	if false == valid_ismn then&lt;br /&gt;
		text = text .. &amp;#039; &amp;#039; .. set_error( &amp;#039;bad_ismn&amp;#039; )							-- add an error message if the ismn is invalid&lt;br /&gt;
	end &lt;br /&gt;
	&lt;br /&gt;
	return text;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; I S S N &amp;gt;----------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Validate and format an issn.  This code fixes the case where an editor has included an ISSN in the citation but&lt;br /&gt;
has separated the two groups of four digits with a space.  When that condition occurred, the resulting link looked&lt;br /&gt;
like this:&lt;br /&gt;
&lt;br /&gt;
	|issn=0819 4327 gives: [http://www.worldcat.org/issn/0819 4327 0819 4327]  -- can&amp;#039;t have spaces in an external link&lt;br /&gt;
	&lt;br /&gt;
This code now prevents that by inserting a hyphen at the issn midpoint.  It also validates the issn for length&lt;br /&gt;
and makes sure that the checkdigit agrees with the calculated value.  Incorrect length (8 digits), characters&lt;br /&gt;
other than 0-9 and X, or checkdigit / calculated value mismatch will all cause a check issn error message.  The&lt;br /&gt;
issn is always displayed with a hyphen, even if the issn was given as a single group of 8 digits.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function issn(id, e)&lt;br /&gt;
	local issn_copy = id;		-- save a copy of unadulterated issn; use this version for display if issn does not validate&lt;br /&gt;
	local handler;&lt;br /&gt;
	local text;&lt;br /&gt;
	local valid_issn = true;&lt;br /&gt;
	&lt;br /&gt;
	if e then&lt;br /&gt;
		 handler = cfg.id_handlers[&amp;#039;EISSN&amp;#039;];&lt;br /&gt;
	else&lt;br /&gt;
		 handler = cfg.id_handlers[&amp;#039;ISSN&amp;#039;];&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	id=id:gsub( &amp;quot;[%s-–]&amp;quot;, &amp;quot;&amp;quot; );									-- strip spaces, hyphens, and endashes from the issn&lt;br /&gt;
&lt;br /&gt;
	if 8 ~= id:len() or nil == id:match( &amp;quot;^%d*X?$&amp;quot; ) then		-- validate the issn: 8 digits long, containing only 0-9 or X in the last position&lt;br /&gt;
		valid_issn=false;										-- wrong length or improper character&lt;br /&gt;
	else&lt;br /&gt;
		valid_issn=is_valid_isxn(id, 8);						-- validate issn&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if true == valid_issn then&lt;br /&gt;
		id = string.sub( id, 1, 4 ) .. &amp;quot;-&amp;quot; .. string.sub( id, 5 );	-- if valid, display correctly formatted version&lt;br /&gt;
	else&lt;br /&gt;
		id = issn_copy;											-- if not valid, use the show the invalid issn with error message&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	text = external_link_id({link = handler.link, label = handler.label,&lt;br /&gt;
		prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode})&lt;br /&gt;
 &lt;br /&gt;
	if false == valid_issn then&lt;br /&gt;
		text = text .. &amp;#039; &amp;#039; .. set_error( &amp;#039;bad_issn&amp;#039;, e and &amp;#039;e&amp;#039; or &amp;#039;&amp;#039; )			-- add an error message if the issn is invalid&lt;br /&gt;
	end &lt;br /&gt;
	&lt;br /&gt;
	return text&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; A M A Z O N &amp;gt;------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Formats a link to Amazon.  Do simple error checking: asin must be mix of 10 numeric or uppercase alpha&lt;br /&gt;
characters.  If a mix, first character must be uppercase alpha; if all numeric, asins must be 10-digit&lt;br /&gt;
isbn. If 10-digit isbn, add a maintenance category so a bot or awb script can replace |asin= with |isbn=.&lt;br /&gt;
Error message if not 10 characters, if not isbn10, if mixed and first character is a digit.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function amazon(id, domain)&lt;br /&gt;
	local err_cat = &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	if not id:match(&amp;quot;^[%d%u][%d%u][%d%u][%d%u][%d%u][%d%u][%d%u][%d%u][%d%u][%d%u]$&amp;quot;) then&lt;br /&gt;
		err_cat =  &amp;#039; &amp;#039; .. set_error (&amp;#039;bad_asin&amp;#039;);								-- asin is not a mix of 10 uppercase alpha and numeric characters&lt;br /&gt;
	else&lt;br /&gt;
		if id:match(&amp;quot;^%d%d%d%d%d%d%d%d%d[%dX]$&amp;quot;) then								-- if 10-digit numeric (or 9 digits with terminal X)&lt;br /&gt;
			if check_isbn( id ) then												-- see if asin value is isbn10&lt;br /&gt;
				add_maint_cat (&amp;#039;ASIN&amp;#039;);&lt;br /&gt;
			elseif not is_set (err_cat) then&lt;br /&gt;
				err_cat =  &amp;#039; &amp;#039; .. set_error (&amp;#039;bad_asin&amp;#039;);						-- asin is not isbn10&lt;br /&gt;
			end&lt;br /&gt;
		elseif not id:match(&amp;quot;^%u[%d%u]+$&amp;quot;) then&lt;br /&gt;
			err_cat =  &amp;#039; &amp;#039; .. set_error (&amp;#039;bad_asin&amp;#039;);							-- asin doesn&amp;#039;t begin with uppercase alpha&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if not is_set(domain) then &lt;br /&gt;
		domain = &amp;quot;com&amp;quot;;&lt;br /&gt;
	elseif in_array (domain, {&amp;#039;jp&amp;#039;, &amp;#039;uk&amp;#039;}) then			-- Japan, United Kingdom&lt;br /&gt;
		domain = &amp;quot;co.&amp;quot; .. domain;&lt;br /&gt;
	elseif in_array (domain, {&amp;#039;au&amp;#039;, &amp;#039;br&amp;#039;, &amp;#039;mx&amp;#039;}) then	-- Australia, Brazil, Mexico&lt;br /&gt;
		domain = &amp;quot;com.&amp;quot; .. domain;&lt;br /&gt;
	end&lt;br /&gt;
	local handler = cfg.id_handlers[&amp;#039;ASIN&amp;#039;];&lt;br /&gt;
	return external_link_id({link=handler.link,&lt;br /&gt;
		label=handler.label, prefix=handler.prefix .. domain .. &amp;quot;/dp/&amp;quot;,&lt;br /&gt;
		id=id, encode=handler.encode, separator = handler.separator}) .. err_cat;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; A R X I V &amp;gt;--------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
See: http://arxiv.org/help/arxiv_identifier&lt;br /&gt;
&lt;br /&gt;
format and error check arXiv identifier.  There are three valid forms of the identifier:&lt;br /&gt;
the first form, valid only between date codes 9108 and 0703 is:&lt;br /&gt;
	arXiv:&amp;lt;archive&amp;gt;.&amp;lt;class&amp;gt;/&amp;lt;date code&amp;gt;&amp;lt;number&amp;gt;&amp;lt;version&amp;gt;&lt;br /&gt;
where:&lt;br /&gt;
	&amp;lt;archive&amp;gt; is a string of alpha characters - may be hyphenated; no other punctuation&lt;br /&gt;
	&amp;lt;class&amp;gt; is a string of alpha characters - may be hyphenated; no other punctuation&lt;br /&gt;
	&amp;lt;date code&amp;gt; is four digits in the form YYMM where YY is the last two digits of the four-digit year and MM is the month number January = 01&lt;br /&gt;
		first digit of YY for this form can only 9 and 0&lt;br /&gt;
	&amp;lt;number&amp;gt; is a three-digit number&lt;br /&gt;
	&amp;lt;version&amp;gt; is a 1 or more digit number preceded with a lowercase v; no spaces (undocumented)&lt;br /&gt;
	&lt;br /&gt;
the second form, valid from April 2007 through December 2014 is:&lt;br /&gt;
	arXiv:&amp;lt;date code&amp;gt;.&amp;lt;number&amp;gt;&amp;lt;version&amp;gt;&lt;br /&gt;
where:&lt;br /&gt;
	&amp;lt;date code&amp;gt; is four digits in the form YYMM where YY is the last two digits of the four-digit year and MM is the month number January = 01&lt;br /&gt;
	&amp;lt;number&amp;gt; is a four-digit number&lt;br /&gt;
	&amp;lt;version&amp;gt; is a 1 or more digit number preceded with a lowercase v; no spaces&lt;br /&gt;
&lt;br /&gt;
the third form, valid from January 2015 is:&lt;br /&gt;
	arXiv:&amp;lt;date code&amp;gt;.&amp;lt;number&amp;gt;&amp;lt;version&amp;gt;&lt;br /&gt;
where:&lt;br /&gt;
	&amp;lt;date code&amp;gt; and &amp;lt;version&amp;gt; are as defined for 0704-1412&lt;br /&gt;
	&amp;lt;number&amp;gt; is a five-digit number&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function arxiv (id, class)&lt;br /&gt;
	local handler = cfg.id_handlers[&amp;#039;ARXIV&amp;#039;];&lt;br /&gt;
	local year, month, version;&lt;br /&gt;
	local err_cat = &amp;#039;&amp;#039;;&lt;br /&gt;
	local text;&lt;br /&gt;
	&lt;br /&gt;
	if id:match(&amp;quot;^%a[%a%.%-]+/[90]%d[01]%d%d%d%d$&amp;quot;) or id:match(&amp;quot;^%a[%a%.%-]+/[90]%d[01]%d%d%d%dv%d+$&amp;quot;) then	-- test for the 9108-0703 format w/ &amp;amp; w/o version&lt;br /&gt;
		year, month = id:match(&amp;quot;^%a[%a%.%-]+/([90]%d)([01]%d)%d%d%d[v%d]*$&amp;quot;);&lt;br /&gt;
		year = tonumber(year);&lt;br /&gt;
		month = tonumber(month);&lt;br /&gt;
		if ((not (90 &amp;lt; year or 8 &amp;gt; year)) or (1 &amp;gt; month or 12 &amp;lt; month)) or		-- if invalid year or invalid month&lt;br /&gt;
			((91 == year and 7 &amp;gt; month) or (7 == year and 3 &amp;lt; month)) then		-- if years ok, are starting and ending months ok?&lt;br /&gt;
				err_cat = &amp;#039; &amp;#039; .. set_error( &amp;#039;bad_arxiv&amp;#039; );						-- set error message&lt;br /&gt;
		end&lt;br /&gt;
	elseif id:match(&amp;quot;^%d%d[01]%d%.%d%d%d%d$&amp;quot;) or id:match(&amp;quot;^%d%d[01]%d%.%d%d%d%dv%d+$&amp;quot;) then	-- test for the 0704-1412 w/ &amp;amp; w/o version&lt;br /&gt;
		year, month = id:match(&amp;quot;^(%d%d)([01]%d)%.%d%d%d%d[v%d]*$&amp;quot;);&lt;br /&gt;
		year = tonumber(year);&lt;br /&gt;
		month = tonumber(month);&lt;br /&gt;
		if ((7 &amp;gt; year) or (14 &amp;lt; year) or (1 &amp;gt; month or 12 &amp;lt; month)) or			-- is year invalid or is month invalid? (doesn&amp;#039;t test for future years)&lt;br /&gt;
			((7 == year) and (4 &amp;gt; month)) then --or									-- when year is 07, is month invalid (before April)?&lt;br /&gt;
				err_cat = &amp;#039; &amp;#039; .. set_error( &amp;#039;bad_arxiv&amp;#039; );						-- set error message&lt;br /&gt;
		end&lt;br /&gt;
	elseif id:match(&amp;quot;^%d%d[01]%d%.%d%d%d%d%d$&amp;quot;) or id:match(&amp;quot;^%d%d[01]%d%.%d%d%d%d%dv%d+$&amp;quot;) then	-- test for the 1501- format w/ &amp;amp; w/o version&lt;br /&gt;
		year, month = id:match(&amp;quot;^(%d%d)([01]%d)%.%d%d%d%d%d[v%d]*$&amp;quot;);&lt;br /&gt;
		year = tonumber(year);&lt;br /&gt;
		month = tonumber(month);&lt;br /&gt;
		if ((15 &amp;gt; year) or (1 &amp;gt; month or 12 &amp;lt; month)) then						-- is year invalid or is month invalid? (doesn&amp;#039;t test for future years)&lt;br /&gt;
			err_cat = &amp;#039; &amp;#039; .. set_error( &amp;#039;bad_arxiv&amp;#039; );							-- set error message&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		err_cat = &amp;#039; &amp;#039; .. set_error( &amp;#039;bad_arxiv&amp;#039; );								-- arXiv id doesn&amp;#039;t match any format&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	text = external_link_id({link = handler.link, label = handler.label,&lt;br /&gt;
			prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) .. err_cat;&lt;br /&gt;
&lt;br /&gt;
	if is_set (class) then&lt;br /&gt;
		class = &amp;#039; [[&amp;#039; .. &amp;#039;//arxiv.org/archive/&amp;#039; .. class .. &amp;#039; &amp;#039; .. class .. &amp;#039;]]&amp;#039;;	-- external link within square brackets, not wikilink&lt;br /&gt;
	else&lt;br /&gt;
		class = &amp;#039;&amp;#039;;																-- empty string for concatenation&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return text .. class;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; N O R M A L I Z E _ L C C N &amp;gt;--------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
lccn normalization (http://www.loc.gov/marc/lccn-namespace.html#normalization)&lt;br /&gt;
1. Remove all blanks.&lt;br /&gt;
2. If there is a forward slash (/) in the string, remove it, and remove all characters to the right of the forward slash.&lt;br /&gt;
3. If there is a hyphen in the string:&lt;br /&gt;
	a. Remove it.&lt;br /&gt;
	b. Inspect the substring following (to the right of) the (removed) hyphen. Then (and assuming that steps 1 and 2 have been carried out):&lt;br /&gt;
		1. All these characters should be digits, and there should be six or less. (not done in this function)&lt;br /&gt;
		2. If the length of the substring is less than 6, left-fill the substring with zeroes until the length is six.&lt;br /&gt;
&lt;br /&gt;
Returns a normalized lccn for lccn() to validate.  There is no error checking (step 3.b.1) performed in this function.&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function normalize_lccn (lccn)&lt;br /&gt;
	lccn = lccn:gsub (&amp;quot;%s&amp;quot;, &amp;quot;&amp;quot;);									-- 1. strip whitespace&lt;br /&gt;
&lt;br /&gt;
	if nil ~= string.find (lccn,&amp;#039;/&amp;#039;) then&lt;br /&gt;
		lccn = lccn:match (&amp;quot;(.-)/&amp;quot;);								-- 2. remove forward slash and all character to the right of it&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local prefix&lt;br /&gt;
	local suffix&lt;br /&gt;
	prefix, suffix = lccn:match (&amp;quot;(.+)%-(.+)&amp;quot;);						-- 3.a remove hyphen by splitting the string into prefix and suffix&lt;br /&gt;
&lt;br /&gt;
	if nil ~= suffix then											-- if there was a hyphen&lt;br /&gt;
		suffix=string.rep(&amp;quot;0&amp;quot;, 6-string.len (suffix)) .. suffix;	-- 3.b.2 left fill the suffix with 0s if suffix length less than 6&lt;br /&gt;
		lccn=prefix..suffix;										-- reassemble the lccn&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return lccn;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; L C C N &amp;gt;----------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Format LCCN link and do simple error checking.  LCCN is a character string 8-12 characters long. The length of&lt;br /&gt;
the LCCN dictates the character type of the first 1-3 characters; the rightmost eight are always digits.&lt;br /&gt;
http://info-uri.info/registry/OAIHandler?verb=GetRecord&amp;amp;metadataPrefix=reg&amp;amp;identifier=info:lccn/&lt;br /&gt;
&lt;br /&gt;
length = 8 then all digits&lt;br /&gt;
length = 9 then lccn[1] is lower case alpha&lt;br /&gt;
length = 10 then lccn[1] and lccn[2] are both lower case alpha or both digits&lt;br /&gt;
length = 11 then lccn[1] is lower case alpha, lccn[2] and lccn[3] are both lower case alpha or both digits&lt;br /&gt;
length = 12 then lccn[1] and lccn[2] are both lower case alpha&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function lccn(lccn)&lt;br /&gt;
	local handler = cfg.id_handlers[&amp;#039;LCCN&amp;#039;];&lt;br /&gt;
	local err_cat =  &amp;#039;&amp;#039;;								-- presume that LCCN is valid&lt;br /&gt;
	local id = lccn;									-- local copy of the lccn&lt;br /&gt;
&lt;br /&gt;
	id = normalize_lccn (id);							-- get canonical form (no whitespace, hyphens, forward slashes)&lt;br /&gt;
	local len = id:len();								-- get the length of the lccn&lt;br /&gt;
&lt;br /&gt;
	if 8 == len then&lt;br /&gt;
		if id:match(&amp;quot;[^%d]&amp;quot;) then						-- if LCCN has anything but digits (nil if only digits)&lt;br /&gt;
			err_cat = &amp;#039; &amp;#039; .. set_error( &amp;#039;bad_lccn&amp;#039; );	-- set an error message&lt;br /&gt;
		end&lt;br /&gt;
	elseif 9 == len then								-- LCCN should be adddddddd&lt;br /&gt;
		if nil == id:match(&amp;quot;%l%d%d%d%d%d%d%d%d&amp;quot;) then			-- does it match our pattern?&lt;br /&gt;
			err_cat = &amp;#039; &amp;#039; .. set_error( &amp;#039;bad_lccn&amp;#039; );	-- set an error message&lt;br /&gt;
		end&lt;br /&gt;
	elseif 10 == len then								-- LCCN should be aadddddddd or dddddddddd&lt;br /&gt;
		if id:match(&amp;quot;[^%d]&amp;quot;) then							-- if LCCN has anything but digits (nil if only digits) ...&lt;br /&gt;
			if nil == id:match(&amp;quot;^%l%l%d%d%d%d%d%d%d%d&amp;quot;) then	-- ... see if it matches our pattern&lt;br /&gt;
				err_cat = &amp;#039; &amp;#039; .. set_error( &amp;#039;bad_lccn&amp;#039; );	-- no match, set an error message&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	elseif 11 == len then								-- LCCN should be aaadddddddd or adddddddddd&lt;br /&gt;
		if not (id:match(&amp;quot;^%l%l%l%d%d%d%d%d%d%d%d&amp;quot;) or id:match(&amp;quot;^%l%d%d%d%d%d%d%d%d%d%d&amp;quot;)) then	-- see if it matches one of our patterns&lt;br /&gt;
			err_cat = &amp;#039; &amp;#039; .. set_error( &amp;#039;bad_lccn&amp;#039; );	-- no match, set an error message&lt;br /&gt;
		end&lt;br /&gt;
	elseif 12 == len then								-- LCCN should be aadddddddddd&lt;br /&gt;
		if not id:match(&amp;quot;^%l%l%d%d%d%d%d%d%d%d%d%d&amp;quot;) then	-- see if it matches our pattern&lt;br /&gt;
			err_cat = &amp;#039; &amp;#039; .. set_error( &amp;#039;bad_lccn&amp;#039; );	-- no match, set an error message&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		err_cat = &amp;#039; &amp;#039; .. set_error( &amp;#039;bad_lccn&amp;#039; );		-- wrong length, set an error message&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if not is_set (err_cat) and nil ~= lccn:find (&amp;#039;%s&amp;#039;) then&lt;br /&gt;
		err_cat = &amp;#039; &amp;#039; .. set_error( &amp;#039;bad_lccn&amp;#039; );		-- lccn contains a space, set an error message&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return external_link_id({link = handler.link, label = handler.label,&lt;br /&gt;
			prefix=handler.prefix,id=lccn,separator=handler.separator, encode=handler.encode}) .. err_cat;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; P M I D &amp;gt;----------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Format PMID and do simple error checking.  PMIDs are sequential numbers beginning at 1 and counting up.  This&lt;br /&gt;
code checks the PMID to see that it contains only digits and is less than test_limit; the value in local variable&lt;br /&gt;
test_limit will need to be updated periodically as more PMIDs are issued.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function pmid(id)&lt;br /&gt;
	local test_limit = 30000000;						-- update this value as PMIDs approach&lt;br /&gt;
	local handler = cfg.id_handlers[&amp;#039;PMID&amp;#039;];&lt;br /&gt;
	local err_cat =  &amp;#039;&amp;#039;;								-- presume that PMID is valid&lt;br /&gt;
	&lt;br /&gt;
	if id:match(&amp;quot;[^%d]&amp;quot;) then							-- if PMID has anything but digits&lt;br /&gt;
		err_cat = &amp;#039; &amp;#039; .. set_error( &amp;#039;bad_pmid&amp;#039; );		-- set an error message&lt;br /&gt;
	else												-- PMID is only digits&lt;br /&gt;
		local id_num = tonumber(id);					-- convert id to a number for range testing&lt;br /&gt;
		if 1 &amp;gt; id_num or test_limit &amp;lt; id_num then		-- if PMID is outside test limit boundaries&lt;br /&gt;
			err_cat = &amp;#039; &amp;#039; .. set_error( &amp;#039;bad_pmid&amp;#039; );	-- set an error message&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return external_link_id({link = handler.link, label = handler.label,&lt;br /&gt;
			prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) .. err_cat;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; I S _ E M B A R G O E D &amp;gt;------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Determines if a PMC identifier&amp;#039;s online version is embargoed. Compares the date in |embargo= against today&amp;#039;s date.  If embargo date is&lt;br /&gt;
in the future, returns the content of |embargo=; otherwise, returns and empty string because the embargo has expired or because&lt;br /&gt;
|embargo= was not set in this cite.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function is_embargoed (embargo)&lt;br /&gt;
	if is_set (embargo) then&lt;br /&gt;
		local lang = mw.getContentLanguage();&lt;br /&gt;
		local good1, embargo_date, good2, todays_date;&lt;br /&gt;
		good1, embargo_date = pcall( lang.formatDate, lang, &amp;#039;U&amp;#039;, embargo );&lt;br /&gt;
		good2, todays_date = pcall( lang.formatDate, lang, &amp;#039;U&amp;#039; );&lt;br /&gt;
	&lt;br /&gt;
		if good1 and good2 then													-- if embargo date and today&amp;#039;s date are good dates&lt;br /&gt;
			if tonumber( embargo_date ) &amp;gt;= tonumber( todays_date ) then			-- is embargo date is in the future?&lt;br /&gt;
				return embargo;													-- still embargoed&lt;br /&gt;
			else&lt;br /&gt;
				add_maint_cat (&amp;#039;embargo&amp;#039;)&lt;br /&gt;
				return &amp;#039;&amp;#039;;														-- unset because embargo has expired&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return &amp;#039;&amp;#039;;																	-- |embargo= not set return empty string&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; P M C &amp;gt;------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Format a PMC, do simple error checking, and check for embargoed articles.&lt;br /&gt;
&lt;br /&gt;
The embargo parameter takes a date for a value. If the embargo date is in the future the PMC identifier will not&lt;br /&gt;
be linked to the article.  If the embargo date is today or in the past, or if it is empty or omitted, then the&lt;br /&gt;
PMC identifier is linked to the article through the link at cfg.id_handlers[&amp;#039;PMC&amp;#039;].prefix.&lt;br /&gt;
&lt;br /&gt;
PMC embargo date testing is done in function is_embargoed () which is called earlier because when the citation&lt;br /&gt;
has |pmc=&amp;lt;value&amp;gt; but does not have a |url= then |title= is linked with the PMC link.  Function is_embargoed ()&lt;br /&gt;
returns the embargo date if the PMC article is still embargoed, otherwise it returns an empty string.&lt;br /&gt;
&lt;br /&gt;
PMCs are sequential numbers beginning at 1 and counting up.  This code checks the PMC to see that it contains only digits and is less&lt;br /&gt;
than test_limit; the value in local variable test_limit will need to be updated periodically as more PMCs are issued.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function pmc(id, embargo)&lt;br /&gt;
	local test_limit = 5000000;							-- update this value as PMCs approach&lt;br /&gt;
	local handler = cfg.id_handlers[&amp;#039;PMC&amp;#039;];&lt;br /&gt;
	local err_cat =  &amp;#039;&amp;#039;;								-- presume that PMC is valid&lt;br /&gt;
	&lt;br /&gt;
	local text;&lt;br /&gt;
&lt;br /&gt;
	if id:match(&amp;quot;[^%d]&amp;quot;) then							-- if PMC has anything but digits&lt;br /&gt;
		err_cat = &amp;#039; &amp;#039; .. set_error( &amp;#039;bad_pmc&amp;#039; );			-- set an error message&lt;br /&gt;
	else												-- PMC is only digits&lt;br /&gt;
		local id_num = tonumber(id);					-- convert id to a number for range testing&lt;br /&gt;
		if 1 &amp;gt; id_num or test_limit &amp;lt; id_num then		-- if PMC is outside test limit boundaries&lt;br /&gt;
			err_cat = &amp;#039; &amp;#039; .. set_error( &amp;#039;bad_pmc&amp;#039; );		-- set an error message&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	if is_set (embargo) then													-- is PMC is still embargoed?&lt;br /&gt;
		text=&amp;quot;[[&amp;quot; .. handler.link .. &amp;quot;|&amp;quot; .. handler.label .. &amp;quot;]]:&amp;quot; .. handler.separator .. id .. err_cat;	-- still embargoed so no external link&lt;br /&gt;
	else&lt;br /&gt;
		text = external_link_id({link = handler.link, label = handler.label,			-- no embargo date or embargo has expired, ok to link to article&lt;br /&gt;
			prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) .. err_cat;&lt;br /&gt;
	end&lt;br /&gt;
	return text;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; D O I &amp;gt;------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Formats a DOI and checks for DOI errors.&lt;br /&gt;
&lt;br /&gt;
DOI names contain two parts: prefix and suffix separated by a forward slash.&lt;br /&gt;
	Prefix: directory indicator &amp;#039;10.&amp;#039; followed by a registrant code&lt;br /&gt;
	Suffix: character string of any length chosen by the registrant&lt;br /&gt;
&lt;br /&gt;
This function checks a DOI name for: prefix/suffix.  If the doi name contains spaces or endashes, or, if it ends&lt;br /&gt;
with a period or a comma, this function will emit a bad_doi error message.&lt;br /&gt;
&lt;br /&gt;
DOI names are case-insensitive and can incorporate any printable Unicode characters so the test for spaces, endash,&lt;br /&gt;
and terminal punctuation may not be technically correct but it appears, that in practice these characters are rarely&lt;br /&gt;
if ever used in doi names.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function doi(id, inactive)&lt;br /&gt;
	local cat = &amp;quot;&amp;quot;&lt;br /&gt;
	local handler = cfg.id_handlers[&amp;#039;DOI&amp;#039;];&lt;br /&gt;
	&lt;br /&gt;
	local text;&lt;br /&gt;
	if is_set(inactive) then&lt;br /&gt;
		local inactive_year = inactive:match(&amp;quot;%d%d%d%d&amp;quot;) or &amp;#039;&amp;#039;;		-- try to get the year portion from the inactive date&lt;br /&gt;
		text = &amp;quot;[[&amp;quot; .. handler.link .. &amp;quot;|&amp;quot; .. handler.label .. &amp;quot;]]:&amp;quot; .. id;&lt;br /&gt;
		if is_set(inactive_year) then&lt;br /&gt;
			table.insert( z.error_categories, &amp;quot;Pages with DOIs inactive since &amp;quot; .. inactive_year );&lt;br /&gt;
		else&lt;br /&gt;
			table.insert( z.error_categories, &amp;quot;Pages with inactive DOIs&amp;quot; );	-- when inactive doesn&amp;#039;t contain a recognizable year&lt;br /&gt;
		end&lt;br /&gt;
		inactive = &amp;quot; (&amp;quot; .. cfg.messages[&amp;#039;inactive&amp;#039;] .. &amp;quot; &amp;quot; .. inactive .. &amp;quot;)&amp;quot; &lt;br /&gt;
	else &lt;br /&gt;
		text = external_link_id({link = handler.link, label = handler.label,&lt;br /&gt;
			prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode})&lt;br /&gt;
		inactive = &amp;quot;&amp;quot; &lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if nil == id:match(&amp;quot;^10%.[^%s–]-/[^%s–]-[^%.,]$&amp;quot;) then	-- doi must begin with &amp;#039;10.&amp;#039;, must contain a fwd slash, must not contain spaces or endashes, and must not end with period or comma&lt;br /&gt;
		cat = &amp;#039; &amp;#039; .. set_error( &amp;#039;bad_doi&amp;#039; );&lt;br /&gt;
	end&lt;br /&gt;
	return text .. inactive .. cat &lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; H D L &amp;gt;------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Formats an HDL with minor error checking.&lt;br /&gt;
&lt;br /&gt;
HDL names contain two parts: prefix and suffix separated by a forward slash.&lt;br /&gt;
	Prefix: character string using any character in the UCS-2 character set except &amp;#039;/&amp;#039;&lt;br /&gt;
	Suffix: character string of any length using any character in the UCS-2 character set chosen by the registrant&lt;br /&gt;
&lt;br /&gt;
This function checks a HDL name for: prefix/suffix.  If the HDL name contains spaces, endashes, or, if it ends&lt;br /&gt;
with a period or a comma, this function will emit a bad_hdl error message.&lt;br /&gt;
&lt;br /&gt;
HDL names are case-insensitive and can incorporate any printable Unicode characters so the test for endashes and&lt;br /&gt;
terminal punctuation may not be technically correct but it appears, that in practice these characters are rarely&lt;br /&gt;
if ever used in HDLs.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function hdl(id)&lt;br /&gt;
	local handler = cfg.id_handlers[&amp;#039;HDL&amp;#039;];&lt;br /&gt;
	&lt;br /&gt;
	local text = external_link_id({link = handler.link, label = handler.label,&lt;br /&gt;
			prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode})&lt;br /&gt;
&lt;br /&gt;
	if nil == id:match(&amp;quot;^[^%s–]-/[^%s–]-[^%.,]$&amp;quot;) then							-- hdl must contain a fwd slash, must not contain spaces, endashes, and must not end with period or comma&lt;br /&gt;
		text = text .. &amp;#039; &amp;#039; .. set_error( &amp;#039;bad_hdl&amp;#039; );&lt;br /&gt;
	end&lt;br /&gt;
	return text;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; O P E N L I B R A R Y &amp;gt;--------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Formats an OpenLibrary link, and checks for associated errors.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function openlibrary(id)&lt;br /&gt;
	local code = id:match(&amp;quot;^%d+([AMW])$&amp;quot;);										-- only digits followed by &amp;#039;A&amp;#039;, &amp;#039;M&amp;#039;, or &amp;#039;W&amp;#039;&lt;br /&gt;
	local handler = cfg.id_handlers[&amp;#039;OL&amp;#039;];&lt;br /&gt;
&lt;br /&gt;
	if ( code == &amp;quot;A&amp;quot; ) then&lt;br /&gt;
		return external_link_id({link=handler.link, label=handler.label,&lt;br /&gt;
			prefix=handler.prefix .. &amp;#039;authors/OL&amp;#039;,&lt;br /&gt;
			id=id, separator=handler.separator,	encode = handler.encode})&lt;br /&gt;
	elseif ( code == &amp;quot;M&amp;quot; ) then&lt;br /&gt;
		return external_link_id({link=handler.link, label=handler.label,&lt;br /&gt;
			prefix=handler.prefix .. &amp;#039;books/OL&amp;#039;,&lt;br /&gt;
			id=id, separator=handler.separator,	encode = handler.encode})&lt;br /&gt;
	elseif ( code == &amp;quot;W&amp;quot; ) then&lt;br /&gt;
		return external_link_id({link=handler.link, label=handler.label,&lt;br /&gt;
			prefix=handler.prefix .. &amp;#039;works/OL&amp;#039;,&lt;br /&gt;
			id=id, separator=handler.separator,	encode = handler.encode})&lt;br /&gt;
	else&lt;br /&gt;
		return external_link_id({link=handler.link, label=handler.label,&lt;br /&gt;
			prefix=handler.prefix .. &amp;#039;OL&amp;#039;,&lt;br /&gt;
			id=id, separator=handler.separator,	encode = handler.encode}) .. &amp;#039; &amp;#039; .. set_error( &amp;#039;bad_ol&amp;#039; );&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; M E S S A G E _ I D &amp;gt;----------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Validate and format a usenet message id.  Simple error checking, looks for &amp;#039;id-left@id-right&amp;#039; not enclosed in&lt;br /&gt;
&amp;#039;&amp;lt;&amp;#039; and/or &amp;#039;&amp;gt;&amp;#039; angle brackets.&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function message_id (id)&lt;br /&gt;
	local handler = cfg.id_handlers[&amp;#039;USENETID&amp;#039;];&lt;br /&gt;
&lt;br /&gt;
	local text = external_link_id({link = handler.link, label = handler.label,&lt;br /&gt;
		prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode})&lt;br /&gt;
 &lt;br /&gt;
	if not id:match(&amp;#039;^.+@.+$&amp;#039;) or not id:match(&amp;#039;^[^&amp;lt;].*[^&amp;gt;]$&amp;#039;)then				-- doesn&amp;#039;t have &amp;#039;@&amp;#039; or has one or first or last character is &amp;#039;&amp;lt; or &amp;#039;&amp;gt;&amp;#039;&lt;br /&gt;
		text = text .. &amp;#039; &amp;#039; .. set_error( &amp;#039;bad_message_id&amp;#039; )						-- add an error message if the message id is invalid&lt;br /&gt;
	end &lt;br /&gt;
	&lt;br /&gt;
	return text&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; B U I L D _ I D _ L I S T &amp;gt;--------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Takes a table of IDs created by extract_ids() and turns it into a table of formatted ID outputs.&lt;br /&gt;
&lt;br /&gt;
inputs:&lt;br /&gt;
	id_list – table of identifiers built by extract_ids()&lt;br /&gt;
	options – table of various template parameter values used to modify some manually handled identifiers&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function build_id_list( id_list, options )&lt;br /&gt;
	local new_list, handler = {};&lt;br /&gt;
&lt;br /&gt;
	local function fallback(k) return { __index = function(t,i) return cfg.id_handlers[k][i] end } end;&lt;br /&gt;
	&lt;br /&gt;
	for k, v in pairs( id_list ) do												-- k is uc identifier name as index to cfg.id_handlers; e.g. cfg.id_handlers[&amp;#039;ISBN&amp;#039;], v is a table&lt;br /&gt;
		-- fallback to read-only cfg&lt;br /&gt;
		handler = setmetatable( { [&amp;#039;id&amp;#039;] = v }, fallback(k) );&lt;br /&gt;
		&lt;br /&gt;
		if handler.mode == &amp;#039;external&amp;#039; then&lt;br /&gt;
			table.insert( new_list, {handler.label, external_link_id( handler ) } );&lt;br /&gt;
		elseif handler.mode == &amp;#039;internal&amp;#039; then&lt;br /&gt;
			table.insert( new_list, {handler.label, internal_link_id( handler ) } );&lt;br /&gt;
		elseif handler.mode ~= &amp;#039;manual&amp;#039; then&lt;br /&gt;
			error( cfg.messages[&amp;#039;unknown_ID_mode&amp;#039;] );&lt;br /&gt;
		elseif k == &amp;#039;DOI&amp;#039; then&lt;br /&gt;
			table.insert( new_list, {handler.label, doi( v, options.DoiBroken ) } );&lt;br /&gt;
		elseif k == &amp;#039;HDL&amp;#039; then&lt;br /&gt;
			table.insert( new_list, {handler.label, hdl( v ) } );&lt;br /&gt;
		elseif k == &amp;#039;ARXIV&amp;#039; then&lt;br /&gt;
			table.insert( new_list, {handler.label, arxiv( v, options.Class ) } ); &lt;br /&gt;
		elseif k == &amp;#039;ASIN&amp;#039; then&lt;br /&gt;
			table.insert( new_list, {handler.label, amazon( v, options.ASINTLD ) } ); &lt;br /&gt;
		elseif k == &amp;#039;LCCN&amp;#039; then&lt;br /&gt;
			table.insert( new_list, {handler.label, lccn( v ) } );&lt;br /&gt;
		elseif k == &amp;#039;OL&amp;#039; or k == &amp;#039;OLA&amp;#039; then&lt;br /&gt;
			table.insert( new_list, {handler.label, openlibrary( v ) } );&lt;br /&gt;
		elseif k == &amp;#039;PMC&amp;#039; then&lt;br /&gt;
			table.insert( new_list, {handler.label, pmc( v, options.Embargo ) } );&lt;br /&gt;
		elseif k == &amp;#039;PMID&amp;#039; then&lt;br /&gt;
			table.insert( new_list, {handler.label, pmid( v ) } );&lt;br /&gt;
		elseif k == &amp;#039;ISMN&amp;#039; then&lt;br /&gt;
			table.insert( new_list, {handler.label, ismn( v ) } );&lt;br /&gt;
		elseif k == &amp;#039;ISSN&amp;#039; then&lt;br /&gt;
			table.insert( new_list, {handler.label, issn( v ) } );&lt;br /&gt;
		elseif k == &amp;#039;EISSN&amp;#039; then&lt;br /&gt;
			table.insert( new_list, {handler.label, issn( v, true ) } );		-- true distinguishes eissn from issn&lt;br /&gt;
		elseif k == &amp;#039;ISBN&amp;#039; then&lt;br /&gt;
			local ISBN = internal_link_id( handler );&lt;br /&gt;
			if not check_isbn( v ) and not is_set(options.IgnoreISBN) then&lt;br /&gt;
				ISBN = ISBN .. set_error( &amp;#039;bad_isbn&amp;#039;, {}, false, &amp;quot; &amp;quot;, &amp;quot;&amp;quot; );&lt;br /&gt;
			end&lt;br /&gt;
			table.insert( new_list, {handler.label, ISBN } );				&lt;br /&gt;
		elseif k == &amp;#039;USENETID&amp;#039; then&lt;br /&gt;
			table.insert( new_list, {handler.label, message_id( v ) } );&lt;br /&gt;
		else&lt;br /&gt;
			error( cfg.messages[&amp;#039;unknown_manual_ID&amp;#039;] );&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local function comp( a, b )	-- used in following table.sort()&lt;br /&gt;
		return a[1] &amp;lt; b[1];&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	table.sort( new_list, comp );&lt;br /&gt;
	for k, v in ipairs( new_list ) do&lt;br /&gt;
		new_list[k] = v[2];&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return new_list;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[[--------------------------&amp;lt; E X T R A C T _ I D S &amp;gt;------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Populates ID table from arguments using configuration settings. Loops through cfg.id_handlers and searches args for&lt;br /&gt;
any of the parameters listed in each cfg.id_handlers[&amp;#039;...&amp;#039;].parameters.  If found, adds the parameter and value to&lt;br /&gt;
the identifier list.  Emits redundant error message is more than one alias exists in args&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local function extract_ids( args )&lt;br /&gt;
	local id_list = {};															-- list of identifiers found in args&lt;br /&gt;
	for k, v in pairs( cfg.id_handlers ) do										-- k is uc identifier name as index to cfg.id_handlers; e.g. cfg.id_handlers[&amp;#039;ISBN&amp;#039;], v is a table&lt;br /&gt;
		v = select_one( args, v.parameters, &amp;#039;redundant_parameters&amp;#039; );			-- v.parameters is a table of aliases for k; here we pick one from args if present&lt;br /&gt;
		if is_set(v) then id_list[k] = v; end									-- if found in args, add identifier to our list&lt;br /&gt;
	end&lt;br /&gt;
	return id_list;&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)&lt;br /&gt;
	cfg = cfg_table_ptr;&lt;br /&gt;
&lt;br /&gt;
	is_set = utilities_page_ptr.is_set;											-- import functions from select Module:Citation/CS1/Utilities module&lt;br /&gt;
	in_array = utilities_page_ptr.in_array;&lt;br /&gt;
	set_error = utilities_page_ptr.set_error;&lt;br /&gt;
	select_one = utilities_page_ptr.select_one;&lt;br /&gt;
	add_maint_cat = utilities_page_ptr.add_maint_cat;&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;
&lt;br /&gt;
return {&lt;br /&gt;
	build_id_list = build_id_list,&lt;br /&gt;
	extract_ids = extract_ids,&lt;br /&gt;
	is_embargoed = is_embargoed;&lt;br /&gt;
	set_selected_modules = set_selected_modules;&lt;br /&gt;
	}&lt;/div&gt;</summary>
		<author><name>LIMAFOX76</name></author>
	</entry>
</feed>