----------------------------< F O R W A R D D E C L A R A T I O N S >--------------------------------------  
local has_accept_as_written, is_set, in_array, set_message, select_one, -- functions in Module:Citation/CS1/Utilities
substitute, make_wikilink;  
local z; -- table of tables defined in Module:Citation/CS1/Utilities  
local cfg; -- table of configuration tables that are defined in Module:Citation/CS1/Configuration  
----------------------------< P A G E S C O P E V A R I A B L E S >--------------------------------------  
declare variables here that have page-wide scope that are not brought in from other modules; that are created here and used here  
local auto_link_urls = {}; -- holds identifier URLs for those identifiers that can auto-link |title=  
--============================<< H E L P E R F U N C T I O N S >>============================================  
----------------------------< W I K I D A T A _ A R T I C L E _ N A M E _ G E T >----------------------------  
as an aid to internationalizing identifier-label wikilinks, gets identifier article names from Wikidata.  
returns :<lang code>:<article title> when <q> has an <article title> for <lang code>; nil else  
for identifiers that do not have q, returns nil  
for wikis that do not have mw.wikibase installed, returns nil  
local function wikidata_article_name_get (q)
if not is_set (q) or (q and not mw.wikibase) then -- when no q number or when a q number but mw.wikibase not installed on this wiki
return nil; -- abandon
end  
local wd_article;
local this_wiki_code = cfg.this_wiki_code; -- Wikipedia subdomain; 'en' for en.wikipedia.org  
wd_article = mw.wikibase.getSitelink (q, this_wiki_code .. 'wiki'); -- fetch article title from WD; nil when no title available at this wiki  
if wd_article then
wd_article = table.concat ({':', this_wiki_code, ':', wd_article}); -- interwiki-style link without brackets if taken from WD; leading colon required
end  
return wd_article; -- article title from WD; nil else
end  
----------------------------< L I N K _ L A B E L _ M A K E >------------------------------------------------  
common function to create identifier link label from handler table or from Wikidata  
returns the first available of
1. redirect from local wiki's handler table (if enabled)
2. Wikidata (if there is a Wikidata entry for this identifier in the local wiki's language)
3. label specified in the local wiki's handler table  
local function link_label_make (handler)
local wd_article;  
if not (cfg.use_identifier_redirects and is_set (handler.redirect)) then -- redirect has priority so if enabled and available don't fetch from Wikidata because expensive
wd_article = wikidata_article_name_get (handler.q); -- if Wikidata has an article title for this wiki, get it;
end  
return (cfg.use_identifier_redirects and is_set (handler.redirect) and handler.redirect) or wd_article or handler.link;
end  
----------------------------< E X T E R N A L _ L I N K _ I D >----------------------------------------------  
Formats a wiki-style external link  
local function external_link_id (options)
local url_string = options.id;
local ext_link;
local this_wiki_code = cfg.this_wiki_code; -- Wikipedia subdomain; 'en' for en.wikipedia.org
local wd_article; -- article title from Wikidata  
if options.encode == true or options.encode == nil then
url_string = mw.uri.encode (url_string, 'PATH');
end  
if options.auto_link and is_set (options.access) then
auto_link_urls[options.auto_link] = table.concat ({options.prefix, url_string, options.suffix});
end  
ext_link = mw.ustring.format ('[%s%s%s %s]', options.prefix, url_string, options.suffix or "", mw.text.nowiki (options.id));
if is_set (options.access) then
ext_link = substitute (cfg.presentation['ext-link-access-signal'], {cfg.presentation[options.access].class, cfg.presentation[options.access].title, ext_link}); -- add the free-to-read / paywall lock
end  
return table.concat ({
make_wikilink (link_label_make (options), options.label), -- redirect, Wikidata link, or locally specified link (in that order)
options.separator or '&nbsp;',
ext_link
});
end  
----------------------------< I N T E R N A L _ L I N K _ I D >----------------------------------------------  
Formats a wiki-style internal link  
TODO: Does not currently need to support options.access, options.encode, auto-linking and COinS (as in external_link_id),
but may be needed in the future for :m:Interwiki_map custom-prefixes like :arxiv:, :bibcode:, :DOI:, :hdl:, :ISSN:,
:JSTOR:, :Openlibrary:, :PMID:, :RFC:.  
local function internal_link_id (options)
local id = mw.ustring.gsub (options.id, '%d', cfg.date_names.local_digits); -- translate 'local' digits to Western 0-9  
return table.concat (
{
make_wikilink (link_label_make (options), options.label), -- wiki-link the identifier label
options.separator or '&nbsp;', -- add the separator
make_wikilink (
table.concat (
{
options.prefix,
id, -- translated to Western digits
options.suffix or ''
}),
substitute (cfg.presentation['bdi'], {'', mw.text.nowiki (options.id)}) -- bdi tags to prevent Latin script identifiers from being reversed at RTL language wikis
); -- nowiki because MediaWiki still has magic links for ISBN and the like; TODO: is it really required?
});
end  
--pmc-embargo-date= against
today's date. If embargo date is in the future, returns the content of |pmc-embargo-date=; otherwise, returns
an empty string because the embargo has expired or because |pmc-embargo-date= was not set in this cite.  
local function is_embargoed (embargo)
if is_set (embargo) then
local lang = mw.getContentLanguage;
local good1, embargo_date, todays_date;
good1, embargo_date = pcall (lang.formatDate, lang, 'U', embargo);
todays_date = lang:formatDate ('U');  
if good1 then -- if embargo date is a good date
if tonumber (embargo_date) >= tonumber (todays_date) then -- is embargo date is in the future?
return embargo; -- still embargoed
else
set_message ('maint_pmc_embargo'); -- embargo has expired; add main cat
return ''; -- unset because embargo has expired
end
end
end
return ''; -- |pmc-embargo-date= not set return empty string
end  
--[=[-------------------------< I S _ V A L I D _ B I O R X I V _ D A T E >------------------------------------  
returns true if:
2019-12-11T00:00Z <= biorxiv_date < today + 2 days  
The dated form of biorxiv identifier has a start date of 2019-12-11. The Unix timestamp for that date is = 1576022400  
biorxiv_date is the date provided in those |biorxiv= parameter values that are dated at time 00:00:00 UTC
today is the current date at time 00:00:00 UTC plus 48 hours
if today is 2015-01-01T00:00:00 then
adding 24 hours gives 2015-01-02T00:00:00 – one second more than today
adding 24 hours gives 2015-01-03T00:00:00 – one second more than tomorrow  
This function does not work if it is fed month names for languages other than English. Wikimedia #time: parser
apparently doesn't understand non-English date month names. This function will always return false when the date
contains a non-English month name because good1 is false after the call to lang_object.formatDate. To get
around that call this function with date parts and create a YYYY-MM-DD format date.  
]=]  
local function is_valid_biorxiv_date (y, m, d)
local biorxiv_date = table.concat ({y, m, d}, '-'); -- make ymd date
local good1, good2;
local biorxiv_ts, tomorrow_ts; -- to hold Unix timestamps representing the dates
local lang_object = mw.getContentLanguage;  
good1, biorxiv_ts = pcall (lang_object.formatDate, lang_object, 'U', biorxiv_date); -- convert biorxiv_date value to Unix timestamp
good2, tomorrow_ts = pcall (lang_object.formatDate, lang_object, 'U', 'today + 2 days' ); -- today midnight + 2 days is one second more than all day tomorrow  
if good1 and good2 then -- lang.formatDate returns a timestamp in the local script which tonumber may not understand