This module contains the code of the {{Authority control}} template. See its documentation.

Parameters, Wikidata properties, and tracking categories সম্পাদনা কৰক

Parameter Section Appears as Wikidata property Tracking categories and page counts
Articles User pages Misc. pages Faulty IDs
AAG আৰ্ট গেলেৰী আৰু সংগ্ৰহালয় Auckland P3372: Auckland Art Gallery artist ID 2 0 2 0
ACM-DL বৈজ্ঞানিক ডাটাবেচ Association for Computing Machinery P864: ACM Digital Library author ID 4 0 2 0
ADB জীৱনীমূলক অভিধান Australia P1907: Australian Dictionary of Biography ID 3 0 0 0
AGSA আৰ্ট গেলেৰী আৰু সংগ্ৰহালয় South Australia P6804: Art Gallery of South Australia creator ID 2 0 0 0
autores.uy জীৱনীমূলক অভিধান Uruguay P2558: autores.uy ID 0 0 0 0
AWR জীৱনীমূলক অভিধান Australian Women's Register P4186: Australian Women's Register ID 0 0 0 0
BIBSYS ৰাষ্ট্ৰীয় পুথিভঁৰাল Norway P1015: NORAF ID 203 0 2 0
Bildindex কলা গৱেষণা প্ৰতিষ্ঠান Bildindex (Germany) P2092: Bildindex der Kunst und Architektur ID 0 0 0 0
BNC ৰাষ্ট্ৰীয় পুথিভঁৰাল Chile P1890: CCAB ID 78 0 0 0
BNE ৰাষ্ট্ৰীয় পুথিভঁৰাল Spain P950: National Library of Spain ID 152 0 2 0
BNF ৰাষ্ট্ৰীয় পুথিভঁৰাল France (data) P268: Bibliothèque nationale de France ID 292 0 2 0
Botanist বৈজ্ঞানিক ডাটাবেচ International Plant Names Index P428: botanist author abbreviation 5 0 0 0
BPN জীৱনীমূলক অভিধান Netherlands P651: Biografisch Portaal van Nederland ID 5 0 0 0
CANTIC ৰাষ্ট্ৰীয় পুথিভঁৰাল Catalonia P1273: CANTIC ID (former scheme) 122 0 0 0
CINII বৈজ্ঞানিক ডাটাবেচ CiNii (Japan) P271: NACSIS-CAT author ID 195 0 2 0
CWGC অন্যান্য Commonwealth War Graves Commission P1908: CWGC person ID 0 0 0 0
DAAO কলা গৱেষণা প্ৰতিষ্ঠান Australian Artists P1707: DAAO ID 0 0 0 0
DBLP বৈজ্ঞানিক ডাটাবেচ DBLP (computer science) P2456: DBLP author ID 14 0 0 0
DIB জীৱনীমূলক অভিধান Ireland P6829: Dictionary of Irish Biography ID 0 0 0 4
DSI কলা গৱেষণা প্ৰতিষ্ঠান Scientific illustrators P2349: Stuttgart Database of Scientific Illustrators ID 0 0 0 0
EMU ৰাষ্ট্ৰীয় পুথিভঁৰাল Ukraine P4613: Encyclopedia of Modern Ukraine ID 8 0 0 0
FAST অন্যান্য Faceted Application of Subject Terminology P2163: FAST ID 311 0 0 0
FNZA কলা গৱেষণা প্ৰতিষ্ঠান New Zealand Artists P6792: Find NZ Artists ID 0 0 0 0
GND সাধাৰণ Integrated Authority File (Germany) P227: GND ID 392 0 2 2
HDS অন্যান্য Historical Dictionary of Switzerland P902: HDS ID 7 0 2 0
IAAF অন্যান্য World Athletics P1146: World Athletics athlete ID 0 0 0 0
ICCU ৰাষ্ট্ৰীয় পুথিভঁৰাল Italy P396: SBN author ID 0 0 2 107
ICIA কলা গৱেষণা প্ৰতিষ্ঠান ICIA (Israel) P1736: Information Center for Israeli Art artist ID 0 0 0 0
IEU অন্যান্য Internet Encyclopedia of Ukraine P9070: Internet Encyclopedia of Ukraine ID 0 0 0 0
ISNI সাধাৰণ ISNI P213: ISNI 347 0 2 0
Joconde কলা গৱেষণা প্ৰতিষ্ঠান Joconde (France) P347: Joconde work ID 0 0 0 0
KULTURNAV কলা গৱেষণা প্ৰতিষ্ঠান KulturNav (Norway) P1248: KulturNav-ID 15 0 0 0
LCCN ৰাষ্ট্ৰীয় পুথিভঁৰাল United States P244: Library of Congress authority ID 448 0 2 0
LIR অন্যান্য Lexicon Istoric Retic (Switzerland) P886: Lexicon istoric retic ID 0 0 0 0
LNB ৰাষ্ট্ৰীয় পুথিভঁৰাল Latvia P1368: National Library of Latvia ID 127 0 0 0
Léonore অন্যান্য Léonore (France) P640: Léonore ID 4 0 0 0
MA অন্যান্য Microsoft Academic P6366: Microsoft Academic ID 45 0 0 0
MBA অন্যান্য MusicBrainz artist P434: MusicBrainz artist ID 122 0 2 0
MBAREA অন্যান্য MusicBrainz area P982: MusicBrainz area ID 1 0 0 0
MBI অন্যান্য MusicBrainz instrument P1330: MusicBrainz instrument ID 0 0 0 0
MBL অন্যান্য MusicBrainz label P966: MusicBrainz label ID 0 0 0 0
MBP অন্যান্য MusicBrainz place P1004: MusicBrainz place ID 1 0 0 0
MBRG অন্যান্য MusicBrainz release group P436: MusicBrainz release group ID 0 0 0 0
MBS অন্যান্য MusicBrainz series P1407: MusicBrainz series ID 1 0 0 0
MBW অন্যান্য MusicBrainz work P435: MusicBrainz work ID 1 0 0 0
MGP বৈজ্ঞানিক ডাটাবেচ Mathematics Genealogy Project P549: Mathematics Genealogy Project ID 66 0 0 0
NARA অন্যান্য National Archives (US) P1225: U.S. National Archives Identifier 41 0 0 0
NCL ৰাষ্ট্ৰীয় পুথিভঁৰাল Taiwan P1048: NCL ID 15 0 0 0
NDL ৰাষ্ট্ৰীয় পুথিভঁৰাল Japan P349: NDL Authority ID 187 0 2 0
NGV আৰ্ট গেলেৰী আৰু সংগ্ৰহালয় Victoria P2041: National Gallery of Victoria artist ID 4 0 0 0
NKC ৰাষ্ট্ৰীয় পুথিভঁৰাল Czech Republic P691: NL CR AUT ID 239 0 2 0
NLA ৰাষ্ট্ৰীয় পুথিভঁৰাল Australia P409: Libraries Australia ID 172 0 2 0
NLG ৰাষ্ট্ৰীয় পুথিভঁৰাল Greece P3348: National Library of Greece ID 98 0 0 0
NLI ৰাষ্ট্ৰীয় পুথিভঁৰাল Israel P949: National Library of Israel ID (old) 132 0 0 0
NLK ৰাষ্ট্ৰীয় পুথিভঁৰাল Korea P5034: National Library of Korea ID 128 0 0 0
NLP ৰাষ্ট্ৰীয় পুথিভঁৰাল Poland P1695: NLP ID (old) 0 0 0 1
NLR ৰাষ্ট্ৰীয় পুথিভঁৰাল Romania P1003: National Library of Romania ID 13 0 0 0
NSK ৰাষ্ট্ৰীয় পুথিভঁৰাল Croatia P1375: NSK ID 105 0 0 0
NTA ৰাষ্ট্ৰীয় পুথিভঁৰাল Netherlands P1006: Nationale Thesaurus voor Auteursnamen ID 250 0 0 0
ORCID সাধাৰণ ORCID P496: ORCID iD 44 0 2 0
PIC কলা গৱেষণা প্ৰতিষ্ঠান Photographers' Identities P2750: Photographers’ Identities Catalog ID 9 0 0 0
PLWABN ৰাষ্ট্ৰীয় পুথিভঁৰাল Poland P7293: PLWABN ID 188 0 0 0
Publons বৈজ্ঞানিক ডাটাবেচ Publons (researchers) P3829: Publons author ID 5 0 0 0
RID বৈজ্ঞানিক ডাটাবেচ ResearcherID P1053: ResearcherID 7 0 0 0
RISM অন্যান্য RISM (France) P5504: RISM ID 0 0 0 22
RERO অন্যান্য RERO (Switzerland) P3065: RERO ID (obsolete) 161 0 0 0
RKDartists কলা গৱেষণা প্ৰতিষ্ঠান RKD Artists (Netherlands) P650: RKDartists ID 19 0 2 0
RKDID কলা গৱেষণা প্ৰতিষ্ঠান RKD ID (Netherlands) P350: RKDimages ID 0 0 0 0
RSL ৰাষ্ট্ৰীয় পুথিভঁৰাল Russia P947: RSL ID (person) 27 0 2 0
SELIBR ৰাষ্ট্ৰীয় পুথিভঁৰাল Sweden P906: SELIBR ID 119 0 2 0
SIKART কলা গৱেষণা প্ৰতিষ্ঠান SIKART (Switzerland) P781: SIKART ID 1 0 0 0
SNAC-ID অন্যান্য Social Networks and Archival Context P3430: SNAC ARK ID 141 0 0 0
SUDOC অন্যান্য SUDOC (France) P269: IdRef ID 310 0 2 0
S2AuthorId বৈজ্ঞানিক ডাটাবেচ Semantic Scholar P4012: Semantic Scholar author ID 24 0 0 0
TA98 বৈজ্ঞানিক ডাটাবেচ Terminologia Anatomica P1323: Terminologia Anatomica 98 ID 1 0 0 0
TDVİA অন্যান্য Encyclopedia of Islam P7314: TDV İslam Ansiklopedisi ID 30 0 0 0
TePapa আৰ্ট গেলেৰী আৰু সংগ্ৰহালয় Te Papa (New Zealand) P3544: Te Papa agent ID 17 0 0 0
TLS অন্যান্য Theaterlexikon (Switzerland) P1362: Theaterlexikon der Schweiz ID 0 0 0 0
Trove অন্যান্য Trove (Australia) P1315: NLA Trove people ID 172 0 0 0
UKPARL অন্যান্য UK Parliament P6213: UK Parliament ID 1 0 0 0
ULAN কলা গৱেষণা প্ৰতিষ্ঠান Artist Names (Getty) P245: Union List of Artist Names ID 45 0 2 0
USCongress অন্যান্য US Congress P1157: US Congress Bio ID 2 0 0 0
VcBA ৰাষ্ট্ৰীয় পুথিভঁৰাল Vatican P8034: Vatican Library VcBA ID 64 0 0 0
VIAF সাধাৰণ VIAF P214: VIAF ID 410 0 2 0
WORLDCATID সাধাৰণ WorldCat P7859: WorldCat Identities ID (superseded) 356 0 0 0
সাধাৰণ WorldCat (via Library of Congress) 3
সাধাৰণ WorldCat (via VIAF) 54
Totals 85 6,567 0 44 136

Additional tracking categories সম্পাদনা কৰক

This module also implements the following hidden tracking categories:

Number of identifiers সম্পাদনা কৰক

State parameter সম্পাদনা কৰক

See also সম্পাদনা কৰক


require('Module:No globals')

local p = {}
local title = mw.title.getCurrentTitle()
local namespace = title.namespace
local testcases = (string.sub(title.subpageText,1,9) == 'testcases')

--[[==========================================================================]]
--[[                            Category functions                            ]]
--[[==========================================================================]]

function p.getCatForId( id )
	local catName = ''
	if namespace == 0 then
		catName = 'Articles with '..id..' identifiers'
	elseif namespace == 2 and not title.isSubpage then
		catName = 'User pages with '..id..' identifiers'
	else
		catName = 'Miscellaneous pages with '..id..' identifiers'
	end
	return '[[Category:'..catName..']]'..p.redCatLink(catName)
end

function p.redCatLink( catName ) --catName == 'Blah' (not 'Category:Blah', not '[[Category:Blah]]')
	if catName and catName ~= '' and
	   testcases == false and
	   mw.title.new(catName, 14).exists == false
	then
		return '[[Category:Pages with red-linked authority control categories]]'
	end
	return ''
end

function p.createRow( id, rawValues, link, links, withUid, specialCat, prefix)
	local catName = 'Articles with faulty '..(specialCat or id)..' identifiers'
	if links then -- all links[] use withUid = false; no check needed
		local row = ''
		if prefix then 
			row = row..'*'..prefix
		end
		for i, l in ipairs( links ) do
			if i == 1 and not prefix then row = row..'*'
			else           row = row..'\n**' end
			if l then
				row = row..'<span class="uid">'..l..'</span>'
			else
				row = row..'<span class="error">The '..id..' id '..rawValues[i]..' is not valid.</span>[[Category:'..catName..']]'..p.redCatLink(catName)
			end
		end
		return row..'\n'
	elseif link then -- All IDs that have a prefix support multiple identifiers, so prefix is not needed
		if withUid then
			return '*<span class="nowrap"><span class="uid">'..link..'</span></span>\n'
		end
		return '*<span class="nowrap">'..link..'</span>\n'
	end
	
	return '* <span class="error">The '..id..' id '..rawValues..' is not valid.</span>[[Category:'..catName..']]'..p.redCatLink(catName)..'\n'
end

--[[==========================================================================]]
--[[                      Property formatting functions                       ]]
--[[==========================================================================]]

-- If a link has a suitable entry in the global inter-wiki prefix table at [[:m:Interwiki_map]],
-- please consider routing through this prefix rather than as external link URL.
-- This will ease future maintenance as necessary updates to the link can be centrally carried out there rather than by updating this module.
-- The "external link" icon would disappear for such entries.

function p.aagLink( id, label)
	--P3372's format regex: \d+ (e.g. 1)
	if not id:match( '^%d+$' ) then
		return false
	end
	return '[https://www.aucklandartgallery.com/explore-art-and-ideas/artist/'..id..'/ '..(label or 'Auckland')..']'..p.getCatForId( 'AAG' )
end

function p.acmLink( id, label )
	--P864's format regex: \d{11} (e.g. 12345678901)
	if not id:match( '^%d%d%d%d%d%d%d%d%d%d%d$' ) then
		return false
	end
	return '[https://dl.acm.org/profile/'..id..' '..(label or 'Association for Computing Machinery')..']'..p.getCatForId( 'ACM-DL' )
end

function p.adbLink( id, label )
	--P1907's format regex: [a-z][-a-z]+-([1-3]\d|[1-9])\d{0,3} (e.g. barton-sir-edmund-toby-71)
	if not id:match( '^[a-z][-a-z]+-[1-3]%d%d?%d?%d?$' ) and
	   not id:match( '^[a-z][-a-z]+-[1-9]%d?%d?%d?$' ) then
		return false
	end
	return '[http://adb.anu.edu.au/biography/'..id..' '..(label or 'Australia')..']'..p.getCatForId( 'ADB' )
end

function p.agsaLink( id, label )
	--P6804's format regex: [1-9]\d* (e.g. 3625)
	if not id:match( '^[1-9]%d*$' ) then
		return false
	end
	return '[https://www.agsa.sa.gov.au/collection-publications/collection/creators/_/'..id..'/ '..(label or 'South Australia')..']'..p.getCatForId( 'AGSA' )
end

function p.autoresuyLink( id, label )
	--P2558's format regex: [1-9]\d{0,4} (e.g. 12345)
	if not id:match( '^[1-9]%d?%d?%d?%d?$' ) then
		return false
	end
	return '[https://autores.uy/autor/'..id..' '..(label or 'Uruguay')..']'..p.getCatForId( 'autores.uy' )
end

function p.awrLink( id, label )
	--P4186's format regex: (([A-Z]{3}\d{4})|([A-Z]{2}\d{5}))[a-z] (e.g. PR00768b)
	if not id:match( '^[A-Z][A-Z][A-Z]%d%d%d%d[a-z]$' ) and
	   not id:match( '^[A-Z][A-Z]%d%d%d%d%d[a-z]$' ) then
		return false
	end
	return '[http://www.womenaustralia.info/biogs/'..id..'.htm '..(label or 'Australian Women\'s Register')..']'..p.getCatForId( 'AWR' )
end

function p.bibsysLink( id, label )
	--P1015's format regex: [1-9]\d* or [1-9](\d{0,8}|\d{12}) (e.g. 1234567890123)
	--TODO: follow up @ [[d:Property talk:P1015#Discrepancy between the 2 regex constraints]] or escalate/investigate
	if not id:match( '^[1-9]%d?%d?%d?%d?%d?%d?%d?%d?$' ) and
	   not id:match( '^[1-9]%d%d%d%d%d%d%d%d%d%d%d%d$' ) then
		return false
	end
	return '[https://authority.bibsys.no/authority/rest/authorities/html/'..id..' '..(label or 'Norway')..']'..p.getCatForId( 'BIBSYS' )
end

function p.bildLink( id, label )
	--P2092's format regex: \d+ (e.g. 1)
	if not id:match( '^%d+$' ) then
		return false
	end
	return '[https://www.bildindex.de/document/obj'..id..' '..(label or 'Bildindex (Germany)')..']'..p.getCatForId( 'Bildindex' )
end

function p.bncLink( id, label )
	--P1890's format regex: \d{9} (e.g. 123456789)
	if not id:match( '^%d%d%d%d%d%d%d%d%d$' ) then
		return false
	end
	return '[http://www.bncatalogo.cl/F?func=direct&local_base=red10&doc_number='..id..' '..(label or 'Chile')..']'..p.getCatForId( 'BNC' )
end

function p.bneLink( id, label )
	--P950's format regex: (XX|FF|a)\d{4,7}|(bima|bimo|bica|bis[eo]|bivi|Mise|Mimo|Mima)\d{10} (e.g. XX1234567)
	if not id:match( '^[XF][XF]%d%d%d%d%d?%d?%d?$' ) and
	   not id:match( '^a%d%d%d%d%d?%d?%d?$' ) and
	   not id:match( '^bi[mcsv][aoei]%d%d%d%d%d%d%d%d%d%d$' ) and
	   not id:match( '^Mi[sm][eoa]%d%d%d%d%d%d%d%d%d%d$' ) then
		return false
	end
	return '[http://catalogo.bne.es/uhtbin/authoritybrowse.cgi?action=display&authority_id='..id..' '..(label or 'Spain')..']'..p.getCatForId( 'BNE' ) --no https as of 9/2019
end

function p.bnfLink( id, label )
	--P268's format regex: \d{8}[0-9bcdfghjkmnpqrstvwxz] (e.g. 123456789)
	if not id:match( '^c?b?%d%d%d%d%d%d%d%d[0-9bcdfghjkmnpqrstvwxz]$' ) then
		return false
	end
	--Add cb prefix if it has been removed
	if not id:match( '^cb.+$' ) then
		id = 'cb'..id
	end
	return '[https://catalogue.bnf.fr/ark:/12148/'..id..' '..(label or 'France')..'] [https://data.bnf.fr/ark:/12148/'..id..' (data)]'..p.getCatForId( 'BNF' )
end

function p.botanistLink( id, label )
	--P428's format regex: ('t )?(d')?(de )?(la )?(van (der )?)?(Ma?c)?(De)?(Di)?\p{Lu}?C?['\p{Ll}]*([-'. ]*(van )?(y )?(d[ae][nr]?[- ])?(Ma?c)?[\p{Lu}bht]?C?['\p{Ll}]*)*\.? ?f?\.? (e.g. L.)
	--not easily/meaningfully implementable in Lua's regex since "(this)?" is not allowed...
	if not mw.ustring.match( id, "^[%u%l%d%. '-]+$" ) then --better than nothing
		return false
	end
	id = id:gsub(' +', '%%20')
	return '[https://www.ipni.org/ipni/advAuthorSearch.do?find_abbreviation='..id..' '..(label or 'International Plant Names Index')..']'..p.getCatForId( 'Botanist' )
end

function p.bpnLink( id, label )
	--P651's format regex: \d{6,8} (e.g. 00123456)
	if not id:match( '^%d%d%d%d%d%d%d%d$' ) and --original format regex, changed 8/2019 to
	   not id:match( '^0?%d%d%d%d%d%d%d$' ) and --allow 1-2 leading 0s, allowed by the website
	   not id:match( '^0?0?%d%d%d%d%d%d$' ) then
		return false
	end
	return '[http://www.biografischportaal.nl/en/persoon/'..id..' '..(label or 'Netherlands')..']'..p.getCatForId( 'BPN' ) --no https as of 9/2019
end

function p.canticLink( id, label )
	--P1273's format regex: a\d{7}[0-9x] (e.g. a10640745)
	if not id:match( '^a%d%d%d%d%d%d%d[%dx]$' ) then
		return false
	end
	return '[http://cantic.bnc.cat/registres/CUCId/'..id..' '..(label or 'Catalonia')..']'..p.getCatForId( 'CANTIC' ) --no https as of 10/2019
end

function p.ciniiLink( id, label )
	--P271's format regex: DA\d{7}[\dX] (e.g. DA12345678)
	if not id:match( '^DA%d%d%d%d%d%d%d[%dX]$' ) then
		return false
	end
	return '[https://ci.nii.ac.jp/author/'..id..'?l=en '..(label or 'CiNii (Japan)')..']'..p.getCatForId( 'CINII' )
end

function p.cwgcLink( id, label )
	--P1908's format regex: [1-9]\d* (e.g. 75228351)
	if not id:match( '^[1-9]%d*$' ) then
		return false
	end
	return '[https://www.cwgc.org/find-war-dead/casualty/'..id..'/ '..(label or 'Commonwealth War Graves Commission')..']'..p.getCatForId( 'CWGC' )
end

function p.emuLink( id, label )
	--P4613's format regex: \d{1,6} (e.g. 15409 (or 015409))
	if not id:match( '^%d%d?%d?%d?%d?%d?$' ) then
		return false
	end
	return '[http://esu.com.ua/search_articles.php?id='..id..' '..(label or 'Ukraine')..']'..p.getCatForId( 'EMU' )
end

function p.daaoLink( id, label )
	--P1707's format regex: [a-z\-]+\d* (e.g. rolf-harris)
	if not id:match( '^[a-z%-]+%d*$' ) then
		return false
	end
	return '[https://www.daao.org.au/bio/'..id..' '..(label or 'Australian Artists')..']'..p.getCatForId( 'DAAO' )
end

function p.dblpLink( id, label )
	--P2456's format regex: \d{2,3} /\d+(-\d+)?|[a-z] /[a-zA-Z][0-9A-Za-z]*(-\d+)? (e.g. 123/123)
	if not id:match( '^%d%d%d?/%d+$' ) and
	   not id:match( '^%d%d%d?/%d+%-%d+$' ) and
	   not id:match( '^[a-z]/[a-zA-Z][0-9A-Za-z]*$' ) and
	   not id:match( '^[a-z]/[a-zA-Z][0-9A-Za-z]*%-%d+$' ) then
		return false
	end
	return '[https://dblp.org/pid/'..id..' '..(label or 'DBLP (computer science)')..']'..p.getCatForId( 'DBLP' )
end

function p.dibLink( id, label )
	--P6829's format regex: a\d{4}\d?(-[A-D])? (e.g. a1953)
	if not id:match( '^a%d%d%d%d%d?%-?[A-D]?$' ) then
		return false
	end
	return '[https://dib.cambridge.org/viewReadPage.do?articleId='..id..' '..(label or 'Ireland')..']'..p.getCatForId( 'DIB' )
end

function p.dsiLink( id, label )
	--P2349's format regex: [1-9]\d* (e.g. 1538)
	if not id:match( '^[1-9]%d*$' ) then
		return false
	end
	return '[http://www.uni-stuttgart.de/hi/gnt/dsi2/index.php?table_name=dsi&function=details&where_field=id&where_value='..id..' '..(label or 'Scientific illustrators')..']'..p.getCatForId( 'DSI' )
end

function p.fastLink( id, label )
	--P2163's format regex: [1-9]\d{0,7} (e.g. 1916996)
	if not id:match( '^[1-9]%d?%d?%d?%d?%d?%d?%d?$' ) then
		return false
	end
	return '[http://id.worldcat.org/fast/'..id..'/ '..(label or 'Faceted Application of Subject Terminology')..']'..p.getCatForId( 'FAST' )
end


function p.fnzaLink( id, label )
	--P6792's format regex: [1-9]\d* (e.g. 9785)
	if not id:match( '^[1-9]%d*$' ) then
		return false
	end
	return '[https://findnzartists.org.nz/artist/'..id..'/ '..(label or 'New Zealand Artists')..']'..p.getCatForId( 'FNZA' )
end

function p.gndLink( id, label )
	--P227's format regex: 1[012]?\d{7}[0-9X]|[47]\d{6}-\d|[1-9]\d{0,7}-[0-9X]|3\d{7}[0-9X] (e.g. 4079154-3)
	if not id:match( '^1[012]?%d%d%d%d%d%d%d[0-9X]$' ) and
	   not id:match( '^[47]%d%d%d%d%d%d%-%d$' ) and
	   not id:match( '^[1-9]%d?%d?%d?%d?%d?%d?%d?%-[0-9X]$' ) and
	   not id:match( '^3%d%d%d%d%d%d%d[0-9X]$' ) then
		return false
	end
	return '[https://d-nb.info/gnd/'..id..' '..(label or 'Integrated Authority File (Germany)')..']'..p.getCatForId( 'GND' )
end

function p.hdsLink( id, label )
	--P902's format regex: \d{6} (e.g. 050123)
	if not id:match( '^%d%d%d%d%d%d$' ) then
		return false
	end
	return '[https://hls-dhs-dss.ch/fr/articles/'..id..' '..(label or 'Historical Dictionary of Switzerland')..']'..p.getCatForId( 'HDS' )
end

function p.iaafLink( id, label )
	--P1146's format regex: [0-9][0-9]* (e.g. 012)
	if not id:match( '^%d+$' ) then
		return false
	end
	return '[https://www.iaaf.org/athletes/_/'..id..' '..(label or 'World Athletics')..']'..p.getCatForId( 'IAAF' )
end


function p.iccuLink( id, label )
	--P396's format regex: IT\\ICCU\\(\d{10}|\D\D[\D\d]\D\\\d{6}) (e.g. IT\ICCU\CFIV\000163)
	if not id:match( '^IT\\ICCU\\%d%d%d%d%d%d%d%d%d%d$' ) and
	   not id:match( '^IT\\ICCU\\%u%u[%u%d]%u\\%d%d%d%d%d%d$' ) then --legacy: %u used here instead of %D (but the faulty ID cat is empty, out of ~12k uses)
		return false
	end
	return '[https://opac.sbn.it/opacsbn/opac/iccu/scheda_authority.jsp?bid='..id..' '..(label or 'Italy')..']'..p.getCatForId( 'ICCU' )
end
function p.iciaLink( id, label )
	--P1736's format regex: \d+ (e.g. 1)
	if not id:match( '^%d+$' ) then
		return false
	end
	return '[https://www.imj.org.il/artcenter/newsite/en/?artist='..id..' '..(label or 'ICIA (Israel)')..']'..p.getCatForId( 'ICIA' )
end

function p.ieuLink( id, label )
	--P9070's format regex: [A-Z]\\[A-Z]\\[A-Za-z0-9]+ (e.g. K\Y\Kyiv)
	if not id:match( '^[A-Z]\\[A-Z]\\%w+$' ) then
		return false
	end
	return '[http://www.encyclopediaofukraine.com/display.asp?linkpath=pages\\'..id..' '..(label or 'Internet Encyclopedia of Ukraine')..']'..p.getCatForId( 'IEU' )
end

function p.isniLink( id, label )
	id = p.validateIsni( id ) --e.g. 0000-0000-6653-4145
	if not id then
		return false
	end
	return '[https://isni.org/isni/'..id..' '..(label or 'ISNI')..']'..p.getCatForId( 'ISNI' )
end

function p.jocondeLink( id, label )
	--P347's format regex: [\-0-9A-Za-z]{11} (e.g. 12345678901)
	local regex = '^'..string.rep('[%-0-9A-Za-z]', 11)..'$'
	if not id:match( regex ) then
		return false
	end
	return '[https://www.pop.culture.gouv.fr/notice/joconde/'..id..' '..(label or 'Joconde (France)')..']'..p.getCatForId( 'Joconde' )
end

function p.kulturnavLink( id, label )
	--P1248's format regex: [0-9a-f]{8}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{12} (e.g. 12345678-1234-1234-1234-1234567890AB)
	if not id:match( '^%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x$' ) then
		return false
	end
	return '[http://kulturnav.org/'..id..' '..(label or 'KulturNav (Norway)')..']'..p.getCatForId( 'KULTURNAV' ) --no https as of 9/2019
end

function p.lccnLink( id, label )
	local parts = p.splitLccn( id ) --e.g. n78039510
	if not parts then
		return false
	end
	local lccnType = parts[1] ~= 'sh' and 'names' or 'subjects'
	id = parts[1] .. parts[2] .. p.append( parts[3], '0', 6 )
	return '[https://id.loc.gov/authorities/'..lccnType..'/'..id..' '..(label or 'United States')..']'..p.getCatForId( 'LCCN' )
end

function p.lirLink( id, label )
	--P886's format regex: \d+ (e.g. 1)
	if not id:match( '^%d+$' ) then
		return false
	end
	return '[http://www.e-lir.ch/e-LIR___Lexicon.'..id..'.450.0.html '..(label or 'Lexicon Istoric Retic (Switzerland)')..']'..p.getCatForId( 'LIR' ) --no https as of 9/2019
end

function p.lnbLink( id, label )
	--P1368's format regex: \d{9} (e.g. 123456789)
	if not id:match( '^%d%d%d%d%d%d%d%d%d$' ) then
		return false
	end
	return '[https://kopkatalogs.lv/F?func=direct&local_base=lnc10&doc_number='..id..'&P_CON_LNG=ENG '..(label or 'Latvia')..']'..p.getCatForId( 'LNB' )
end

function p.leonoreLink( id, label )
	--P640's format regex: LH//\d{1,4}/\d{1,3}|19800035/\d{1,4}/\d{1,5}(Bis|Ter)?|C/0/\d{1,2} (e.g. LH//2064/18)
	if not id:match( '^LH//%d%d?%d?%d?/%d%d?%d?$' ) and               --IDs from      LH//1/1 to        LH//2794/54 (legionaries)
	   not id:match( '^19800035/%d%d?%d?%d?/%d%d?%d?%d?%d?$' ) and    --IDs from 19800035/1/1 to 19800035/385/51670 (legionnaires who died 1954-1977 & some who died < 1954)
	   not id:match( '^19800035/%d%d?%d?%d?/%d%d?%d?%d?%d?Bis$' ) and --IDs from ?
	   not id:match( '^19800035/%d%d?%d?%d?/%d%d?%d?%d?%d?Ter$' ) and --IDs from ?
	   not id:match( '^C/0/%d%d?$' ) then                             --IDs from        C/0/1 to             C/0/84 (84 famous legionaries)
		return false
	end
	return '[http://www.culture.gouv.fr/public/mistral/leonore_fr?ACTION=CHERCHER&FIELD_1=COTE&VALUE_1='..id..' '..(label or 'Léonore (France)')..']'..p.getCatForId( 'Léonore' ) --no https as of 9/2019
end

function p.maLink( id, label )
	--P6366's format regex: [1-9]\d{3,9} (e.g. 1498221862)
	if not id:match( '^[1-9]%d%d%d%d?%d?%d?%d?%d?%d?$' ) then
		return false
	end
	return '[https://academic.microsoft.com/v2/detail/'..id..' '..(label or 'Microsoft Academic')..']'..p.getCatForId( 'MA' )
end

function p.mbaLink( id, label )
	--P434's format regex: [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} (e.g. 12345678-1234-1234-1234-1234567890AB)
	if not id:match( '^%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x$' ) then
		return false
	end
	local url = 'https://musicbrainz.org/artist/'..id
	local cat = p.getCatForId( 'MusicBrainz' )--special cat name
	if label then
		return '['..url..' '..label..']'..cat	
	else
		return '[[:en:MBA (identifier)|MusicBrainz]] ['..url..' artist]'..cat
	end
end

function p.mbareaLink( id, label )
	--P982's format regex: [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} (e.g. 12345678-1234-1234-1234-1234567890AB)
	if not id:match( '^%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x$' ) then
		return false
	end
	local url = 'https://musicbrainz.org/area/'..id
	local cat = p.getCatForId( 'MusicBrainz area' )--special cat name
	if label then
		return '['..url..' '..label..']'..cat	
	else
		return '[[:en:MBAREA (identifier)|MusicBrainz]] ['..url..' area]'..cat
	end
end

function p.mbiLink( id, label )
	--P1330's format regex: [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} (e.g. 12345678-1234-1234-1234-1234567890AB)
	if not id:match( '^%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x$' ) then
		return false
	end
	local url = 'https://musicbrainz.org/instrument/'..id
	local cat = p.getCatForId( 'MusicBrainz instrument' )--special cat name
	if label then
		return '['..url..' '..label..']'..cat	
	else
		return '[[:en:MBI (identifier)|MusicBrainz]] ['..url..' instrument]'..cat
	end
end

function p.mblLink( id, label )
	--P966's format regex: [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} (e.g. 12345678-1234-1234-1234-1234567890AB)
	if not id:match( '^%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x$' ) then
		return false
	end
	local url = 'https://musicbrainz.org/label/'..id
	local cat = p.getCatForId( 'MusicBrainz label' )--special cat name
	if label then
		return '['..url..' '..label..']'..cat	
	else
		return '[[:en:MBL (identifier)|MusicBrainz]] ['..url..' label]'..cat
	end
end

function p.mbpLink( id, label )
	--P1004's format regex: [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} (e.g. 12345678-1234-1234-1234-1234567890AB)
	if not id:match( '^%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x$' ) then
		return false
	end
	local url = 'https://musicbrainz.org/place/'..id
	local cat = p.getCatForId( 'MusicBrainz place' )--special cat name
	if label then
		return '['..url..' '..label..']'..cat	
	else
		return '[[:en:MBP (identifier)|MusicBrainz]] ['..url..' place]'..cat
	end
end

function p.mbrgLink( id, label )
	--P436's format regex: [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} (e.g. 12345678-1234-1234-1234-1234567890AB)
	if not id:match( '^%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x$' ) then
		return false
	end
	local url = 'https://musicbrainz.org/release-group/'..id
	local cat = p.getCatForId( 'MusicBrainz release group' )--special cat name
	if label then
		return '['..url..' '..label..']'..cat	
	else
		return '[[:en:MBRG (identifier)|MusicBrainz]] ['..url..' release group]'..cat
	end
end

function p.mbsLink( id, label )
	--P1407's format regex: [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} (e.g. 12345678-1234-1234-1234-1234567890AB)
	if not id:match( '^%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x$' ) then
		return false
	end
	local url = 'https://musicbrainz.org/series/'..id
	local cat = p.getCatForId( 'MusicBrainz series' )--special cat name
	if label then
		return '['..url..' '..label..']'..cat	
	else
		return '[[:en:MBS (identifier)|MusicBrainz]] ['..url..' series]'..cat
	end
end

function p.mbwLink( id, label )
	--P435's format regex: [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} (e.g. 12345678-1234-1234-1234-1234567890AB)
	if not id:match( '^%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x$' ) then
		return false
	end
	
	local url = 'https://musicbrainz.org/work/'..id
	local cat = p.getCatForId( 'MusicBrainz work' )--special cat name
	if label then
		return '['..url..' '..label..']'..cat	
	else
		return '[[:en:MBW (identifier)|MusicBrainz]] ['..url..' work]'..cat
	end
end

function p.mgpLink( id, label )
	--P549's format regex: \d{1,6} (e.g. 123456)
	if not id:match( '^%d%d?%d?%d?%d?%d?$' ) then
		return false
	end
	return '[https://genealogy.math.ndsu.nodak.edu/id.php?id='..id..' '..(label or 'Mathematics Genealogy Project')..']'..p.getCatForId( 'MGP' )
end

function p.naraLink( id, label )
	--P1225's format regex: ^([1-9]\d{0,8})$ (e.g. 123456789)
	if not id:match( '^[1-9]%d?%d?%d?%d?%d?%d?%d?%d?$' ) then
		return false
	end
	return '[https://catalog.archives.gov/id/'..id..' '..(label or 'National Archives (US)')..']'..p.getCatForId( 'NARA' )
end

function p.nclLink( id, label )
	--P1048's format regex: \d+ (e.g. 1081436)
	if not id:match( '^%d+$' ) then
		return false
	end
	return '[http://aleweb.ncl.edu.tw/F/?func=accref&acc_sequence='..id..'&CON_LNG=ENG '..(label or 'Taiwan')..']'..p.getCatForId( 'NCL' ) --no https as of 9/2019
end

function p.ndlLink( id, label )
	--P349's format regex: 0?\d{8} (e.g. 012345678)
	if not id:match( '^0?%d%d%d%d%d%d%d%d$' ) then
		return false
	end
	return '[https://id.ndl.go.jp/auth/ndlna/'..id..' '..(label or 'Japan')..']'..p.getCatForId( 'NDL' )
end

function p.ngvLink( id, label )
	--P2041's format regex: \d+ (e.g. 12354)
	if not id:match( '^%d+$' ) then
		return false
	end
	return '[https://www.ngv.vic.gov.au/explore/collection/artist/'..id..'/ '..(label or 'Victoria')..']'..p.getCatForId( 'NGV' )
end

function p.nkcLink( id, label )
	--P691's format regex: [a-z]{2,4}[0-9]{2,14} (e.g. abcd12345678901234)
	if not id:match( '^[a-z][a-z][a-z]?[a-z]?%d%d%d?%d?%d?%d?%d?%d?%d?%d?%d?%d?%d?%d?$' ) then
		return false
	end
	return '[https://aleph.nkp.cz/F/?func=find-c&local_base=aut&ccl_term=ica='..id..'&CON_LNG=ENG '..(label or 'Czech Republic')..']'..p.getCatForId( 'NKC' )
end

function p.nlaLink( id, label )
	--P409's format regex: [1-9][0-9]{0,11} (e.g. 123456789012)
	if not id:match( '^[1-9]%d?%d?%d?%d?%d?%d?%d?%d?%d?%d?%d?$' ) then
		return false
	end
	return '[https://nla.gov.au/anbd.aut-an'..id..' '..(label or 'Australia')..']'..p.getCatForId( 'NLA' )
end

function p.nlgLink( id, label )
	--P3348's format regex: [1-9]\d* (e.g. 1)
	if not id:match( '^[1-9]%d*$' ) then
		return false
	end
	return '[https://data.nlg.gr/resource/authority/record'..id..' '..(label or 'Greece')..']'..p.getCatForId( 'NLG' )
end

function p.nliLink( id, label )
	--P949's format regex: \d{9} (e.g. 123456789)
	if not id:match( '^%d%d%d%d%d%d%d%d%d$' ) then
		return false
	end
	return '[http://uli.nli.org.il/F/?func=direct&doc_number='..id..'&local_base=nlx10'..' '..(label or 'Israel')..']'..p.getCatForId( 'NLI' )
end

function p.nlkLink( id, label )
	--P5034's format regex: KA.(19|20).{7} (e.g. KAC201501465)
	if not id:match( '^KA.19.......$' ) and
	   not id:match( '^KA.20.......$' ) then
		return false
	end
	return '[https://nl.go.kr/authorities/resource/'..id..' '..(label or 'Korea')..']'..p.getCatForId( 'NLK' )
end

function p.nlpLink( id, label )
	--P1695's format regex: 9810[0-9]\d* or A[0-9]{7}[0-9X] (e.g. 9810123456789012345 or A10414836)
	if not id:match( '^9810%d+$' ) and
	   not id:match( '^A%d%d%d%d%d%d%d[%dX]$' ) then
		return false
	end
	return '[https://tools.wmflabs.org/wikidata-externalid-url?p=1695&id='..id..' '..(label or 'Poland')..']'..p.getCatForId( 'NLP' )
end

function p.nlrLink( id, label )
	--P1003's format regex: \d{9} (e.g. 123456789)
	if not id:match( '^%d%d%d%d%d%d%d%d%d$' ) then
		return false
	end
	return '[http://aleph.bibnat.ro:8991/F/?func=direct&local_base=NLR10&doc_number='..id..' '..(label or 'Romania')..']'..p.getCatForId( 'NLR' )
end

function p.nskLink( id, label )
	--P1375's format regex: \d{9} (e.g. 123456789)
	if not id:match( '^%d%d%d%d%d%d%d%d%d$' ) then
		return false
	end
	return '[http://katalog.nsk.hr/F/?func=direct&doc_number='..id..'&local_base=nsk10 '..(label or 'Croatia')..']'..p.getCatForId( 'NSK' ) --no https as of 9/2019
end

function p.ntaLink( id, label )
	--P1006's format regex: \d{8}[\dX] (e.g. 12345678X)
	if not id:match( '^%d%d%d%d%d%d%d%d[%dX]$' ) then
		return false
	end
	return '[http://data.bibliotheken.nl/id/thes/p'..id..' '..(label or 'Netherlands')..']'..p.getCatForId( 'NTA' )
end

function p.orcidLink( id, label )
	id = p.validateIsni( id ) --e.g. 0000-0002-7398-5483
	if not id then
		return false
	end
	id = id:sub( 1, 4 )..'-'..id:sub( 5, 8 )..'-'..id:sub( 9, 12 )..'-'..id:sub( 13, 16 )
	return '[https://orcid.org/'..id..' '..(label or 'ORCID')..']'..p.getCatForId( 'ORCID' )
end

function p.picLink( id, label )
	--P2750's format regex: [1-9]\d* (e.g. 1)
	if not id:match( '^[1-9]%d*$' ) then
		return false
	end
	return '[https://pic.nypl.org/constituents/'..id..' '..(label or 'Photographers\' Identities')..']'..p.getCatForId( 'PIC' )
end

function p.plwabnLink( id, label )
	--P7293's format regex: 981[0-9]{8}05606 (e.g. 9810696457305606)
	if not id:match( '^981%d%d%d%d%d%d%d%d05606*$' ) then
		return false
	end
	return '[http://mak.bn.org.pl/cgi-bin/KHW/makwww.exe?BM=1&NU=1&IM=4&WI='..id..' '..(label or 'Poland')..']'..p.getCatForId( 'PLWABN' )
end

function p.publonsLink( id, label )
	--P3829's format regex: \d+ (e.g. 654601)
	if not id:match( '^%d+$' ) then
		return false
	end
	return '[https://publons.com/author/'..id..'/ '..(label or 'Publons (researchers)')..']'..p.getCatForId( 'Publons' )
end

function p.ridLink( id, label )
	--P1053's format regex: [A-Z]{1,3}-\d{4}-(19|20)\d\d (e.g. AAS-5150-2020)
	if not id:match( '^[A-Z][A-Z]?[A-Z]?%-%d%d%d%d%-19%d%d$' ) and
	   not id:match( '^[A-Z][A-Z]?[A-Z]?%-%d%d%d%d%-20%d%d$' ) then
		return false
	end
	return '[https://www.researcherid.com/rid/'..id..' '..(label or 'ResearcherID')..']'..p.getCatForId( 'RID' )
end

function p.rismLink( id, label )
	--P5504's format regex: (pe|ks)?\[1-9]d* (e.g. pe30006410)
	if not id:match( '^pe[1-9]%d*$' ) and --99% start with 'pe'
	   not id:match( '^ks[1-9]%d*$' ) and
	   not id:match( '^[1-9]%d*$' ) then
		return false
	end
	return '[https://opac.rism.info/search?id='..id..' '..(label or 'RISM (France)')..']'..p.getCatForId( 'RISM' )
end

function p.reroLink( id, label )
	--P3065's format regex: 0[1-2]-[A-Z0-9]{1,10} (e.g. 02-A012345678)
	if not id:match( '^0[1-2]%-[A-Z%d][A-Z%d]?[A-Z%d]?[A-Z%d]?[A-Z%d]?[A-Z%d]?[A-Z%d]?[A-Z%d]?[A-Z%d]?[A-Z%d]?$' ) then
		return false
	end
	return '[http://data.rero.ch/'..id..' '..(label or 'RERO (Switzerland)')..']'..p.getCatForId( 'RERO' )
end

function p.rkdartistsLink( id, label )
	--P650's format regex: [1-9]\d{0,5} (e.g. 123456)
	if not id:match( '^[1-9]%d?%d?%d?%d?%d?$' ) then
		return false
	end
	return '[https://rkd.nl/en/explore/artists/'..id..' '..(label or 'RKD Artists (Netherlands)')..']'..p.getCatForId( 'RKDartists' )
end

function p.rkdidLink( id, label )
	--P350's format regex: [1-9]\d{0,5} (e.g. 123456)
	if not id:match( '^[1-9]%d?%d?%d?%d?%d?$' ) then
		return false
	end
	return '[https://rkd.nl/nl/explore/images/'..id..' '..(label or 'RKD ID (Netherlands)')..']'..p.getCatForId( 'RKDID' )
end

function p.rslLink( id, label )
	--P947's format regex: \d{1,9} (e.g. 123456789)
	if not id:match( '^%d%d?%d?%d?%d?%d?%d?%d?%d?$' ) then
		return false
	end
	return '[http://aleph.rsl.ru/F?func=find-b&find_code=SYS&adjacent=Y&local_base=RSL11&request='..id..'&CON_LNG=ENG '..(label or 'Russia')..']'..p.getCatForId( 'RSL' ) --no https as of 9/2019
end

function p.selibrLink( id, label )
	--P906's format regex: [1-9]\d{4,5} (e.g. 123456)
	if not id:match( '^[1-9]%d%d%d%d%d?$' ) then
		return false
	end
	return '[https://libris.kb.se/auth/'..id..' '..(label or 'Sweden')..']'..p.getCatForId( 'SELIBR' )
end

function p.sikartLink( id, label )
	--P781's format regex: \d{7,9} (e.g. 123456789)
	if not id:match( '^%d%d%d%d%d%d%d%d?%d?$' ) then
		return false
	end
	return '[http://www.sikart.ch/KuenstlerInnen.aspx?id='..id..'&lng=en '..(label or 'SIKART (Switzerland)')..']'..p.getCatForId( 'SIKART' ) --no https as of 9/2019
end

function p.snacLink( id, label )
	--P3430's format regex: \d*[A-Za-z][0-9A-Za-z]* (e.g. A)
	if not id:match( '^%d*[A-Za-z][0-9A-Za-z]*$' ) then
		return false
	end
	return '[https://snaccooperative.org/ark:/99166/'..id..' '..(label or 'Social Networks and Archival Context')..']'..p.getCatForId( 'SNAC-ID' )
end

function p.sudocLink( id, label )
	--P269's format regex: (\d{8}[\dX]|) (e.g. 026927608)
	if not id:match( '^%d%d%d%d%d%d%d%d[%dxX]$' ) then --legacy: allow lowercase 'x'
		return false
	end
	return '[https://www.idref.fr/'..id..' '..(label or 'SUDOC (France)')..']'..p.getCatForId( 'SUDOC' )
end

function p.s2authoridLink( id, label )
	--P4012's format regex: [1-9]\d* (e.g. 1796130)
	if not id:match( '^[1-9]%d*$' ) then
		return false
	end
	return '[https://www.semanticscholar.org/author/'..id..' '..(label or 'Semantic Scholar')..']'..p.getCatForId( 'Semantic Scholar author' ) --special cat name
end

function p.ta98Link( id, label )
	--P1323's format regex: A\d{2}\.\d\.\d{2}\.\d{3}[FM]? (e.g. A12.3.45.678)
	if not id:match( '^A%d%d%.%d%.%d%d%.%d%d%d[FM]?$' ) then
		return false
	end
	local longurl = '[http://tools.wmflabs.org/wikidata-externalid-url/?p=1323&url_prefix=https:%2F%2Fwww.unifr.ch%2Fifaa%2FPublic%2FEntryPage%2FTA98%20Tree%2FEntity%20TA98%20EN%2F&url_suffix=%20Entity%20TA98%20EN.htm&id='
	return longurl..id..' '..(label or 'Terminologia Anatomica')..']'..p.getCatForId( 'TA98' )
end

function p.tdviaLink( id, label )
	--P7314's format regex: [a-z/-]+] (e.g. barkan-omer-lutfi)
	if not id:match( '^[a-z/-]+$' ) then
		return false
	end
	return '[https://islamansiklopedisi.org.tr/'..id..' '..(label or 'Encyclopedia of Islam')..']'..p.getCatForId( 'TDVİA' )
end


function p.tepapaLink( id, label )
	--P3544's format regex: \d+ (e.g. 1)
	if not id:match( '^%d+$' ) then
		return false
	end
	return '[https://collections.tepapa.govt.nz/agent/'..id..' '..(label or 'Te Papa (New Zealand)')..']'..p.getCatForId( 'TePapa' )
end

function p.tlsLink( id, label )
	id = id:gsub(' +', '_')
	--P1362's format regex: \p{Lu}[\p{L}\d_',\.\-\(\)\*/–]{3,59} (e.g. Abcd)
	local class = "[%a%d_',%.%-%(%)%*/–]"
	local regex = '^%u'..string.rep(class, 3)..string.rep(class..'?', 56)..'$'
	if not mw.ustring.match( id, regex ) then
		return false
	end
	return '[http://tls.theaterwissenschaft.ch/wiki/'..id..' '..(label or 'Theaterlexikon (Switzerland)')..']'..p.getCatForId( 'TLS' ) --no https as of 9/2019
end

function p.troveLink( id, label )
	--P1315's format regex: [1-9]\d{5,7} (e.g. 12345678)
	if not id:match( '^[1-9]%d%d%d%d%d%d?%d?$' ) then
		return false
	end
	return '[https://trove.nla.gov.au/people/'..id..' '..(label or 'Trove (Australia)')..']'..p.getCatForId( 'Trove' )
end

function p.ukparlLink( id, label )
	--P6213's format regex: [a-zA-Z\d]{8} (e.g. AQUupyiR)
	if not id:match( '^[a-zA-Z%d][a-zA-Z%d][a-zA-Z%d][a-zA-Z%d][a-zA-Z%d][a-zA-Z%d][a-zA-Z%d][a-zA-Z%d]$' ) then
		return false
	end
	return '[https://id.parliament.uk/'..id..' '..(label or 'UK Parliament')..']'..p.getCatForId( 'UKPARL' )
end

function p.ulanLink( id, label )
	--P245's format regex: 500\d{6} (e.g. 500123456)
	if not id:match( '^500%d%d%d%d%d%d$' ) then
		return false
	end
	return '[https://www.getty.edu/vow/ULANFullDisplay?find=&role=&nation=&subjectid='..id..' '..(label or 'Artist Names (Getty)')..']'..p.getCatForId( 'ULAN' )
end

function p.uscongressLink( id, label )
	--P1157's format regex: [A-Z]00[01]\d{3} (e.g. A000123)
	if not id:match( '^[A-Z]00[01]%d%d%d$' ) then
		return false
	end
	return '[http://bioguide.congress.gov/scripts/biodisplay.pl?index='..id..' '..(label or 'US Congress')..']'..p.getCatForId( 'USCongress' ) --no https as of 9/2019
end

function p.vcbaLink( id, label )
	--P8034's format regex: \d{3}\/[1-9]\d{0,5} (e.g. 494/9793)
	if not id:match( '^%d%d%d\/[1-9]%d?%d?%d?%d?%d?$' ) then
		return false
	end
	id = id:gsub('\/', '_')
	return '[https://opac.vatlib.it/auth/detail/'..id..' '..(label or 'Vatican')..']'..p.getCatForId( 'VcBA' )
end

function p.viafLink( id, label )
	--P214's format regex: [1-9]\d(\d{0,7}|\d{17,20}) (e.g. 123456789, 1234567890123456789012)
	if not id:match( '^[1-9]%d%d?%d?%d?%d?%d?%d?%d?$' ) and
	   not id:match( '^[1-9]%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d?%d?%d?$' ) then
		return false
	end
	-- If the "VIAF" entry at [[:m:Interwiki map]] would resolve to "https://viaf.org/viaf/$1" (rather than "http://viaf.org/viaf/$1", as it currently still does),
	-- then the code below could change from '[https://viaf.org/viaf/'..id..' '..id..']' to '[[:VIAF:'..id..'|'..id..']]'.
	return '[https://viaf.org/viaf/'..id..' '..(label or 'VIAF')..']'..p.getCatForId( 'VIAF' )
end

--[[=========================== Helper functions =============================]]

function p.append(str, c, length)
	while str:len() < length do
		str = c..str
	end
	return str
end

--Returns the ISNI check digit isni must be a string where the 15 first elements are digits, e.g. 0000000066534145
function p.getIsniCheckDigit( isni )
	local total = 0
	for i = 1, 15 do
		local digit = isni:byte( i ) - 48 --Get integer value
		total = (total + digit) * 2
	end
	local remainder = total % 11
	local result = (12 - remainder) % 11
	if result == 10 then
		return 'X'
	end
	return tostring( result )
end

--Validate ISNI (and ORCID) and retuns it as a 16 characters string or returns false if it's invalid
--See http://support.orcid.org/knowledgebase/articles/116780-structure-of-the-orcid-identifier
function p.validateIsni( id )
	--P213 (ISNI) format regex: [0-9]{4} [0-9]{4} [0-9]{4} [0-9]{3}[0-9X] (e.g. 0000-0000-6653-4145)
	--P496 (ORCID) format regex: 0000-000(1-[5-9]|2-[0-9]|3-[0-4])\d{3}-\d{3}[\dX] (e.g. 0000-0002-7398-5483)
	id = id:gsub( '[ %-]', '' ):upper()
	if not id:match( '^%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d[%dX]$' ) then
		return false
	end
	if p.getIsniCheckDigit( id ) ~= string.char( id:byte( 16 ) ) then
		return false
	end
	return id
end

function p.splitLccn( id )
	--P244's format regex: (n|nb|nr|no|ns|sh)([4-9][0-9]|00|20[0-1][0-9])[0-9]{6} (e.g. n78039510)
	if id:match( '^%l%l?%l?%d%d%d%d%d%d%d%d%d?%d?$' ) then
		id = id:gsub( '^(%l+)(%d+)(%d%d%d%d%d%d)$', '%1/%2/%3' )
	end
	if id:match( '^%l%l?%l?/%d%d%d?%d?/%d+$' ) then
		return mw.text.split( id, '/' )
	end
	return false
end

--[[==========================================================================]]
--[[                    Wikidata & documentation functions                    ]]
--[[==========================================================================]]

function p.getIdsFromWikidata( itemId, property )
	local ids = {}
	local statements = mw.wikibase.getBestStatements( itemId, property )
	if statements then
		for _, statement in ipairs( statements ) do
			if statement.mainsnak.datavalue then
				table.insert( ids, statement.mainsnak.datavalue.value )
			end
		end
	end
	return ids
end

-- Creates a human-readable standalone wikitable version of p.conf, and tracking categories with page counts, for use in the documentation
function p.docConfTable( frame )
	local wikiTable = '{| class="wikitable sortable"\n'..
					  '! rowspan=2 | Parameter\n'..
					  '! rowspan=2 | Section\n'..
					  '! rowspan=2 | Appears as\n'..
					  '! rowspan=2; data-sort-type=number | Wikidata property\n'..
					  '! colspan=4 | Tracking categories and page counts\n'..
					  '|-\n'..
					  '! [[:Category:Articles with authority control information|'..           'Articles]]\n'..
					  '! [[:Category:User pages with authority control information|'..         'User pages]]\n'..
					  '! [[:Category:Miscellaneous pages with authority control information|'..'Misc. pages]]\n'..
					  '! [[:Category:Articles with faulty authority control information|'..    'Faulty IDs]]\n'..
					  '|-\n'
	local lang = mw.getContentLanguage()
	local a, u, m, f, P = 0, 0, 0, 0, 0 --cumulative sums
	for _, conf in pairs( p.conf ) do
		local param, pid, section = conf[1], conf[2], conf[4]
		local appearsAs
		if param == 'WORLDCATID' then
			-- WorldCat is special
			appearsAs = '[https://www.worldcat.org/identities/lccn-n78039510 WorldCat]'
		elseif conf.prefix then
			appearsAs = conf.prefix
		else
			appearsAs = conf[3](conf[5])
		end
		local link = conf.link or param..' (identifier)'
		local category = conf.category or param
		local args = { id = 'f', pid }
		local wpl = frame:expandTemplate{ title = 'Wikidata property link', args = args }
		--cats
		local articleCat = 'Articles with '..category..' identifiers'
		local userCat =    'User pages with '..category..' identifiers'
		local miscCat =    'Miscellaneous pages with '..category..' identifiers'
		local faultyCat =  'Articles with faulty '..category..' identifiers'
		--counts
		local articleCount = lang:formatNum( mw.site.stats.pagesInCategory(articleCat, 'pages') )
		local userCount =    lang:formatNum( mw.site.stats.pagesInCategory(userCat, 'pages') )
		local miscCount =    lang:formatNum( mw.site.stats.pagesInCategory(miscCat, 'pages') )
		local faultyCount =  lang:formatNum( mw.site.stats.pagesInCategory(faultyCat, 'pages') )
		--calcs
		P = P + 1 --property count
		a = a + lang:parseFormattedNumber(articleCount)
		u = u + lang:parseFormattedNumber(userCount)
		m = m + lang:parseFormattedNumber(miscCount)
		f = f + lang:parseFormattedNumber(faultyCount)
		--concat
		wikiTable = wikiTable..'\n'..
					'|-\n'..
					'||[['..link..'|'..param..']]'..
					'||'..section..
					'||'..appearsAs..
					'||data-sort-value='..pid..'|'..wpl..
					'||style="text-align: right;"|[[:Category:'..articleCat..'|'..articleCount..']]'..
					'||style="text-align: right;"|[[:Category:'..   userCat..'|'..   userCount..']]'..
					'||style="text-align: right;"|[[:Category:'..   miscCat..'|'..   miscCount..']]'..
					'||style="text-align: right;"|[[:Category:'.. faultyCat..'|'.. faultyCount..']]'
	end
	
	--append derivative WorldCat cats
	local wcd = { 'WorldCat-LCCN', 'WorldCat-VIAF' }
	for _, w in pairs(wcd) do
		local articleCat = 'Articles with '..w..' identifiers'
		local articleCount = lang:formatNum( mw.site.stats.pagesInCategory(articleCat, 'pages') )
		local appearsAs 
		if w == 'WorldCat-LCCN' then
			appearsAs = '[https://www.worldcat.org/identities/lccn-n79-113947 WorldCat (via Library of Congress)]'
		else
			appearsAs = '[https://www.worldcat.org/identities/containsVIAFID/12345789 WorldCat (via VIAF)]'
		end
		a = a + lang:parseFormattedNumber(articleCount)
		wikiTable = wikiTable..'\n'..
					'|-\n'..
					'||'..'—'..
					'||সাধাৰণ'..
					'||'..appearsAs..
					'||data-sort-value='..w..'|'..'—'..
					'||style="text-align: right;"|[[:Category:'..articleCat..'|'..articleCount..']]'..
					'||style="text-align: right;"|—'..
					'||style="text-align: right;"|—'..
					'||style="text-align: right;"|—'
	end
	
	--append sums
	wikiTable = wikiTable..'\n'..
				'|-\n'..
				'! style="text-align: right;" colspan=3|Totals'..
				'||style="text-align: right;"|'..lang:formatNum(P)..
				'||style="text-align: right;"|'..lang:formatNum(a)..
				'||style="text-align: right;"|'..lang:formatNum(u)..
				'||style="text-align: right;"|'..lang:formatNum(m)..
				'||style="text-align: right;"|'..lang:formatNum(f)
	
	return require('Module:Suppress categories').main(wikiTable)..'\n|}'
end

--[[==========================================================================]]
--[[                              Configuration                               ]]
--[[==========================================================================]]

-- Please use "<parameter> (identifier)" redirects rather than linking directly to the target page.
-- This reduces clutter in "What links here" on both the redirect and the target,
-- and improves reverse lookup of articles where a manifestation of each identifier is used.

-- p.conf table basic format: { 'parameter name', propertyId # in Wikidata, formatting/validation function, section, example ID for documentation }
-- p.conf table optional named parameters: 
--  link: to override the link in the documentation (defaults to "<parameter> (identifer)")
--  category: to override the ID in category names (defaults to "... with <parameter> identifiers")
--  prefix: to include a prefix (usually a wikilink explaining what the identifier is) before the external link itself
p.conf = {
	{ 'AAG', 3372, p.aagLink, 'আৰ্ট গেলেৰী আৰু সংগ্ৰহালয়', '1' },
	{ 'ACM-DL', 864, p.acmLink, 'বৈজ্ঞানিক ডাটাবেচ', '12345678901', link = 'ACM DL (identifier)' },
	{ 'ADB', 1907, p.adbLink,'জীৱনীমূলক অভিধান', 'barton-sir-edmund-toby-71' },
	{ 'AGSA', 6804, p.agsaLink, 'আৰ্ট গেলেৰী আৰু সংগ্ৰহালয়', '3625' },
	{ 'autores.uy', 2558, p.autoresuyLink, 'জীৱনীমূলক অভিধান', '12345' },
	{ 'AWR', 4186, p.awrLink, 'জীৱনীমূলক অভিধান', 'PR00768b' },
	{ 'BIBSYS', 1015, p.bibsysLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', '1234567890123' },
	{ 'Bildindex', 2092, p.bildLink, 'কলা গৱেষণা প্ৰতিষ্ঠান', '1' },
	{ 'BNC', 1890, p.bncLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', '123456789' },
	{ 'BNE', 950, p.bneLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', 'XX1234567' },
	{ 'BNF', 268, p.bnfLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', '123456789' },
	{ 'Botanist', 428, p.botanistLink , 'বৈজ্ঞানিক ডাটাবেচ', 'L.' },
	{ 'BPN', 651, p.bpnLink , 'জীৱনীমূলক অভিধান', '12345678' },
	{ 'CANTIC', 1273, p.canticLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', 'a12345678' },
	{ 'CINII', 271, p.ciniiLink, 'বৈজ্ঞানিক ডাটাবেচ', 'DA12345678', link = 'CiNii (identifier)' },
	{ 'CWGC', 1908, p.cwgcLink, 'অন্যান্য', '1234567' },
	{ 'DAAO', 1707, p.daaoLink, 'কলা গৱেষণা প্ৰতিষ্ঠান', 'rolf-harris' },
	{ 'DBLP', 2456, p.dblpLink, 'বৈজ্ঞানিক ডাটাবেচ', '123/123' },
	{ 'DIB',  6829, p.dibLink, 'জীৱনীমূলক অভিধান', 'a1234' },
	{ 'DSI', 2349, p.dsiLink, 'কলা গৱেষণা প্ৰতিষ্ঠান', '1538' },
	{ 'EMU', 4613, p.emuLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', '15409' },
	{ 'FAST', 2163, p.fastLink, 'অন্যান্য', '1' },
	{ 'FNZA', 6792, p.fnzaLink, 'কলা গৱেষণা প্ৰতিষ্ঠান', '12' },
	{ 'GND', 227, p.gndLink, 'সাধাৰণ', '4079154-3' },
	{ 'HDS', 902, p.hdsLink, 'অন্যান্য', '050123' },
	{ 'IAAF', 1146, p.iaafLink, 'অন্যান্য', '123' },
	{ 'ICCU', 396, p.iccuLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', 'IT\\ICCU\\CFIV\\000163' }, --formerly SBN
	{ 'ICIA', 1736, p.iciaLink, 'কলা গৱেষণা প্ৰতিষ্ঠান', '1' },
	{ 'IEU', 9070, p.ieuLink, 'অন্যান্য', 'N\\A\\NationalAcademyofArtandArchitecture' },
	{ 'ISNI', 213, p.isniLink, 'সাধাৰণ', '0000-0000-6653-4145', prefix = '[[:en:ISNI (identifier)|ISNI]]' },
	{ 'Joconde', 347, p.jocondeLink, 'কলা গৱেষণা প্ৰতিষ্ঠান', '12345678901' },
	{ 'KULTURNAV', 1248, p.kulturnavLink, 'কলা গৱেষণা প্ৰতিষ্ঠান', '12345678-1234-1234-1234-1234567890AB', link = 'KulturNav (identifier)' },
	{ 'LCCN', 244, p.lccnLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', 'n78039510' },
	{ 'LIR', 886, p.lirLink, 'অন্যান্য', '1' },
	{ 'LNB', 1368, p.lnbLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', '123456789' },
	{ 'Léonore', 640, p.leonoreLink, 'অন্যান্য', 'LH//1/1', prefix = '[[:en:Léonore (identifier)|Léonore (France)]]' },
	{ 'MA', 6366, p.maLink, 'অন্যান্য', '123456789' },
	{ 'MBA', 434, p.mbaLink, 'অন্যান্য', '12345678-1234-1234-1234-1234567890AB', category = 'MusicBrainz' }, --special cat name
	{ 'MBAREA', 982, p.mbareaLink, 'অন্যান্য', '12345678-1234-1234-1234-1234567890AB', category = 'MusicBrainz area' }, --special cat name
	{ 'MBI', 1330, p.mbiLink, 'অন্যান্য', '12345678-1234-1234-1234-1234567890AB', category = 'MusicBrainz instrument' }, --special cat name
	{ 'MBL', 966, p.mblLink, 'অন্যান্য', '12345678-1234-1234-1234-1234567890AB', category = 'MusicBrainz label' }, --special cat name
	{ 'MBP', 1004, p.mbpLink, 'অন্যান্য', '12345678-1234-1234-1234-1234567890AB', category = 'MusicBrainz place' }, --special cat name
	{ 'MBRG', 436, p.mbrgLink, 'অন্যান্য', '12345678-1234-1234-1234-1234567890AB', category = 'MusicBrainz release group' }, --special cat name
	{ 'MBS', 1407, p.mbsLink, 'অন্যান্য', '12345678-1234-1234-1234-1234567890AB', category = 'MusicBrainz series' }, --special cat name
	{ 'MBW',  435, p.mbwLink, 'অন্যান্য', '12345678-1234-1234-1234-1234567890AB', category = 'MusicBrainz work' }, --special cat name
	{ 'MGP', 549, p.mgpLink, 'বৈজ্ঞানিক ডাটাবেচ', '123456' },
	{ 'NARA', 1225, p.naraLink, 'অন্যান্য', '12345678' },
	{ 'NCL', 1048, p.nclLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', '1081436' },
	{ 'NDL', 349, p.ndlLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', '012345678' },
	{ 'NGV', 2041, p.ngvLink, 'আৰ্ট গেলেৰী আৰু সংগ্ৰহালয়', '12354' },
	{ 'NKC', 691, p.nkcLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', 'abcd12345678901234' },
	{ 'NLA', 409, p.nlaLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', '123456789012' },
	{ 'NLG', 3348, p.nlgLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', '12345678' },
	{ 'NLI', 949, p.nliLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', '123456789' },
	{ 'NLK', 5034, p.nlkLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', 'KAB197000000' },
	{ 'NLP', 1695, p.nlpLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', '9810123456789012345' },
	{ 'NLR', 1003, p.nlrLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', '123456789' },
	{ 'NSK', 1375, p.nskLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', '123456789' },
	{ 'NTA', 1006, p.ntaLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', '12345678X' },
	{ 'ORCID', 496, p.orcidLink, 'সাধাৰণ', '0000-0002-7398-5483', prefix = '[[:en:ORCID (identifier)|ORCID]]' },
	{ 'PIC', 2750, p.picLink, 'কলা গৱেষণা প্ৰতিষ্ঠান', '1' },
	{ 'PLWABN',  7293, p.plwabnLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', '9812345678905606' },
	{ 'Publons', 3829, p.publonsLink, 'বৈজ্ঞানিক ডাটাবেচ', '2776255' },
	{ 'RID', 1053, p.ridLink, 'বৈজ্ঞানিক ডাটাবেচ', 'A-1234-1934' },
	{ 'RISM', 5504, p.rismLink, 'অন্যান্য', 'pe1',  prefix = '[[:en:RISM (identifier)|RISM (France)]]' },
	{ 'RERO', 3065, p.reroLink, 'অন্যান্য', '02-A012345678', prefix = '[[:en:RERO (identifier)|RERO (Switzerland)]]' },
	{ 'RKDartists', 650, p.rkdartistsLink, 'কলা গৱেষণা প্ৰতিষ্ঠান', '123456' },
	{ 'RKDID', 350, p.rkdidLink, 'কলা গৱেষণা প্ৰতিষ্ঠান', '123456' },
	{ 'RSL', 947, p.rslLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', '123456789' },
	{ 'SELIBR', 906, p.selibrLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', '123456' },
	{ 'SIKART', 781, p.sikartLink, 'কলা গৱেষণা প্ৰতিষ্ঠান', '123456789' },
	{ 'SNAC-ID', 3430, p.snacLink, 'অন্যান্য', 'A' },
	{ 'SUDOC', 269, p.sudocLink, 'অন্যান্য', '026927608', prefix = '[[:en:SUDOC (identifier)|SUDOC (France)]]' },
	{ 'S2AuthorId', 4012, p.s2authoridLink, 'বৈজ্ঞানিক ডাটাবেচ', '1796130', category = 'Semantic Scholar author' }, --special cat name
	{ 'TA98', 1323, p.ta98Link, 'বৈজ্ঞানিক ডাটাবেচ', 'A12.3.45.678' },
	{ 'TDVİA', 7314, p.tdviaLink, 'অন্যান্য', 'asim-b-behdele' },
	{ 'TePapa', 3544, p.tepapaLink, 'আৰ্ট গেলেৰী আৰু সংগ্ৰহালয়', '1' },
	{ 'TLS',  1362, p.tlsLink, 'অন্যান্য', 'Abcd' },
	{ 'Trove', 1315, p.troveLink, 'অন্যান্য', '12345678', prefix = '[[:en:Trove (identifier)|Trove (Australia)]]' }, --formerly NLA-person
	{ 'UKPARL', 6213, p.ukparlLink, 'অন্যান্য', 'AQUupyiR' },
	{ 'ULAN', 245, p.ulanLink, 'কলা গৱেষণা প্ৰতিষ্ঠান', '500123456' },
	{ 'USCongress', 1157, p.uscongressLink, 'অন্যান্য', 'A000123', link = 'US Congress (identifier)' },
	{ 'VcBA', 8034, p.vcbaLink, 'ৰাষ্ট্ৰীয় পুথিভঁৰাল', '494/9793' },
	{ 'VIAF', 214, p.viafLink, 'সাধাৰণ', '123456789', prefix = '[[:en:VIAF (identifier)|VIAF]]' },
	{ 'WORLDCATID', 7859, nil, 'সাধাৰণ', nil, link = 'WorldCat Identities (identifier)' },
}

-- Legitimate aliases to p.conf, for convenience
-- Format: { 'alias', 'parameter name in p.conf' }
p.aliases = {
	{ 'DNB', 'GND' }, --Deutsche Nationalbibliothek -> Gemeinsame Normdatei
	{ 'Leonore', 'Léonore' }, --alias name without diacritics
	{ 'leonore', 'Léonore' }, --lowercase variant without diacritics
	{ 'MusicBrainz', 'MBA' },
	{ 'MusicBrainz artist', 'MBA' },
	{ 'MusicBrainz label', 'MBL' },
	{ 'MusicBrainz release group', 'MBRG' },
	{ 'MusicBrainz work', 'MBW' },
	{ 'SBN', 'ICCU' }, --SBN alias to be deprecated at a later stage
	{ 'TDVIA', 'TDVİA' }, --alias name without diacritics
	{ 'tdvia', 'TDVİA' }, --lowercase variant without diacritics
}

-- Deprecated aliases to p.conf; tracked in [[Category:Articles with deprecated authority control identifiers]]
-- Format: { 'deprecated parameter name', 'replacement parameter name in p.conf' }
p.deprecated = {
	{ 'GKD', 'GND' },
	{ 'PND', 'GND' },
	{ 'RLS', 'RSL' },
	{ 'SWD', 'GND' },
	{ 'NARA-organization', 'NARA' },
	{ 'NARA-person', 'NARA' },
}

--[[==========================================================================]]
--[[                                   Main                                   ]]
--[[==========================================================================]]

function p.authorityControl( frame )
	local resolveEntity = require( 'Module:ResolveEntityId' )
	local parentArgs = frame:getParent().args --WD IDs added here later
	local iParentArgs = 0 --count original/manual parent args only later
	local worldcatCat = ''
	local elementsCat = ''
	local multipleIdCat = ''
	local suppressedIdCat = ''
	local suppressedIdCatArts = ''
	local deprecatedIdCat = ''
	local differentOnWDCat = ''
	local sameOnWDCat = ''
	local stateCat = ''
	
	--redirect aliases to proper parameter names
	for _, a in pairs( p.aliases ) do
		local alias, param = a[1], a[2]
		if (parentArgs[param] == nil or parentArgs[param] == '') and parentArgs[alias] then
			parentArgs[param] = parentArgs[alias]
		end
	end
	
	--redirect deprecated parameters to proper parameter names, and assign tracking cat
	for _, d in pairs( p.deprecated ) do
		local dep, param = d[1], d[2]
		if (parentArgs[param] == nil or parentArgs[param] == '') and parentArgs[dep] then
			parentArgs[param] = parentArgs[dep]
			if namespace == 0 then
				deprecatedIdCat = '[[Category:Articles with deprecated authority control identifiers|'..dep..']]'
			end
		end
	end
	
	--use QID= parameter for testing/example purposes only
	local itemId = nil
	if namespace ~= 0 then
		local qid = parentArgs['qid'] or parentArgs['QID']
		if qid then
			itemId = 'Q'..mw.ustring.gsub(qid, '^[Qq]', '')
			itemId = resolveEntity._id(itemId) --nil if unresolvable
		end
	else
		itemId = mw.wikibase.getEntityIdForCurrentPage()
	end
	
	--Wikidata fallback if available
	if itemId then
		local suppressedIdCount = 0
		local iMatches = 0
		for _, params in ipairs( p.conf ) do
			if params[2] > 0 then
				local val = parentArgs[mw.ustring.lower(params[1])] or parentArgs[params[1]]
				if val == nil or val == '' then
					local wikidataIds = p.getIdsFromWikidata( itemId, 'P'..params[2] )
					if wikidataIds[1] then
						if val == '' and (namespace == 0 or testcases) then
							suppressedIdCount = suppressedIdCount + 1
							suppressedIdCat = '[[Category:Articles with suppressed authority control identifiers|'..params[1]..']]'
						else
							parentArgs[params[1]] = wikidataIds[1] --add ID from WD
						end
					end
				else
					iParentArgs = iParentArgs + 1
					local wikidataIds = p.getIdsFromWikidata( itemId, 'P'..params[2] )
					if wikidataIds[1] and differentOnWDCat == '' then
						local bMatch = false
						for _, wd in pairs( wikidataIds ) do
							if val == wd then
								iMatches = iMatches + 1
								bMatch = true
							end
						end
						if bMatch == false then
							differentOnWDCat = '[[Category:Pages using authority control with parameters different on Wikidata|'..params[1]..']]'
		end	end	end	end	end
		if iMatches > 0 and iMatches == iParentArgs then
			sameOnWDCat = '[[Category:Pages using authority control with parameters all matching Wikidata]]'
		end
		if parentArgs['arts'] == 'arts' and suppressedIdCount > 0 then
			if namespace == 0 or testcases then
				local s = 's'
				if suppressedIdCount == 1 then s = '' end
				local sCat = 'ACArt with '..suppressedIdCount..' suppressed element'..s
				suppressedIdCatArts  = '[[Category:'..sCat..']]'..p.redCatLink(sCat)
			end
		end
	end
	
	--configure rows
	local rct = 0
	local sectionOrder = {'সাধাৰণ','ৰাষ্ট্ৰীয় পুথিভঁৰাল','আৰ্ট গেলেৰী আৰু সংগ্ৰহালয়',
						  'কলা গৱেষণা প্ৰতিষ্ঠান','জীৱনীমূলক অভিধান','বৈজ্ঞানিক ডাটাবেচ',
						  'অন্যান্য'}
	local sections = {
		['সাধাৰণ'] = {},
		['ৰাষ্ট্ৰীয় পুথিভঁৰাল'] = {},
		['আৰ্ট গেলেৰী আৰু সংগ্ৰহালয়'] = {},
		['কলা গৱেষণা প্ৰতিষ্ঠান'] = {},
		['জীৱনীমূলক অভিধান'] = {},
		['বৈজ্ঞানিক ডাটাবেচ'] = {},
		['অন্যান্য'] = {}
	}
	--don't show NLP if PLWABN is present, since they both go to the National Library of Poland
	--and the library has deprecated NLP IDs in favor of PLWABN IDs
	if parentArgs.PLWABN or parentArgs.plwabn then
		parentArgs.NLP = ''
		parentArgs.nlp = ''
	end
	for _, params in ipairs( p.conf ) do
		local val = parentArgs[mw.ustring.lower(params[1])] or parentArgs[params[1]]
		local tval, tlinks = {}, {} --init tables
		if val and val ~= '' and type(params[3]) == 'function' then
			table.insert( tval, val )
			if params.prefix then 
				table.insert( tlinks, params[3]( val, '1' ) )
			else
				table.insert( tlinks, params[3]( val ) )
			end
		end
		--collect other unique vals (IDs) from WD, if present
		if itemId and tval[1] then
			local nextIdVal = 2
			local wikidataIds = p.getIdsFromWikidata( itemId, 'P'..params[2] )
			for _, v in pairs( wikidataIds ) do
				local bnew = true
				for _, w in pairs( tval ) do
					if v == w then bnew = false end
				end
				if bnew then
					table.insert( tval, v )
					table.insert( tlinks, params[3]( v, tostring(nextIdVal) ) )
					nextIdVal = nextIdVal + 1
				end
			end
		end
		--assemble
		if tval[1] then
			table.insert( sections[params[4]], p.createRow( params[1], tval, nil, tlinks, true, params.category, params.prefix) )
			rct = rct + 1
			if tval[2] then
				multipleIdCat = p.getCatForId( 'multiple' )
			end
		end
	
	end
	
	--WorldCat
	local worldcatId = parentArgs['worldcatid'] or parentArgs['WORLDCATID']
	if worldcatId and worldcatId ~= '' then --if WORLDCATID present & unsuppressed
		table.insert( sections['সাধাৰণ'], p.createRow( 'WORLDCATID', worldcatId, '[https://www.worldcat.org/identities/'..mw.uri.encode(worldcatId, 'PATH')..' WorldCat]', nil, false ) ) --Validation?
		worldcatCat = p.getCatForId( 'WORLDCATID' )
		rct = rct + 1
	elseif worldcatId == nil then --if WORLDCATID absent but unsuppressed
		local viafId = parentArgs['viaf'] or parentArgs['VIAF']
		local lccnId = parentArgs['lccn'] or parentArgs['LCCN']
		if viafId and viafId ~= '' and p.viafLink( viafId ) then --VIAF must be present, unsuppressed, & validated
			table.insert( sections['সাধাৰণ'], p.createRow( 'VIAF', viafId, '[https://www.worldcat.org/identities/containsVIAFID/'..viafId..' WorldCat (via VIAF)]', nil, false ) )
			if namespace == 0 then 
				worldcatCat = '[[Category:Articles with WorldCat-VIAF identifiers]]'
			end
			rct = rct + 1
		elseif lccnId and lccnId ~= '' and p.lccnLink( lccnId ) then --LCCN must be present, unsuppressed, & validated
			local lccnParts = p.splitLccn( lccnId )
			if lccnParts and lccnParts[1] ~= 'sh' then
				local lccnIdFmtd = lccnParts[1]..lccnParts[2]..'-'..lccnParts[3]
				table.insert( sections['সাধাৰণ'], p.createRow( 'LCCN', lccnId, '[https://www.worldcat.org/identities/lccn-'..lccnIdFmtd..' WorldCat (via Library of Congress)]', nil, false ) )
				if namespace == 0 then
					worldcatCat = '[[Category:Articles with WorldCat-LCCN identifiers]]'
				end
			end
			rct = rct + 1
		end
	elseif worldcatId == '' then --if WORLDCATID suppressed
		suppressedIdCat = '[[Category:Articles with suppressed authority control identifiers|WORLDCATID]]'
	end
	
	--configure Navbox
	local outString = ''
	if rct > 0 then
		local Navbox = require('Module:Navbox')
		local sectionID = 1
		local args = { pid = 'identifiers' } -- #target the list of identifiers
		if testcases and itemId then args = { pid = 'identifiers', qid = itemId } end --expensive
		local pencil = frame:expandTemplate{ title = 'EditAtWikidata', args = args}
		local navboxArgs = {
			name  = 'কৰ্তৃপক্ষ নিয়ন্ত্ৰণ',
			navboxclass = 'authority-control',
			bodyclass = 'hlist',
			state = parentArgs.state or 'autocollapse',
			navbar = 'off'
		}
		for _, sectName in ipairs(sectionOrder) do
			if #sections[sectName] ~= 0 then
				navboxArgs['group'..sectionID] = sectName
				navboxArgs['list'..sectionID] = table.concat(sections[sectName])
				sectionID = sectionID + 1
			end
		end
		if navboxArgs.group2 then
			navboxArgs.title = '[[:en:Help:Authority control|কৰ্তৃপক্ষ নিয়ন্ত্ৰণ]]'..pencil
		else
			local sect = navboxArgs.group1
			if sect == 'সাধাৰণ' or sect == 'অন্যান্য' then
				-- Just say "Authority control" with no label if only সাধাৰণ or only অন্যান্য IDs are present
				-- since "সাধাৰণ" is redundant and "অন্যান্য" is silly when there's nothing to contrast it with
				navboxArgs.group1 = '[[:en:Help:Authority control|কৰ্তৃপক্ষ নিয়ন্ত্ৰণ]]'..pencil
			else 
				navboxArgs.group1 = '[[:en:Help:Authority control|কৰ্তৃপক্ষ নিয়ন্ত্ৰণ: '..sect..']] '..pencil
			end
		end
		outString = Navbox._navbox(navboxArgs)
	end
	
	--auxCats
	if rct == 0 or rct >= 25 then
		if namespace == 0 or testcases then
			local eCat = 'AC with '..rct..' elements'
			elementsCat  = '[[Category:'..eCat..']]'..p.redCatLink(eCat)
		end
	end
	if parentArgs.state then
		if namespace == 0 or testcases then
			local sCat
			if parentArgs.state == 'collapsed' then sCat = 'AC using state parameter: collapsed'
			elseif parentArgs.state == 'expanded' then sCat = 'AC using state parameter: expanded'
			elseif parentArgs.state == 'autocollapse' then sCat = 'AC using state parameter: autocollapse'
			else sCat = 'AC using state parameter: অন্যান্য'
			end
			stateCat  = '[[Category:'..sCat..']]'..p.redCatLink(sCat)
		end
	end
	local auxCats = worldcatCat..elementsCat..multipleIdCat..suppressedIdCat..suppressedIdCatArts..
					deprecatedIdCat..differentOnWDCat..sameOnWDCat..stateCat
	if testcases then
		auxCats = mw.ustring.gsub(auxCats, '(%[%[)(Category)', '%1:%2') --for easier checking
	end
	
	--out
	outString = outString..auxCats
	if namespace ~= 0 then
		outString = mw.ustring.gsub(outString, '(%[%[)(Category:Articles)', '%1:%2') --by definition
	end
	
	return outString
end

return p