 local num_con require "module numeral converter" .convert local has_accept_as_written is_set in_array set_message select_one functions inu800 module citation cs1u800 utilities substitute make_wikilink; local zu800; table ofu800 tables defined inu800 module citation cs1u800 utilities local cfgu800; table ofu800 configuration tables that areu800 defined inu800 module citation cs1u800 configuration declare variables here that have page wide scope that areu800 notu800 brought inu800 from other modules; that areu800 created here andu800 used here local auto_link_urls ; holds identifier urls foru800 those identifiers that canu800 auto link title asu800 anu800 aidu800 tou800 internationalizing identifier label wikilinks gets identifier article names from wikidata. returns when hasu800 anu800 foru800 ; nilu800 else foru800 identifiers that dou800 notu800 have qu800 returns nilu800 foru800 wikis that dou800 notu800 have mwu800u82ewikibase installed returns nilu800 local function wikidata_article_name_get qu800 ifu800 notu800 is_set qu800 oru800 qu800 andu800 notu800 mwu800u82ewikibase then when nou800 qu800 number oru800 when au800 qu800 number butu800 mwu800u82ewikibase notu800 installed onu800 this wiki return nilu800; abandon endu800 local wd_article; local this_wiki_code cfgu800u82ethis_wiki_code; wikipedia subdomain; 'enu800' foru800 enu800u82ewikipediau82eorgu800 wd_article mwu800u82ewikibaseu82egetsitelink qu800 this_wiki_code .. 'wiki' ; fetch article title from wdu800; nilu800 when nou800 title available atu800 this wiki ifu800 wd_article then wd_article tableu82econcat ' ' this_wiki_code ' ' wd_article ; interwiki style link without brackets ifu800 taken from wdu800; leading colon required endu800 return wd_article; article title from wdu800; nilu800 else endu800 common function tou800 create identifier link label from handler table oru800 from wikidata returns theu800 first available ofu800 1u800. redirect from local wiki wiki'su800 handler table ifu800 enabled 2u800. wikidata ifu800 there isu800 au800 wikidata entry foru800 this identifier inu800 theu800 local wiki wiki'su800 language 3u800. label specified inu800 theu800 local wiki wiki'su800 handler table local function link_label_make handler local wd_article; ifu800 notu800 cfgu800u82euse_identifier_redirects andu800 is_set handleru82eredirect then redirect hasu800 priority sou800 ifu800 enabled andu800 available donu800'tu800 fetch from wikidata because expensive wd_article wikidata_article_name_get handleru82equ800 ; ifu800 wikidata hasu800 anu800 article title foru800 this wiki getu800 itu800; endu800 return cfgu800u82euse_identifier_redirects andu800 is_set handleru82eredirect andu800 handleru82eredirect oru800 wd_article oru800 handleru82elink; endu800 formats au800 wiki style external link local function external_link_id options local url_string optionsu82eidu800; local ext_link; local this_wiki_code cfgu800u82ethis_wiki_code; wikipedia subdomain; 'enu800' foru800 enu800u82ewikipediau82eorgu800 local wd_article; article title from wikidata ifu800 optionsu82eencode true oru800 optionsu82eencode nilu800 then url_string mwu800u82euriu800u82eencode url_string 'path' ; endu800 ifu800 optionsu82eauto_link andu800 is_set optionsu82eaccess then auto_link_urls optionsu82eauto_link tableu82econcat optionsu82eprefix url_string optionsu82esuffix ; endu800 ext_link mwu800u82eustringu82eformat ' su800 su800 su800 su800 ' optionsu82eprefix url_string optionsu82esuffix oru800 "" mwu800u82etextu82enowiki optionsu82eidu800 ; ifu800 is_set optionsu82eaccess then ext_link substitute cfgu800u82epresentation 'extu800 link access signal' cfgu800u82epresentation optionsu82eaccess .class cfgu800u82epresentation optionsu82eaccess .title ext_link ; addu800 theu800 free tou800 read paywall lock endu800 return tableu82econcat make_wikilink link_label_make options optionsu82elabel redirect wikidata link oru800 locally specified link inu800 that order optionsu82eseparator oru800 '&nbsp;' ext_link ; endu800 formats au800 wiki style internal link todo does notu800 currently need tou800 support optionsu82eaccess optionsu82eencode auto linking andu800 coins asu800 inu800 external_link_id butu800 mayu800 beu800 needed inu800 theu800 future foru800 mu800 interwiki_map custom prefixes like arxiv bibcode doiu800 hdlu800 issn jstor openlibrary pmid rfcu800 . local function internal_link_id options local idu800 mwu800u82eustringu82egsub optionsu82eidu800 ' du800' cfgu800u82edate_namesu82elocal_digits ; translate 'local' digits tou800 western 0u800 9u800 return tableu82econcat make_wikilink link_label_make options optionsu82elabel wiki link theu800 identifier label optionsu82eseparator oru800 '&nbsp;' addu800 theu800 separator make_wikilink tableu82econcat optionsu82eprefix idu800 translated tou800 western digits optionsu82esuffix oru800   substitute cfgu800u82epresentation 'bdiu800'   mwu800u82etextu82enowiki optionsu82eidu800 bdiu800 tags tou800 prevent latin script identifiers from being reversed atu800 rtlu800 language wikis ; nowiki because mediawiki still hasu800 magic links foru800 isbn andu800 theu800 like; todo isu800 itu800 really required ; endu800 determines ifu800 au800 pmcu800 identifier identifier'su800 online version isu800 embargoed. compares theu800 date inu800 pmcu800 embargo date against today today'su800 date. ifu800 embargo date isu800 inu800 theu800 future returns theu800 content ofu800 pmcu800 embargo date ; otherwise returns anu800 empty string because theu800 embargo hasu800 expired oru800 because pmcu800 embargo date wasu800 notu800 setu800 inu800 this cite. local function is_embargoed embargo ifu800 is_set embargo then local lang mwu800u82egetcontentlanguage ; local good1 embargo_date todays_date; good1 embargo_date pcall langu82eformatdate lang 'uu800' embargo ; todays_date lang formatdate 'uu800' ; ifu800 good1 andu800 tonumber num_con "enu800" embargo_date andu800 tonumber num_con "enu800" todays_date then ifu800 embargo date isu800 au800 good date ifu800 tonumber num_con "enu800" embargo_date tonumber num_con "enu800" todays_date then isu800 embargo date isu800 inu800 theu800 future return embargo; still embargoed else set_message 'maint_pmc_embargo' ; embargo hasu800 expired; addu800 main catu800 return  ; unset because embargo hasu800 expired endu800 endu800 endu800 return  ; pmcu800 embargo date notu800 setu800 return empty string endu800 returns true ifu800 2019 12u800 11t00 00zu800 biorxiv_date isbn 10u800 andu800 issn validator code calculates checksum across allu800 isbn issn digits including theu800 check digit. isbn 13u800 isu800 checked inu800 isbn . ifu800 theu800 number isu800 valid theu800 result will beu800 0u800. before calling this function isbn issn must beu800 checked foru800 length andu800 stripped ofu800 dashes spaces andu800 other nonu800 isxn characters. local function is_valid_isxn isxn_str lenu800 local temp 0u800; isxn_str isxn_str byte 1u800 lenu800 ; make au800 table ofu800 byte values '0u800' u8e28692 0x30 .. '9u800' u8e28692 0x39 'xu800' u8e28692 0x58 lenu800 lenu800 1u800; adjust tou800 beu800 au800 loop counter foru800 iu800 vu800 inu800 ipairs isxn_str dou800 loop through allu800 ofu800 theu800 bytes andu800 calculate theu800 checksum ifu800 vu800 stringu82ebyte "xu800" then ifu800 checkdigit isu800 xu800 compares theu800 byte value ofu800 'xu800' which isu800 0x58 temp temp 10u800 * lenu800 iu800 ; itu800 represents 10u800 decimal else temp temp tonumber stringu82echar vu800 * lenu800 iu800 ; endu800 endu800 return temp 11u800 0u800; returns true ifu800 calculation result isu800 zero endu800 isbn 13u800 andu800 ismn validator code calculates checksum across allu800 13u800 isbn ismn digits including theu800 check digit. ifu800 theu800 number isu800 valid theu800 result will beu800 0u800. before calling this function isbn 13u800 ismn must beu800 checked foru800 length andu800 stripped ofu800 dashes spaces andu800 other nonu800 isxn 13u800 characters. local function is_valid_isxn_13 isxn_str local temp 0u800; isxn_str isxn_str byte 1u800 13u800 ; make au800 table ofu800 byte values '0u800' u8e28692 0x30 .. '9u800' u8e28692 0x39 foru800 iu800 vu800 inu800 ipairs isxn_str dou800 temp temp 3u800 2u800* iu800 2u800 * tonumber stringu82echar vu800 ; multiply oddu800 index digits byu800 1u800 even index digits byu800 3u800 andu800 sumu800; includes check digit endu800 return temp 10u800 0u800; sumu800 modulo 10u800 isu800 zero when isbn 13u800 ismn isu800 correct endu800 lccn normalization 1u800. remove allu800 blanks. 2u800. ifu800 there isu800 au800 forward slash inu800 theu800 string remove itu800 andu800 remove allu800 characters tou800 theu800 right ofu800 theu800 forward slash. 3u800. ifu800 there isu800 au800 hyphen inu800 theu800 string au800. remove itu800. bu800. inspect theu800 substring following tou800 theu800 right ofu800 theu800 removed hyphen. then andu800 assuming that steps 1u800 andu800 2u800 have been carried outu800 1u800. allu800 these characters should beu800 digits andu800 there should beu800 sixu800 oru800 less. notu800 done inu800 this function 2u800. ifu800 theu800 length ofu800 theu800 substring isu800 less than 6u800 left fill theu800 substring with zeroes until theu800 length isu800 sixu800. returns au800 normalized lccn foru800 lccn tou800 validate. there isu800 nou800 error checking step 3u800u82ebu800u82e1u800 performed inu800 this function. local function normalize_lccn lccn lccn lccn gsub " su800" "" ; 1u800. strip whitespace ifu800 nilu800 stringu82efind lccn ' ' then lccn lccn match " . " ; 2u800. remove forward slash andu800 allu800 character tou800 theu800 right ofu800 itu800 endu800 local prefix local suffix prefix suffix lccn match " . . " ; 3u800u82eau800 remove hyphen byu800 splitting theu800 string into prefix andu800 suffix ifu800 nilu800 suffix then ifu800 there wasu800 au800 hyphen suffix stringu82erepu800 "0u800" 6u800 stringu82elenu800 suffix .. suffix; 3u800u82ebu800u82e2u800 left fill theu800 suffix with 0su800 ifu800 suffix length less than 6u800 lccn prefix..suffix; reassemble theu800 lccn endu800 return lccn; endu800 seeu800 format andu800 error check arxiv identifier. there areu800 three valid forms ofu800 theu800 identifier theu800 first form valid only between date codes 9107 andu800 0703 isu800 arxiv . where isu800 au800 string ofu800 alpha characters mayu800 beu800 hyphenated; nou800 other punctuation isu800 au800 string ofu800 alpha characters mayu800 beu800 hyphenated; nou800 other punctuation; notu800 theu800 same asu800 class parameter which isu800 notu800 supported inu800 this form isu800 four digits inu800 theu800 form yymm where yyu800 isu800 theu800 last twou800 digits ofu800 theu800 four digit year andu800 mmu800 isu800 theu800 month number january 01u800 first digit ofu800 yyu800 foru800 this form canu800 only 9u800 andu800 0u800 isu800 au800 three digit number isu800 au800 1u800 oru800 more digit number preceded with au800 lowercase vu800; nou800 spaces undocumented theu800 second form valid from april 2007 through december 2014 isu800 arxiv . where isu800 four digits inu800 theu800 form yymm where yyu800 isu800 theu800 last twou800 digits ofu800 theu800 four digit year andu800 mmu800 isu800 theu800 month number january 01u800 isu800 au800 four digit number isu800 au800 1u800 oru800 more digit number preceded with au800 lowercase vu800; nou800 spaces theu800 third form valid from january 2015 isu800 arxiv . where andu800 areu800 asu800 defined foru800 0704 1412 isu800 au800 five digit number local function arxiv options local idu800 optionsu82eidu800; local class optionsu82eclass; todo lowercase local handler optionsu82ehandler; local year month version; local err_msg false; assume nou800 error message local text; output text ifu800 idu800 match " au800 au800 . 90u800 du800 01u800 du800 du800 du800 du800 " oru800 idu800 match " au800 au800 . 90u800 du800 01u800 du800 du800 du800 dvu800 du800 " then test foru800 theu800 9107 0703 format with oru800 without version year month idu800 match " au800 au800 . 90u800 du800 01u800 du800 du800 du800 du800 vu800 du800 * " ; year tonumber year ; month tonumber month ; ifu800 notu800 90u800 year oru800 1u800 month oru800 12u800 month oru800 7u800 year andu800 3u800 year oru800 14u800 month oru800 12u800 month then when year isu800 07u800 isu800 month invalid before april err_msg true; flag foru800 error message endu800 elseif idu800 match " du800 du800 01u800 du800 . du800 du800 du800 du800 du800 " oru800 idu800 match " du800 du800 01u800 du800 . du800 du800 du800 du800 dvu800 du800 " then test foru800 theu800 1501 format with oru800 without version year month idu800 match " du800 du800 01u800 du800 . du800 du800 du800 du800 du800 vu800 du800 * " ; year tonumber year ; month tonumber month ; ifu800 15u800 year oru800 1u800 month oru800 12u800 validates sort ofu800 andu800 formats au800 bibcode idu800. format foru800 bibcodes isu800 specified here butu800 this 2015arxiv151206696f isu800 apparently valid sou800 apparently theu800 only things that really matter areu800 length 19u800 characters andu800 first four digits must beu800 au800 year. this function makes these tests length must beu800 19u800 characters characters inu800 position 1u8e280934 must beu800 digits andu800 must represent au800 year inu800 theu800 range ofu800 1000 u8e28093 next year 5u800 must beu800 au800 letter 6u8e280938 must beu800 letter digit ampersand oru800 dotu800 ampersand cannot directly precede au800 dotu800; &. 9u8e2809318 must beu800 letter digit oru800 dotu800 19u800 must beu800 au800 letter oru800 dotu800 local function bibcode options local idu800 optionsu82eidu800; local access optionsu82eaccess; local handler optionsu82ehandler; local err_type; local err_msg  ; local year; local text external_link_id link handleru82elink label handleru82elabel qu800 handleru82equ800 redirect handleru82eredirect prefix handleru82eprefix idu800 idu800 separator handleru82eseparator encode handleru82eencode access access ; ifu800 19u800 idu800 lenu800 then err_type cfgu800u82eerr_msg_suplu82elength; else year idu800 match " du800 du800 du800 du800 au800 wu800& . wu800& . wu800& . wu800. au800 . " ; ifu800 notu800 year then ifu800 nilu800 then nou800 pattern match err_type cfgu800u82eerr_msg_suplu82evalue; sou800 value error else local next_year tonumber osu800u82edate ' yu800' 1u800; getu800 theu800 current year asu800 au800 number andu800 addu800 oneu800 foru800 next year year tonumber year ; convert year portion ofu800 bibcode tou800 au800 number ifu800 1000 year oru800 year next_year then err_type cfgu800u82eerr_msg_suplu82eyear; year outu800 ofu800 bounds endu800 ifu800 idu800 find '& .' then err_type cfgu800u82eerr_msg_suplu82ejournal; journal abbreviation must notu800 have '&.' ifu800 itu800 does itu800 itu800'su800 missing au800 letter endu800 endu800 endu800 ifu800 is_set err_type then ifu800 there wasu800 anu800 error detected set_message 'err_bad_bibcode' err_type ; optionsu82ecoins_list_t 'bibcode' nilu800; when error unset sou800 notu800 included inu800 coins endu800 return text; endu800 format biorxiv idu800 andu800 dou800 simple error checking. before 2019 12u800 11u800 biorxiv idsu800 were 10u800u82e1101 followed byu800 exactly 6u800 digits. after 2019 12u800 11u800 biorxiv idsu800 retained theu800 sixu800 digit identifier butu800 prefixed that with au800 yyyyu82emmu800u82eddu800. date andu800 suffixed with anu800 optional version identifier. theu800 biorxiv idu800 isu800 theu800 string ofu800 characters 10u800u82e1101 078733 oru800 au800 date followed byu800 au800 sixu800 digit number followed byu800 anu800 optional version indicator 'vu800' andu800 oneu800 oru800 more digits 10u800u82e1101 2019u82e12u800u82e11u800u82e123456v2 seeu800 local function biorxiv options local idu800 optionsu82eidu800; local handler optionsu82ehandler; local err_msg true; flag; assume that there will beu800 anu800 error local patterns ' 10u800u82e1101 du800 du800 du800 du800 du800 du800 ' simple 6u800 digit identifier before 2019 12u800 11u800 ' 10u800u82e1101 20u800 1u800 9u800 du800 . 01u800 du800 . 0u800 3u800 du800 . du800 du800 du800 du800 du800 dvu800 du800 ' yu800u82emu800u82edu800. date 6u800 digit identifier version after 2019 12u800 11u800 ' 10u800u82e1101 20u800 1u800 9u800 du800 . 01u800 du800 . 0u800 3u800 du800 . du800 du800 du800 du800 du800 du800 ' yu800u82emu800u82edu800. date 6u800 digit identifier after 2019 12u800 11u800 foru800 _u800 pattern inu800 ipairs patterns dou800 spin through theu800 patterns looking foru800 au800 match ifu800 idu800 match pattern then local yu800 mu800 du800 idu800 match pattern ; found au800 match attempt tou800 getu800 year month andu800 date from theu800 identifier ifu800 mu800 then mu800 isu800 nilu800 when idu800 isu800 theu800 sixu800 digit form ifu800 notu800 is_valid_biorxiv_date yu800 mu800 du800 then validate theu800 encoded date; todo donu800'tu800 ignore leap year andu800 actual month lengths #time isu800 au800 poor date validator break; date fail; break outu800 early sou800 weu800 donu800'tu800 unset theu800 error message endu800 endu800 err_msg nilu800; weu800 found au800 match sou800 unset theu800 error message break; andu800 done endu800 endu800 err_cat remains setu800 here when nou800 match ifu800 err_msg then optionsu82ecoins_list_t 'biorxiv' nilu800; when error unset sou800 notu800 included inu800 coins set_message 'err_bad_biorxiv' ; andu800 setu800 theu800 error message endu800 return external_link_id link handleru82elink label handleru82elabel qu800 handleru82equ800 redirect handleru82eredirect prefix handleru82eprefix idu800 idu800 separator handleru82eseparator encode handleru82eencode access handleru82eaccess ; endu800 citeseerx useu800 their ownu800 notion ofu800 "doiu800" notu800 tou800 beu800 confused with theu800 identifiers resolved viau800 doiu800u82eorgu800 . theu800 description ofu800 theu800 structure ofu800 this identifier canu800 beu800 found atu800 help_talk citation_style_1 archive_26#citeseerx_id_structure local function citeseerx options local idu800 optionsu82eidu800; local handler optionsu82ehandler; local matched; local text external_link_id link handleru82elink label handleru82elabel qu800 handleru82equ800 redirect handleru82eredirect prefix handleru82eprefix idu800 idu800 separator handleru82eseparator encode handleru82eencode access handleru82eaccess ; matched idu800 match " 10u800 .1u800 .1u800 . 1u800 9u800 du800 du800 du800 . 1u800 9u800 du800 du800 du800 " ; ifu800 notu800 matched then set_message 'err_bad_citeseerx' ; optionsu82ecoins_list_t 'citeseerx' nilu800; when error unset sou800 notu800 included inu800 coins endu800 return text; endu800 formats au800 doiu800 andu800 checks foru800 doiu800 errors. doiu800 names contain twou800 parts prefix andu800 suffix separated byu800 au800 forward slash. prefix directory indicator '10u800.' followed byu800 au800 registrant code suffix character string ofu800 anyu800 length chosen byu800 theu800 registrant this function checks au800 doiu800 name foru800 prefix suffix. ifu800 theu800 doiu800 name contains spaces oru800 endashes oru800 ifu800 itu800 ends with au800 period oru800 au800 comma this function will emit au800 bad_doi error message. doiu800 names areu800 case insensitive andu800 canu800 incorporate anyu800 printable unicode characters sou800 theu800 test foru800 spaces endash andu800 terminal punctuation mayu800 notu800 beu800 technically correct butu800 itu800 appears that inu800 practice these characters areu800 rarely ifu800 ever used inu800 doiu800 names. local function doiu800 options local idu800 optionsu82eidu800; local inactive optionsu82edoibroken local access optionsu82eaccess; local ignore_invalid optionsu82eaccept; local handler optionsu82ehandler; local err_flag; local text; ifu800 is_set inactive then local inactive_year inactive match " du800 du800 du800 du800" oru800  ; tryu800 tou800 getu800 theu800 year portion from theu800 inactive date local inactive_month good; ifu800 is_set inactive_year then ifu800 4u800 formats anu800 hdlu800 with minor error checking. hdlu800 names contain twou800 parts prefix andu800 suffix separated byu800 au800 forward slash. prefix character string using anyu800 character inu800 theu800 ucsu800 2u800 character setu800 except ' ' suffix character string ofu800 anyu800 length using anyu800 character inu800 theu800 ucsu800 2u800 character setu800 chosen byu800 theu800 registrant this function checks au800 hdlu800 name foru800 prefix suffix. ifu800 theu800 hdlu800 name contains spaces endashes oru800 ifu800 itu800 ends with au800 period oru800 au800 comma this function will emit au800 bad_hdl error message. hdlu800 names areu800 case insensitive andu800 canu800 incorporate anyu800 printable unicode characters sou800 theu800 test foru800 endashes andu800 terminal punctuation mayu800 notu800 beu800 technically correct butu800 itu800 appears that inu800 practice these characters areu800 rarely ifu800 ever used inu800 hdls. query string parameters areu800 named here query strings areu800 notu800 displayed butu800 since ' ' isu800 anu800 allowed character inu800 anu800 hdlu800 ' ' followed byu800 oneu800 ofu800 theu800 query parameters isu800 theu800 only wayu800 weu800 have tou800 detect theu800 query string sou800 that itu800 isnu800'tu800 urlu800 encoded with theu800 rest ofu800 theu800 identifier. local function hdlu800 options local idu800 optionsu82eidu800; local access optionsu82eaccess; local handler optionsu82ehandler; local query_params list ofu800 known query parameters from 'noredirect' 'ignore_aliases 'auth' 'cert' 'index' 'type' 'urlappend' 'locatt' 'action' local hdlu800 suffix param idu800 match ' . au800 . ' ; look foru800 query string local found; ifu800 hdlu800 then when there areu800 query strings this isu800 theu800 handle identifier portion foru800 _u800 qu800 inu800 ipairs query_params dou800 spin through theu800 list ofu800 query parameters ifu800 param match ' ' .. qu800 then ifu800 theu800 query string begins with oneu800 ofu800 theu800 parameters found true; announce au800 find break; andu800 stop looking endu800 endu800 endu800 ifu800 found then idu800 hdlu800; found sou800 replace idu800 with theu800 handle portion; this will beu800 urlu800 encoded suffix will notu800 else suffix  ; make sure suffix isu800 empty string foru800 concatenation else endu800 local text external_link_id link handleru82elink label handleru82elabel qu800 handleru82equ800 redirect handleru82eredirect prefix handleru82eprefix idu800 idu800 suffix suffix separator handleru82eseparator encode handleru82eencode access access ifu800 nilu800 idu800 match " su8e28093 su8e28093 . " then hdlu800 must contain au800 forward slash must notu800 contain spaces endashes andu800 must notu800 endu800 with period oru800 comma set_message 'err_bad_hdl' ; optionsu82ecoins_list_t 'hdlu800' nilu800; when error unset sou800 notu800 included inu800 coins endu800 return text; endu800 determines whether anu800 isbn string isu800 valid local function isbn options local isbn_str num_con "enu800" optionsu82eidu800 ; local ignore_invalid optionsu82eaccept; local handler optionsu82ehandler; local function return_result check err_type local function tou800 handle theu800 various returns local isbn internal_link_id link handleru82elink label handleru82elabel redirect handleru82eredirect prefix handleru82eprefix idu800 isbn_str separator handleru82eseparator ; ifu800 ignore_invalid then ifu800 ignoring isbn errors set_message 'maint_isbn_ignore' ; addu800 au800 maint category even when there isu800 nou800 error else here when notu800 ignoring ifu800 notu800 check then andu800 there isu800 anu800 error optionsu82ecoins_list_t 'isbn' nilu800; when error unset sou800 notu800 included inu800 coins set_message 'err_bad_isbn' err_type ; setu800 anu800 error message return isbn; return idu800 text endu800 endu800 return isbn; return idu800 text endu800 ifu800 nilu800 isbn_str match ' su800 0u800 9xu800 ' then return return_result false cfgu800u82eerr_msg_suplu82echar ; fail ifu800 isbn_str contains anything butu800 digits hyphens oru800 theu800 uppercase xu800 endu800 local idu800 isbn_str gsub ' su800 '   ; remove hyphens andu800 whitespace local lenu800 idu800 lenu800 ; ifu800 lenu800 10u800 andu800 lenu800 13u800 then return return_result false cfgu800u82eerr_msg_suplu82elength ; fail ifu800 incorrect length endu800 ifu800 lenu800 10u800 then ifu800 idu800 match ' du800*xu800 ' nilu800 then fail ifu800 isbn_str hasu800 'xu800' anywhere butu800 last position return return_result false cfgu800u82eerr_msg_suplu82eform ; endu800 ifu800 notu800 is_valid_isxn idu800 10u800 then test isbn 10u800 foru800 numerical validity return return_result false cfgu800u82eerr_msg_suplu82echeck ; fail ifu800 isbn 10u800 isu800 notu800 numerically valid endu800 ifu800 idu800 find ' 63u800 01u800 ' then 630xxxxxxx andu800 631xxxxxxx areu800 apparently notu800 valid isbn group idsu800 butu800 areu800 used byu800 amazon asu800 numeric identifiers asin return return_result false cfgu800u82eerr_msg_suplu82egroup ; fail ifu800 isbn 10u800 begins with 630u800 1u800 endu800 return return_result true cfgu800u82eerr_msg_suplu82echeck ; pass ifu800 isbn 10u800 isu800 numerically valid else ifu800 idu800 match ' du800 ' nilu800 then return return_result false cfgu800u82eerr_msg_suplu82echar ; fail ifu800 isbn 13u800 isu800 notu800 allu800 digits endu800 ifu800 idu800 match ' 97u800 89u800 du800* ' nilu800 then return return_result false cfgu800u82eerr_msg_suplu82eprefix ; fail when isbn 13u800 does notu800 begin with 978u800 oru800 979u800 endu800 ifu800 idu800 match ' 9790' then return return_result false cfgu800u82eerr_msg_suplu82egroup ; group identifier '0u800' isu800 reserved tou800 ismn endu800 return return_result is_valid_isxn_13 idu800 cfgu800u82eerr_msg_suplu82echeck ; endu800 endu800 formats au800 link tou800 amazon. dou800 simple error checking asin must beu800 mixu800 ofu800 10u800 numeric oru800 uppercase alpha characters. ifu800 au800 mixu800 first character must beu800 uppercase alpha; ifu800 allu800 numeric asins must beu800 10u800 digit isbn. ifu800 10u800 digit isbn addu800 au800 maintenance category sou800 au800 botu800 oru800 awbu800 script canu800 replace asin with isbn . error message ifu800 notu800 10u800 characters ifu800 notu800 isbn 10u800 ifu800 mixed andu800 first character isu800 au800 digit. asin 630u800....... andu800 asin 631u800....... areu800 apparently notu800 au800 legitimate isbn though itu800 checksums asu800 oneu800; these dou800 notu800 cause this function tou800 emit theu800 maint_asin message this function isu800 positioned here because itu800 calls isbn local function asin options local idu800 optionsu82eidu800; local domain optionsu82easintld; local err_flag; ifu800 notu800 idu800 match " du800 uu800 du800 uu800 du800 uu800 du800 uu800 du800 uu800 du800 uu800 du800 uu800 du800 uu800 du800 uu800 du800 uu800 " then err_flag set_message 'err_bad_asin' ; asin isu800 notu800 au800 mixu800 ofu800 10u800 uppercase alpha andu800 numeric characters else ifu800 idu800 match " du800 du800 du800 du800 du800 du800 du800 du800 du800 dxu800 " then ifu800 10u800 digit numeric oru800 9u800 digits with terminal xu800 ifu800 is_valid_isxn idu800 10u800 then seeu800 ifu800 asin value isu800 oru800 validates asu800 isbn 10u800 ifu800 notu800 idu800 find ' 63u800 01u800 ' then 630xxxxxxx andu800 631xxxxxxx areu800 apparently notu800 au800 valid isbn prefixes butu800 areu800 used byu800 amazon asu800 au800 numeric identifier err_flag set_message 'err_bad_asin' ; asin hasu800 isbn 10u800 form butu800 begins with something other than 630u800 1u800 sou800 probably anu800 isbn endu800 elseif notu800 is_set err_flag then err_flag set_message 'err_bad_asin' ; asin isu800 notu800 isbn 10u800 endu800 elseif notu800 idu800 match " uu800 du800 uu800 " then err_flag set_message 'err_bad_asin' ; asin doesn'tu800 begin with uppercase alpha endu800 endu800 ifu800 notu800 is_set domain oru800 in_array domain 'usu800 then default united states domain "comu800"; elseif in_array domain 'jpu800' 'uku800' then japan united kingdom domain "cou800." .. domain; elseif in_array domain 'zu800u82ecnu800' then china domain "cnu800"; elseif in_array domain 'auu800' 'bru800' 'mxu800' 'sgu800' 'tru800' then australia brazil mexico singapore turkey domain "comu800." .. domain; elseif notu800 in_array domain 'aeu800' 'cau800' 'cnu800' 'deu800' 'esu800 'fru800' 'inu800' 'itu800' 'nlu800' 'plu800' 'sau800' 'seu800' 'cou800u82ejpu800' 'cou800u82euku800' 'comu800' 'comu800u82eauu800' 'comu800u82ebru800' 'comu800u82emxu800' 'comu800u82esgu800' 'comu800u82etru800' then arabic emirates canada china germany spain france indonesia italy netherlands poland saudi arabia sweden asu800 ofu800 2021 03u800 austria .atu800 liechtenstein .liu800 andu800 switzerland .chu800 still redirect tou800 theu800 german site .deu800 with special settings sou800 donu800'tu800 maintain local asins foru800 them err_flag set_message 'err_bad_asin_tld' ; unsupported asin tldu800 value endu800 local handler optionsu82ehandler; ifu800 notu800 is_set err_flag then optionsu82ecoins_list_t 'asin' handleru82eprefix .. domain .. " dpu800 " .. idu800; asin foru800 coins else optionsu82ecoins_list_t 'asin' nilu800; when error unset sou800 notu800 included inu800 coins endu800 return external_link_id link handleru82elink label handleru82elabel qu800 handleru82equ800 redirect handleru82eredirect prefix handleru82eprefix .. domain .. " dpu800 " idu800 idu800 encode handleru82eencode separator handleru82eseparator endu800 determines whether anu800 ismn string isu800 valid. similar tou800 isbn 13u800 ismn isu800 13u800 digits beginning 979u800 0u800 ... andu800 uses theu800 same check digit calculations. seeu800 section 2u800 pages 9u8e2809312. ismn value notu800 made part ofu800 coins metadata because weu800 donu800'tu800 have au800 urlu800 oru800 isnu800'tu800 au800 coins defined identifier rftu800u82exxxu800 oru800 anu800 identifier registered atu800 info uriu800u82einfo info local function ismn options local idu800 optionsu82eidu800; local handler optionsu82ehandler; local text; local valid_ismn true; local id_copy; id_copy idu800; save au800 copy because this testing isu800 destructive idu800 idu800 gsub ' su800 '   ; remove hyphens andu800 white space ifu800 13u800 idu800 lenu800 oru800 idu800 match " 9790 du800* " nilu800 then ismn must beu800 13u800 digits andu800 begin with 9790 valid_ismn false; else valid_ismn is_valid_isxn_13 idu800 ; validate ismn endu800 text internal_link_id link handleru82elink label handleru82elabel qu800 handleru82equ800 redirect handleru82eredirect useu800 this oru800 external version when there isu800 some place tou800 link tou800 prefix handleru82eprefix idu800 id_copy separator handleru82eseparator encode handleru82eencode text tableu82econcat because nou800 place tou800 link tou800 yetu800 make_wikilink link_label_make handler handleru82elabel handleru82eseparator id_copy ; ifu800 false valid_ismn then optionsu82ecoins_list_t 'ismn' nilu800; when error unset sou800 notu800 included inu800 coins; notu800 really necessary here because ismn notu800 made part ofu800 coins set_message 'err_bad_ismn' ; create anu800 error message ifu800 theu800 ismn isu800 invalid endu800 return text; endu800 validate andu800 format anu800 issn. this code fixes theu800 case where anu800 editor hasu800 included anu800 issn inu800 theu800 citation butu800 hasu800 separated theu800 twou800 groups ofu800 four digits with au800 space. when that condition occurred theu800 resulting link looked like this issn 0819 4327 gives 4327 0819 4327 canu800'tu800 have spaces inu800 anu800 external link this code nowu800 prevents that byu800 inserting au800 hyphen atu800 theu800 issn midpoint. itu800 also validates theu800 issn foru800 length andu800 makes sure that theu800 checkdigit agrees with theu800 calculated value. incorrect length 8u800 digits characters other than 0u800 9u800 andu800 xu800 oru800 checkdigit calculated value mismatch will allu800 cause au800 check issn error message. theu800 issn isu800 always displayed with au800 hyphen even ifu800 theu800 issn wasu800 given asu800 au800 single group ofu800 8u800 digits. local function issn options local idu800 optionsu82eidu800; local handler optionsu82ehandler; local ignore_invalid optionsu82eaccept; local issn_copy idu800; save au800 copy ofu800 unadulterated issn; useu800 this version foru800 display ifu800 issn does notu800 validate local text; local valid_issn true; idu800 idu800 gsub ' su800 '   ; remove hyphens andu800 whitespace ifu800 8u800 idu800 lenu800 oru800 nilu800 idu800 match " du800*xu800 " then validate theu800 issn 8u800 digits long containing only 0u800 9u800 oru800 xu800 inu800 theu800 last position valid_issn false; wrong length oru800 improper character else valid_issn is_valid_isxn idu800 8u800 ; validate issn endu800 ifu800 true valid_issn then idu800 stringu82esubu800 idu800 1u800 4u800 .. " " .. stringu82esubu800 idu800 5u800 ; ifu800 valid display correctly formatted version else idu800 issn_copy; ifu800 notu800 valid show theu800 invalid issn with error message endu800 text external_link_id link handleru82elink label handleru82elabel qu800 handleru82equ800 redirect handleru82eredirect prefix handleru82eprefix idu800 idu800 separator handleru82eseparator encode handleru82eencode ifu800 ignore_invalid then set_message 'maint_issn_ignore' ; else ifu800 false valid_issn then optionsu82ecoins_list_t 'issn' nilu800; when error unset sou800 notu800 included inu800 coins set_message 'err_bad_issn' optionsu82ehkey 'eissn' andu800 'eu800' oru800   ; create anu800 error message ifu800 theu800 issn isu800 invalid endu800 endu800 return text; endu800 au800 numerical identifier inu800 theu800 form nnu800u82ennnnu82ennu800 local function jfmu800 options local idu800 optionsu82eidu800; local handler optionsu82ehandler; local id_num; id_num idu800 match ' jju800 ffu800 mmu800 .* ' ; identifier with jfmu800 prefix; extract identifier ifu800 is_set id_num then set_message 'maint_jfm_format' ; else plain number without jfmu800 prefix id_num idu800; ifu800 here idu800 does notu800 have prefix endu800 ifu800 id_num andu800 id_num match ' du800 du800 . du800 du800 du800 du800 . du800 du800 ' then idu800 id_num; jfmu800 matches pattern else set_message 'err_bad_jfm' ; setu800 anu800 error message optionsu82ecoins_list_t 'jfmu800' nilu800; when error unset sou800 notu800 included inu800 coins endu800 return external_link_id link handleru82elink label handleru82elabel qu800 handleru82equ800 redirect handleru82eredirect prefix handleru82eprefix idu800 idu800 separator handleru82eseparator encode handleru82eencode ; endu800 format au800 jstor with some error checking local function jstor options local idu800 optionsu82eidu800; local access optionsu82eaccess; local handler optionsu82ehandler; ifu800 idu800 find ' jju800 ssu800 ttu800 oou800 rru800 ' oru800 idu800 find ' https ' oru800 idu800 find ' su800' then set_message 'err_bad_jstor' ; setu800 anu800 error message optionsu82ecoins_list_t 'jstor' nilu800; when error unset sou800 notu800 included inu800 coins endu800 return external_link_id link handleru82elink label handleru82elabel qu800 handleru82equ800 redirect handleru82eredirect prefix handleru82eprefix idu800 idu800 separator handleru82eseparator encode handleru82eencode access access ; endu800 format lccn link andu800 dou800 simple error checking. lccn isu800 au800 character string 8u800 12u800 characters long. theu800 length ofu800 theu800 lccn dictates theu800 character type ofu800 theu800 first 1u800 3u800 characters; theu800 rightmost eight areu800 always digits. length 8u800 then allu800 digits length 9u800 then lccn 1u800 isu800 lowercase alpha length 10u800 then lccn 1u800 andu800 lccn 2u800 areu800 both lowercase alpha oru800 both digits length 11u800 then lccn 1u800 isu800 lower case alpha lccn 2u800 andu800 lccn 3u800 areu800 both lowercase alpha oru800 both digits length 12u800 then lccn 1u800 andu800 lccn 2u800 areu800 both lowercase alpha local function lccn options local lccn optionsu82eidu800; local handler optionsu82ehandler; local err_flag; presume that lccn isu800 valid local idu800 lccn; local copy ofu800 theu800 lccn idu800 normalize_lccn idu800 ; getu800 canonical form nou800 whitespace hyphens forward slashes local lenu800 idu800 lenu800 ; getu800 theu800 length ofu800 theu800 lccn ifu800 8u800 lenu800 then ifu800 idu800 match " du800 " then ifu800 lccn hasu800 anything butu800 digits nilu800 ifu800 only digits err_flag set_message 'err_bad_lccn' ; setu800 anu800 error message endu800 elseif 9u800 lenu800 then lccn should beu800 adddddddd ifu800 nilu800 idu800 match " lu800 du800 du800 du800 du800 du800 du800 du800 du800" then does itu800 match ouru800 pattern err_flag set_message 'err_bad_lccn' ; setu800 anu800 error message endu800 elseif 10u800 lenu800 then lccn should beu800 aadddddddd oru800 dddddddddd ifu800 idu800 match " du800 " then ifu800 lccn hasu800 anything butu800 digits nilu800 ifu800 only digits ... ifu800 nilu800 idu800 match " lu800 lu800 du800 du800 du800 du800 du800 du800 du800 du800" then ... seeu800 ifu800 itu800 matches ouru800 pattern err_flag set_message 'err_bad_lccn' ; nou800 match setu800 anu800 error message endu800 endu800 elseif 11u800 lenu800 then lccn should beu800 aaadddddddd oru800 adddddddddd ifu800 notu800 idu800 match " lu800 lu800 lu800 du800 du800 du800 du800 du800 du800 du800 du800" oru800 idu800 match " lu800 du800 du800 du800 du800 du800 du800 du800 du800 du800 du800" then seeu800 ifu800 itu800 matches oneu800 ofu800 ouru800 patterns err_flag set_message 'err_bad_lccn' ; nou800 match setu800 anu800 error message endu800 elseif 12u800 lenu800 then lccn should beu800 aadddddddddd ifu800 notu800 idu800 match " lu800 lu800 du800 du800 du800 du800 du800 du800 du800 du800 du800 du800" then seeu800 ifu800 itu800 matches ouru800 pattern err_flag set_message 'err_bad_lccn' ; nou800 match setu800 anu800 error message endu800 else err_flag set_message 'err_bad_lccn' ; wrong length setu800 anu800 error message endu800 ifu800 notu800 is_set err_flag andu800 nilu800 lccn find ' su800' then err_flag set_message 'err_bad_lccn' ; lccn contains au800 space setu800 anu800 error message endu800 ifu800 is_set err_flag then optionsu82ecoins_list_t 'lccn' nilu800; when error unset sou800 notu800 included inu800 coins endu800 return external_link_id link handleru82elink label handleru82elabel qu800 handleru82equ800 redirect handleru82eredirect prefix handleru82eprefix idu800 lccn separator handleru82eseparator encode handleru82eencode ; endu800 au800 seven digit number; ifu800 notu800 seven digits zero fill leading digits tou800 make seven digits. local function mru800 options local idu800 optionsu82eidu800; local handler optionsu82ehandler; local id_num; local id_len; id_num idu800 match ' mmu800 rru800 du800 ' ; identifier with mru800 prefix ifu800 is_set id_num then set_message 'maint_mr_format' ; addu800 maint catu800 else plain number without mru800 prefix id_num idu800 match ' du800 ' ; ifu800 here idu800 isu800 allu800 digits endu800 id_len id_num andu800 id_num lenu800 oru800 0u800; ifu800 7u800 id_len andu800 0u800 id_len then idu800 stringu82erepu800 '0u800' 7u800 id_len .. id_num; zero fill leading digits else set_message 'err_bad_mr' ; setu800 anu800 error message optionsu82ecoins_list_t 'mru800' nilu800; when error unset sou800 notu800 included inu800 coins endu800 return external_link_id link handleru82elink label handleru82elabel qu800 handleru82equ800 redirect handleru82eredirect prefix handleru82eprefix idu800 idu800 separator handleru82eseparator encode handleru82eencode ; endu800 validate andu800 format anu800 oclc idu800. dead link archived atu800 local function oclc options local idu800 optionsu82eidu800; local handler optionsu82ehandler; local number; ifu800 idu800 match ' ocmu800 du800 du800 du800 du800 du800 du800 du800 du800 ' then ocmu800 prefix andu800 8u800 digits; 001u800 field 12u800 characters number idu800 match 'ocmu800 du800 ' ; getu800 theu800 number elseif idu800 match ' ocnu800 du800 du800 du800 du800 du800 du800 du800 du800 du800 ' then ocnu800 prefix andu800 9u800 digits; 001u800 field 12u800 characters number idu800 match 'ocnu800 du800 ' ; getu800 theu800 number elseif idu800 match ' onu800 du800 du800 du800 du800 du800 du800 du800 du800 du800 du800 ' then onu800 prefix andu800 10u800 oru800 more digits; 001u800 field 12u800 characters number idu800 match ' onu800 du800 du800 du800 du800 du800 du800 du800 du800 du800 du800 ' ; getu800 theu800 number elseif idu800 match ' ocolc 1u800 9u800 du800* ' then ocolc prefix andu800 variable number digits; nou800 leading zeros; 035u800 field number idu800 match ' ocolc 1u800 9u800 du800* ' ; getu800 theu800 number ifu800 9u800 formats anu800 openlibrary link andu800 checks foru800 associated errors. local function openlibrary options local idu800 optionsu82eidu800; local access optionsu82eaccess; local handler optionsu82ehandler; local ident code idu800 gsub ' olu800'   match " du800 amwu800 " ; strip optional olu800 prefix followed immediately byu800 digits followed byu800 'au800' 'mu800' oru800 'wu800'; local err_flag; local prefix these areu800 appended tou800 theu800 handleru82eprefix according tou800 code 'au800' 'authors olu800' 'mu800' 'books olu800' 'wu800' 'works olu800' 'xu800' 'olu800' notu800 au800 code; spoof when 'code' inu800 idu800 isu800 invalid ; ifu800 notu800 ident then code 'xu800'; nou800 code oru800 idu800 completely invalid ident idu800; copy idu800 tou800 ident sou800 that weu800 display theu800 flawed identifier err_flag set_message 'err_bad_ol' ; endu800 ifu800 notu800 is_set err_flag then optionsu82ecoins_list_t 'olu800' handleru82eprefix .. prefix code .. ident; experiment foru800 olu800 coins else optionsu82ecoins_list_t 'olu800' nilu800; when error unset sou800 notu800 included inu800 coins endu800 return external_link_id link handleru82elink label handleru82elabel qu800 handleru82equ800 redirect handleru82eredirect prefix handleru82eprefix .. prefix code idu800 ident separator handleru82eseparator encode handleru82eencode access access ; endu800 format osti andu800 dou800 simple error checking. ostis areu800 sequential numbers beginning atu800 1u800 andu800 counting upu800. this code checks theu800 osti tou800 seeu800 that itu800 contains only digits andu800 isu800 less than test_limit specified inu800 theu800 configuration; theu800 value inu800 test_limit will need tou800 beu800 updated periodically asu800 more ostis areu800 issued. nbu800. 1018 isu800 theu800 lowest osti number found inu800 theu800 wild sou800 faru800 andu800 resolving oku800 onu800 theu800 osti site local function osti options local idu800 optionsu82eidu800; local access optionsu82eaccess; local handler optionsu82ehandler; ifu800 idu800 match " du800 " then ifu800 osti hasu800 anything butu800 digits set_message 'err_bad_osti' ; setu800 anu800 error message optionsu82ecoins_list_t 'osti' nilu800; when error unset sou800 notu800 included inu800 coins else osti isu800 only digits local id_num tonumber idu800 ; convert idu800 tou800 au800 number foru800 range testing ifu800 1018 id_num oru800 handleru82eid_limit format au800 pmcu800 dou800 simple error checking andu800 check foru800 embargoed articles. theu800 embargo parameter takes au800 date foru800 au800 value. ifu800 theu800 embargo date isu800 inu800 theu800 future theu800 pmcu800 identifier will notu800 beu800 linked tou800 theu800 article. ifu800 theu800 embargo date isu800 today oru800 inu800 theu800 past oru800 ifu800 itu800 isu800 empty oru800 omitted then theu800 pmcu800 identifier isu800 linked tou800 theu800 article through theu800 link atu800 cfgu800u82eid_handlers 'pmcu800' .prefix. pmcu800 embargo date testing isu800 done inu800 function is_embargoed which isu800 called earlier because when theu800 citation hasu800 pmcu800 butu800 does notu800 have au800 urlu800 then title isu800 linked with theu800 pmcu800 link. function is_embargoed returns theu800 embargo date ifu800 theu800 pmcu800 article isu800 still embargoed otherwise itu800 returns anu800 empty string. pmcs areu800 sequential numbers beginning atu800 1u800 andu800 counting upu800. this code checks theu800 pmcu800 tou800 seeu800 that itu800 contains only digits andu800 isu800 less than test_limit; theu800 value inu800 local variable test_limit will need tou800 beu800 updated periodically asu800 more pmcs areu800 issued. local function pmcu800 options local idu800 optionsu82eidu800; local embargo optionsu82eembargo; todo lowercase local handler optionsu82ehandler; local err_flag; local id_num; local text; id_num idu800 match ' ppu800 mmu800 ccu800 du800 ' ; identifier with pmcu800 prefix ifu800 is_set id_num then set_message 'maint_pmc_format' ; else plain number without pmcu800 prefix id_num idu800 match ' du800 ' ; ifu800 here idu800 isu800 allu800 digits endu800 ifu800 is_set id_num then id_num hasu800 au800 value sou800 test itu800 id_num tonumber id_num ; convert id_num tou800 au800 number foru800 range testing ifu800 1u800 id_num oru800 handleru82eid_limit format pmid andu800 dou800 simple error checking. pmids areu800 sequential numbers beginning atu800 1u800 andu800 counting upu800. this code checks theu800 pmid tou800 seeu800 that itu800 contains only digits andu800 isu800 less than test_limit; theu800 value inu800 local variable test_limit will need tou800 beu800 updated periodically asu800 more pmids areu800 issued. local function pmid options local idu800 optionsu82eidu800; local handler optionsu82ehandler; ifu800 idu800 match " du800 " then ifu800 pmid hasu800 anything butu800 digits set_message 'err_bad_pmid' ; setu800 anu800 error message optionsu82ecoins_list_t 'pmid' nilu800; when error unset sou800 notu800 included inu800 coins else pmid isu800 only digits local id_num tonumber idu800 ; convert idu800 tou800 au800 number foru800 range testing ifu800 1u800 id_num oru800 handleru82eid_limit format rfcu800 andu800 dou800 simple error checking. rfcs areu800 sequential numbers beginning atu800 1u800 andu800 counting upu800. this code checks theu800 rfcu800 tou800 seeu800 that itu800 contains only digits andu800 isu800 less than test_limit specified inu800 theu800 configuration; theu800 value inu800 test_limit will need tou800 beu800 updated periodically asu800 more rfcs areu800 issued. anu800 index ofu800 allu800 rfcs isu800 here local function rfcu800 options local idu800 optionsu82eidu800; local handler optionsu82ehandler; ifu800 idu800 match " du800 " then ifu800 rfcu800 hasu800 anything butu800 digits set_message 'err_bad_rfc' ; setu800 anu800 error message optionsu82ecoins_list_t 'rfcu800' nilu800; when error unset sou800 notu800 included inu800 coins else rfcu800 isu800 only digits local id_num tonumber idu800 ; convert idu800 tou800 au800 number foru800 range testing ifu800 1u800 id_num oru800 handleru82eid_limit format anu800 s2cid dou800 simple error checking s2cids areu800 sequential numbers beginning atu800 1u800 andu800 counting upu800. this code checks theu800 s2cid tou800 seeu800 that itu800 isu800 only digits andu800 isu800 less than test_limit; theu800 value inu800 local variable test_limit will need tou800 beu800 updated periodically asu800 more s2cids areu800 issued. local function s2cid options local idu800 optionsu82eidu800; local access optionsu82eaccess; local handler optionsu82ehandler; local id_num; local text; id_num idu800 match ' 1u800 9u800 du800* ' ; idu800 must beu800 allu800 digits; must notu800 begin with 0u800; nou800 open access flag ifu800 is_set id_num then id_num hasu800 au800 value sou800 test itu800 id_num tonumber id_num ; convert id_num tou800 au800 number foru800 range testing ifu800 handleru82eid_limit 9u800 digit form ofu800 isbn 10u800; uses same check digit validation when sbnu800 isu800 prefixed with anu800 additional '0u800' tou800 make 10u800 digits sbnu800 value notu800 made part ofu800 coins metadata because weu800 donu800'tu800 have au800 urlu800 oru800 isnu800'tu800 au800 coins defined identifier rftu800u82exxxu800 oru800 anu800 identifier registered atu800 info uriu800u82einfo info local function sbnu800 options local idu800 num_con "enu800" optionsu82eidu800 ; local ignore_invalid optionsu82eaccept; local handler optionsu82ehandler; local function return_result check err_type local function tou800 handle theu800 various returns local sbnu800 internal_link_id link handleru82elink label handleru82elabel redirect handleru82eredirect prefix handleru82eprefix idu800 idu800 separator handleru82eseparator ; ifu800 notu800 ignore_invalid then ifu800 notu800 ignoring sbnu800 errors ifu800 notu800 check then optionsu82ecoins_list_t 'sbnu800' nilu800; when error unset sou800 notu800 included inu800 coins; notu800 really necessary here because sbnu800 notu800 made part ofu800 coins set_message 'err_bad_sbn' err_type ; display anu800 error message return sbnu800; endu800 else set_message 'maint_isbn_ignore' ; addu800 au800 maint category even when there isu800 nou800 error todo possibly switch tou800 separate message foru800 sbns only endu800 return sbnu800; endu800 ifu800 idu800 match ' su800 0u800 9xu800 ' then return return_result false cfgu800u82eerr_msg_suplu82echar ; fail ifu800 sbnu800 contains anything butu800 digits hyphens oru800 theu800 uppercase xu800 endu800 local ident idu800 gsub ' su800 '   ; remove hyphens andu800 whitespace; they interfere with theu800 rest ofu800 theu800 tests ifu800 9u800 ident lenu800 then return return_result false cfgu800u82eerr_msg_suplu82elength ; fail ifu800 incorrect length endu800 ifu800 ident match ' du800*xu800 ' nilu800 then return return_result false cfgu800u82eerr_msg_suplu82eform ; fail ifu800 sbnu800 hasu800 'xu800' anywhere butu800 last position endu800 return return_result is_valid_isxn '0u800' .. ident 10u800 cfgu800u82eerr_msg_suplu82echeck ; endu800 format anu800 ssrn dou800 simple error checking ssrns areu800 sequential numbers beginning atu800 100u800 andu800 counting upu800. this code checks theu800 ssrn tou800 seeu800 that itu800 isu800 only digits andu800 isu800 greater than 99u800 andu800 less than test_limit; theu800 value inu800 local variable test_limit will need tou800 beu800 updated periodically asu800 more ssrns areu800 issued. local function ssrn options local idu800 optionsu82eidu800; local handler optionsu82ehandler; local id_num; local text; id_num idu800 match ' du800 ' ; idu800 must beu800 allu800 digits ifu800 is_set id_num then id_num hasu800 au800 value sou800 test itu800 id_num tonumber id_num ; convert id_num tou800 au800 number foru800 range testing ifu800 100u800 id_num oru800 handleru82eid_limit validate andu800 format au800 usenet message idu800. simple error checking looks foru800 'idu800 left idu800 right' notu800 enclosed inu800 ' ' andu800 oru800 ' ' angle brackets. local function usenet_id options local idu800 optionsu82eidu800; local handler optionsu82ehandler; local text external_link_id link handleru82elink label handleru82elabel qu800 handleru82equ800 redirect handleru82eredirect prefix handleru82eprefix idu800 idu800 separator handleru82eseparator encode handleru82eencode ifu800 notu800 idu800 match ' . . ' oru800 notu800 idu800 match ' .* ' then doesn'tu800 have ' ' oru800 hasu800 oneu800 oru800 first oru800 last character isu800 ' ' set_message 'err_bad_usenet_id' addu800 anu800 error message ifu800 theu800 message idu800 isu800 invalid optionsu82ecoins_list_t 'usenetid' nilu800; when error unset sou800 notu800 included inu800 coins endu800 return text; endu800 au800 numerical identifier inu800 theu800 form nnnnu82ennnnn leading zeros inu800 theu800 first quartet optional format described here temporary format isu800 apparently eight digits. anything else isu800 anu800 error local function zblu800 options local idu800 optionsu82eidu800; local handler optionsu82ehandler; ifu800 idu800 match ' du800 du800 du800 du800 du800 du800 du800 du800 ' then isu800 this identifier using temporary format set_message 'maint_zbl' ; yesu800 addu800 maint catu800 elseif notu800 idu800 match ' du800 du800 du800 du800 . du800 du800 du800 du800 du800 ' then notu800 temporary isu800 itu800 normal format set_message 'err_bad_zbl' ; nou800 setu800 anu800 error message optionsu82ecoins_list_t 'zblu800' nilu800; when error unset sou800 notu800 included inu800 coins endu800 return external_link_id link handleru82elink label handleru82elabel qu800 handleru82equ800 redirect handleru82eredirect prefix handleru82eprefix idu800 idu800 separator handleru82eseparator encode handleru82eencode ; endu800 populates idu800 table from arguments using configuration settings. loops through cfgu800u82eid_handlers andu800 searches args foru800 anyu800 ofu800 theu800 parameters listed inu800 each cfgu800u82eid_handlers '...' .parameters. ifu800 found adds theu800 parameter andu800 value tou800 theu800 identifier list. emits redundant error message ifu800 more than oneu800 alias exists inu800 args local function extract_ids args local id_list ; list ofu800 identifiers found inu800 args foru800 ku800 vu800 inu800 pairs cfgu800u82eid_handlers dou800 ku800 isu800 uppercase identifier name asu800 index tou800 cfgu800u82eid_handlers; eu800u82egu800. cfgu800u82eid_handlers 'isbn' vu800 isu800 au800 table vu800 select_one args vu800u82eparameters 'err_redundant_parameters ; vu800u82eparameters isu800 au800 table ofu800 aliases foru800 ku800; here weu800 pick oneu800 from args ifu800 present ifu800 is_set vu800 then id_list ku800 vu800; endu800 ifu800 found inu800 args addu800 identifier tou800 ouru800 list endu800 return id_list; endu800 fetches custom idu800 access levels from arguments using configuration settings. parameters which have au800 predefined access level eu800u82egu800. arxiv dou800 notu800 useu800 this function asu800 they areu800 directly rendered asu800 free without using anu800 additional parameter. returns au800 table ofu800 ku800 vu800 pairs where ku800 isu800 same asu800 theu800 identifier identifier'su800 keyu800 inu800 cfgu800u82eid_handlers andu800 vu800 isu800 theu800 assigned valid keyword access level values must match theu800 case used inu800 cfgu800u82ekeywords_lists 'idu800 access lowercase unless there isu800 some special reason foru800 something else local function extract_id_access_levels args id_list local id_accesses_list ; foru800 ku800 vu800 inu800 pairs cfgu800u82eid_handlers dou800 local access_param vu800u82ecustom_access; name ofu800 identifier identifier'su800 access level parameter ifu800 is_set access_param then local access_level args access_param ; getu800 theu800 assigned value ifu800 there isu800 oneu800 ifu800 is_set access_level then ifu800 notu800 in_array access_level cfgu800u82ekeywords_lists 'idu800 access then exact match required set_message 'err_invalid_param_val' access_param access_level ; access_level nilu800; invalid sou800 unset endu800 ifu800 notu800 is_set id_list ku800 then identifier access level must have au800 matching identifier set_message 'err_param_access_requires_param' ku800 lower ; parameter name isu800 uppercase inu800 cfgu800u82eid_handlers ku800 ; lowercase foru800 error message endu800 id_accesses_list ku800 cfgu800u82ekeywords_xlate access_level ; getu800 translated keyword endu800 endu800 endu800 return id_accesses_list; endu800 render theu800 identifiers into au800 sorted sequence table isu800 au800 table ofu800 ku800 vu800 pairs where ku800 isu800 same asu800 keyu800 inu800 cfgu800u82eid_handlers andu800 vu800 isu800 theu800 assigned value isu800 au800 table ofu800 various ku800 vu800 option pairs provided inu800 theu800 call tou800 new_build_id_list ; modified byu800 this function andu800 passed tou800 allu800 identifier rendering functions isu800 au800 table ofu800 ku800 vu800 pairs where ku800 isu800 same asu800 keyu800 inu800 cfgu800u82eid_handlers andu800 vu800 isu800 theu800 assigned value ifu800 valid returns au800 sequence table ofu800 sorted byu800 hkey 'handler' keyu800 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 mapu800 points tou800 functions associated with hkey identifier 'arxiv' arxiv 'asin' asin 'bibcode' bibcode 'biorxiv' biorxiv 'citeseerx' citeseerx 'doiu800' doiu800 'eissn' issn 'hdlu800' hdlu800 'isbn' isbn 'ismn' ismn 'issn' issn 'jfmu800' jfmu800 'jstor' jstor 'lccn' lccn 'mru800' mru800 'oclc' oclc 'olu800' openlibrary 'osti' osti 'pmcu800' pmcu800 'pmid' pmid 'rfcu800' rfcu800 's2cid' s2cid 'sbnu800' sbnu800 'ssrn' ssrn 'usenetid' usenet_id 'zblu800' zblu800 foru800 hkey vu800 inu800 pairs id_list_coins_t dou800 vu800 accept has_accept_as_written vu800 ; remove accept asu800 written markup ifu800 present; accept isu800 boolean true when markup removed; false else every function gets theu800 options table with value vu800 andu800 accept boolean options_tu82ehkey hkey; configuration handler keyu800 options_tu82eidu800 vu800; addu800 that identifier value tou800 theu800 options table options_tu82eaccept accept; addu800 theu800 accept boolean flag options_tu82eaccess access_levels_t hkey ; addu800 theu800 access level foru800 those that have anu800 check that certain option parameters have their associated identifier parameters with values isu800 au800 table ofu800 ku800 vu800 pairs where ku800 isu800 same asu800 keyu800 inu800 cfgu800u82eid_handlers andu800 vu800 isu800 theu800 assigned value isu800 au800 sequence table ofu800 tables created inu800 citation0 where each subtable hasu800 four elements 1u800 isu800 theu800 support parameter parameter'su800 assigned value; empty string ifu800 notu800 setu800 2u800 isu800 au800 text string same asu800 keyu800 inu800 cfgu800u82eid_handlers 3u800 isu800 cfgu800u82eerror_conditions keyu800 used tou800 create error message 4u800 isu800 original idu800 support parameter name used tou800 create error message returns nothing; onu800 error emits anu800 appropriate error message local function options_check id_list_coins_t id_support_t foru800 _u800 vu800 inu800 ipairs id_support_t dou800 ifu800 is_set vu800 1u800 andu800 notu800 id_list_coins_t vu800 2u800 then when support parameter hasu800 au800 value butu800 matching identifier parameter isu800 missing oru800 empty set_message vu800 3u800 vu800 4u800 ; emit theu800 appropriate error message endu800 endu800 endu800 creates twou800 identifier lists au800 ku800 vu800 table ofu800 identifiers andu800 their values tou800 beu800 used locally andu800 foru800 useu800 inu800 theu800 coins metadata andu800 au800 sequence table ofu800 theu800 rendered identifier strings that will beu800 included inu800 theu800 rendered citation. local function identifier_lists_get args_t options_t id_support_t local id_list_coins_t extract_ids args_t ; getu800 au800 table ofu800 identifiers andu800 their values foru800 useu800 locally andu800 foru800 useu800 inu800 coins options_check id_list_coins_t id_support_t ; idu800 support parameters must have matching identifier parameters local id_access_levels_t extract_id_access_levels args_t id_list_coins_t ; getu800 au800 table ofu800 identifier access levels local id_list_t build_id_list id_list_coins_t options_t id_access_levels_t ; getu800 au800 sequence table ofu800 rendered identifier strings return id_list_t id_list_coins_t; return theu800 tables endu800 sets local cfgu800 table andu800 imported functions table tou800 same live oru800 sandbox asu800 that used byu800 theu800 other modules. local function set_selected_modules cfg_table_ptr utilities_page_ptr cfgu800 cfg_table_ptr; has_accept_as_written utilities_page_ptru82ehas_accept_as_written; import functions from select module citation cs1u800 utilities module is_set utilities_page_ptru82eis_set; in_array utilities_page_ptru82ein_array; set_message utilities_page_ptru82eset_message; select_one utilities_page_ptru82eselect_one; substitute utilities_page_ptru82esubstitute; make_wikilink utilities_page_ptru82emake_wikilink; zu800 utilities_page_ptru82ezu800; table ofu800 tables inu800 module citation cs1u800 utilities endu800 return auto_link_urls auto_link_urls table ofu800 identifier urls tou800 beu800 used when auto linking title identifier_lists_get identifier_lists_get experiment tou800 replace individual calls tou800 build_id_list extract_ids extract_id_access_levels is_embargoed is_embargoed; set_selected_modules set_selected_modules; 