모듈:Authority control

위키백과, 우리 모두의 백과사전.
모듈 설명문서[보기] [편집] [역사] [새로 고침]

이 모듈은 {{전거 통제}} 틀의 루아 코드를 담고 있습니다. 해당 틀의 설명문서를 참고하세요.

변수, 위키데이터 속성, 추적용 분류

변수문단표시위키데이터 속성추적용 분류와 문서 수
문서잘못된 ID
AAG미술관오클랜드Auckland Art Gallery artist ID (P3372)1700
ACM-DL학술 데이터베이스ACMACM 전자도서관 저자 식별자 (P864)1450
ADB인명 사전오스트레일리아Australian Dictionary of Biography ID (P1907)940
admiralty등대 식별자AdmiraltyAdmiralty number (P3562)120
AGSA미술관사우스오스트레일리아주Art Gallery of South Australia creator ID (P6804)1680
ARLHS등대 식별자ARLHSARLHS lighthouse ID (P2980)80
autores.uy인명 사전우루과이autores.uy ID (P2558)190
AWR인명 사전Australian Women's RegisterAustralian Women's Register ID (P4186)550
BIBSYS국립도서관노르웨이BIBSYS ID (P1015)13,7790
Bildindex미술 연구소Bildindex (독일)Bildindex der Kunst und Architektur ID (P2092)20
BNC국립도서관칠레CCAB ID (P1890)7450
BNE국립도서관스페인스페인 국립도서관 ID (P950)22,8710
BNF국립도서관프랑스 (데이터)프랑스 국립도서관 ID (P268)47,8940
BNMM국립도서관아르헨티나BNMM authority ID (P3788)1,0840
Botanist학술 데이터베이스국제 식물명 색인식물학자 약자 (P428)1430
BPN인명 사전네덜란드Biografisch Portaal van Nederland ID (P651)4770
CANTIC국립도서관카탈루냐카탈루냐 국립도서관 ID (P1273)720
CANTICN국립도서관카탈로니아CANTIC ID (P9984)8,2050
CCG등대 식별자CCGCanadian Coastguard Lighthouse ID (P3920)00
CINII학술 데이터베이스CiNii (일본)CiNii 저자 식별자 (P271)9,4060
CWGC기타연합군인묘지위원회CWGC 인물 ID (P1908)200
DAAO미술 연구소Australian ArtistsDAAO ID (P1707)261
DBLP학술 데이터베이스DBLP (컴퓨터 과학)DBLP ID (P2456)4670
DIB인명 사전아일랜드Dictionary of Irish Biography ID (P6829)2490
DSI미술 연구소Scientific illustratorsStuttgart Database of Scientific Illustrators ID (P2349)1630
DTBIO인명 사전독일Deutsche Biographie (GND) ID (P7902)17,2040
EMU국립도서관우크라이나Encyclopedia of Modern Ukraine ID (P4613)1,4560
FAST기타Faceted Application of Subject Terminology패스트 아이디 (P2163)30,2170
FNZA미술 연구소뉴질랜드 아티스트Find NZ Artists ID (P6792)140
GND국립도서관독일GND 식별자 (P227)69,8880
Google Scholar학술 데이터베이스구글 학술 검색구글 학술검색 저자 ID (P1960)2780
HDS기타스위스 역사 사전HDS ID (P902)2,3790
IAAF기타월드 애슬레틱스국제육상경기연맹 ID (P1146)8170
ICCU국립도서관이탈리아이탈리아 국가도서관서비스 ID (P396)5,3760
ICIA미술 연구소ICIA (이스라엘)Information Center for Israeli Art artist ID (P1736)80
IEU기타우크라이나 인터넷 백과사전Internet Encyclopedia of Ukraine ID (P9070)2850
ISNI일반ISNIISNI (P213)57,2780
J9U국립도서관이스라엘이스라엘 국립도서관 J9U ID (P8189)54,9060
Joconde미술 연구소Joconde (프랑스)Joconde (P347)230
KULTURNAV미술 연구소KulturNav (노르웨이)KulturNav-ID (P1248)5200
LCCN국립도서관미국미국 의회도서관 전거 ID (P244)88,5610
LIR기타Lexicon Istoric Retic (스위스)LIR (P886)540
LNB국립도서관라트비아라트비아 국립도서관 ID (P1368)6,8850
Marina Militare등대 식별자이탈리아Italian Navy Lighthouses and Beacons ID (P3863)00
MarineTraffic등대 식별자MarineTrafficMarineTraffic Lighthouse ID (P3601)60
MATHSN학술 데이터베이스MathSciNetMR 저자 ID (P4955)9090
MBA기타뮤직브레인즈 아티스트뮤직브레인즈 아티스트 ID (P434)22,4020
MBAREA기타뮤직브레인즈 지역뮤직브레인즈 지역 ID (P982)11,3120
MBI기타뮤직브레인즈 악기뮤직브레인즈 악기 ID (P1330)1530
MBL기타뮤직브레인즈 레이블뮤직브레인즈 레이블 ID (P966)7140
MBP기타뮤직브레인즈 장소뮤직브레인즈 장소 ID (P1004)1,1200
MBRG기타뮤직브레인즈 릴리스 그룹뮤직브레인즈 음반 목록 ID (P436)14,2570
MBS기타뮤직브레인즈 시리즈뮤직브레인즈 주제별 목록 ID (P1407)1160
MBW기타뮤직브레인즈 작품뮤직브레인즈 작품 ID (P435)3,0790
MGP학술 데이터베이스수학 계보 프로젝트수학 계보 프로젝트 ID (P549)1,4650
NARA기타국립문서기록관리청 (미국)미 국립문서기록관리청 식별자 (P1225)8,9610
NCL국립도서관타이완NCL 식별자 (P1048)1940
NDL국립도서관일본일본 국립국회도서관 ID (P349)26,6471
NGA등대 식별자NGANGA lighthouse ID (P3563)80
NGV미술관빅토리아빅토리아 국립미술관 예술가 ID (P2041)3540
NKC국립도서관체코체코 국립도서관 ID (P691)39,9180
NLA국립도서관오스트레일리아오스트레일리아 국립도서관 ID (P409)9,8970
NLG국립도서관그리스그리스 국립도서관 ID (P3348)4,6250
NLK국립도서관한국대한민국 국립중앙도서관 ID (P5034)16,31730
NLP국립도서관폴란드폴란드 국립도서관 식별자 (P1695)1260
NLR국립도서관루마니아루마니아 국립도서관 식별자 (P1003)1160
NSK국립도서관크로아티아자그레브 국립대학도서관 식별자 (P1375)4,2670
NTA국립도서관네덜란드네덜란드 국립도서관 저자 ID (P1006)23,7700
ORCID일반ORCIDORCID iD (P496)3790
PIC미술 연구소Photographers' Identities사진가의 식별자 카탈로그 ID (P2750)5490
PLWABN국립도서관폴란드PLWABN ID (P7293)20,8820
Publons학술 데이터베이스Publons (researchers)Publons author ID (P3829)360
RID학술 데이터베이스ResearcherIDResearcherID (P1053)450
RISM기타RISM (프랑스)RISM ID (P5504)1,8170
RERO기타RERO (스위스)RERO ID (P3065)7,2030
RKDartists미술 연구소RKD Artists (네덜란드)RKDartists ID (P650)1,8090
RKDID미술 연구소RKD ID (네덜란드)RKDimages (P350)190
RSL국립도서관러시아러시아 국립도서관 인물 ID (P947)3920
Scopus학술 데이터베이스Scopus authorScopus 저자 ID (P1153)5320
SELIBR국립도서관스웨덴스웨덴 도서관정보시스템 ID (P906)8,2261
SIKART미술 연구소SIKART (스위스)SIKART ID (P781)520
SNAC-ID기타Social Networks and Archival ContextSNAC ARK ID (P3430)15,9770
SUDOC기타SUDOC (프랑스)idRef 전거 식별자 (P269)32,9400
TA98학술 데이터베이스Terminologia AnatomicaTerminologia Anatomica 98 ID (P1323)5500
TDVİA기타이슬람 백과사전TDV İslam Ansiklopedisi ID (P7314)8550
TePapa미술관Te Papa (뉴질랜드)Te Papa agent ID (P3544)5120
TLS기타Theaterlexikon (스위스)Theaterlexikon der Schweiz ID (P1362)870
Trove기타Trove (오스트레일리아)NLA Trove people ID (P1315)10,9950
UKPARL기타영국 의회UK Parliament identifier (P6213)1260
ULAN미술 연구소Artist Names (Getty)ULAN ID (P245)3,5770
USCG등대 식별자USCG (6-0695)USCG lighthouse ID (P3723)00
USCongress기타미국 의회US Congress Bio ID (P1157)3730
VcBA국립도서관바티칸Vatican Library VcBA ID (P8034)5,6840
VIAF일반VIAFVIAF 식별자 (P214)102,4010
WORLDCATID일반WorldCatWorldCat ID ID (P7859)86,1540
ZBMATH학술 데이터베이스zbMATHzbMATH 저자 ID (P1556)1,6260
-일반월드캣 (미국 의회도서관을 통해)867
-일반월드캣 (VIAF를 통해)16,357
전체96954,17833

require('Module:No globals')

local p = {}
local title = mw.title.getCurrentTitle()
local namespace = title.namespace
local testcases = (string.sub(title.subpageText,1,3) == '시험장')

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

local function addCat( cat )
	if cat and cat ~= '' then return '[[분류:'..cat..']]'..p.redCatLink(cat) end
	return ''
end

function p.getCatForId( id )
	local cat = ''
	if namespace == 0 then
		cat = id..' 식별자를 포함한 위키백과 문서'
	end
	return addCat(cat)
end

function p.redCatLink( cat ) --cat == 'Blah' (not 'Category:Blah', not '[[Category:Blah]]')
	if cat and cat ~= '' and testcases == false and mw.title.new(cat, 14).exists == false then
		return '[[분류:깨진 전거 통제 분류를 포함한 문서]]'
	end
	return ''
end

function p.createRow( id, rawValues, link, links, withUid, specialCat, prefix)
	local faultyCat = '잘못된 '..(specialCat or id)..' 식별자를 포함한 위키백과 문서'
	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">'..id..' id '..rawValues[i]..' 값은 유효하지 않습니다.</span>'..addCat(faultyCat)
			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">'..id..' id '..rawValues..' 값은 유효하지 않습니다.</span>'..addCat(faultyCat)..'\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 '오클랜드')..']'..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 'ACM')..']'..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 '오스트레일리아')..']'..p.getCatForId( 'ADB' )
end

function p.admiraltyLink(id,label)
	--P3562's format regex: [A-Q]\d{4}(\.\d+)? (e.g. D1204.1)
	if not id:match('^[A-Q]%d%d%d%d$') and
	   not id:match('^[A-Q]%d%d%d%d%.%d+$') then
		return false
	end
	return id..p.getCatForId( 'admiralty' )
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 '사우스오스트레일리아주')..']'..p.getCatForId( 'AGSA' )
end

function p.ARLHSLink(id,label)
	--P2980's format regex: [A-Z]{3}\d{3,4}[A-Z]?| e.g. LAT023
	if not id:match('^[A-Z][A-Z][A-Z]%d%d%d%d?[A-Z]?$') then
		return false
	end
	return '[http://wlol.arlhs.com/lighthouse/'..id..'.html '..(label or 'ARLHS')..']'..p.getCatForId( 'ARLHS' )
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 '우루과이')..']'..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 '노르웨이')..']'..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 (독일)')..']'..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 '칠레')..']'..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 '스페인')..']'..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 '프랑스')..'] [https://data.bnf.fr/ark:/12148/'..id..' (데이터)]'..p.getCatForId( 'BNF' )
end

function p.bnmmLink( id, label )
	--P3788's format regex: \d{9} (e.g. 000024044)
	if id:match( '^%d%d%d%d%d%d%d%d%d$' ) then
		return '[https://catalogo.bn.gov.ar/F/?func=direct&local_base=BNA10&doc_number='..id..' '..(label or '아르헨티나')..']'..p.getCatForId( 'BNMM' )
	else
		return false
	end
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 '국제 식물명 색인')..']'..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 '네덜란드')..']'..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 '카탈루냐')..']'..p.getCatForId( 'CANTIC' ) --no https as of 10/2019
end

function p.canticnLink( id, label )
	--P9984's format regex: 981(0|1)\d{9}06706 (e.g. 981058515460906706)
	if not id:match( '^981[0-1]%d%d%d%d%d%d%d%d%d06706$' ) then
		return false
	end
	return '[https://cantic.bnc.cat/registre/'..id..' '..(label or '카탈로니아')..']'..p.getCatForId( 'CANTICN' )
end

function p.ccgLink( id, label )
	--P3920's format regex: ([NAIP])?[1-9]\d*(\.\d+)? (e.g. A1761)
	if not id:match( '^[NAIP]?[1-9]%d*$' ) and
	   not id:match( '^[NAIP]?[1-9]%d*%.%d+$' ) then
		return false
	end
	return id..p.getCatForId( 'CCG' )
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 (일본)')..']'..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 '연합군인묘지위원회')..']'..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 '우크라이나')..']'..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 (컴퓨터 과학)')..']'..p.getCatForId( 'DBLP' )
end

function p.dibLink( id, label )
	--P6829's format regex: 0[01]\d{4}(\.[A-D])? (e.g. 001953)
	if not id:match( '^0[01]%d%d%d%d%.?[A-D]?$' ) then
		return false
	end
	return '[https://dib.cambridge.org/viewReadPage.do?articleId='..id..' '..(label or '아일랜드')..']'..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.dtbioLink( id, label )
	--P7902's format regex: 1[0-9]{7,8}[0-9X] (e.g. 118554700)
	if not id:match( '^1[0-9]%d%d%d%d%d%d%d?[0-9X]$' ) then
		return false
	end
	return '[https://www.deutsche-biographie.de/pnd'..id..'.html?language=en '..(label or '독일')..']'..p.getCatForId( 'DTBIO' )
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 '뉴질랜드 아티스트')..']'..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 '독일')..']'..p.getCatForId( 'GND' )
end

function p.googleLink( id, label )
	--P1960's format regex: [-_0-9A-Za-z]{12} (e.g. CUO0vDcAAAAJ)
	if not id:match( '^[%-_%d%l%u][%-_%d%l%u][%-_%d%l%u][%-_%d%l%u][%-_%d%l%u][%-_%d%l%u][%-_%d%l%u][%-_%d%l%u][%-_%d%l%u][%-_%d%l%u][%-_%d%l%u][%-_%d%l%u]$' ) then
		return false
	end
	return '[https://scholar.google.com/citations?user='..id..' '..(label or '구글 학술 검색')..']'..p.getCatForId( 'Google Scholar' )
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 '스위스 역사 사전')..']'..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 '월드 애슬레틱스')..']'..p.getCatForId( 'IAAF' )
end

function p.iccuLink( id, label )
	--P396's format regex: \D{2}[A-Z0-3]V\d{6} (e.g. CFIV000163)
	if not id:match( '^%u%u[%u0-3]V%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/nome/'..id..' '..(label or '이탈리아')..']'..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 (이스라엘)')..']'..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 '우크라이나 인터넷 백과사전')..']'..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.j9uLink( id, label )
	--P8189's format regex: 9870(0|1)\d{8}05171 (e.g. 987007305652505171)
	if not id:match( '^9870[0-1]%d%d%d%d%d%d%d%d05171$' ) then
		return false
	end
	return '[http://uli.nli.org.il/F/?func=find-b&local_base=NLX10&find_code=UID&request='..id..' '..(label or '이스라엘')..']'..p.getCatForId( 'J9U' )
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 (프랑스)')..']'..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 (노르웨이)')..']'..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 '미국')..']'..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 (스위스)')..']'..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 '라트비아')..']'..p.getCatForId( 'LNB' )
end

function p.marinaMilitareLink( id, label )
	--P3863's format regex: [1-9]\d* (e.g. 3856)
	if id:match( '^[1-9]%d*$' ) then
		return '[http://www.marina.difesa.it/cosa-facciamo/per-la-difesa-sicurezza/fari/Pagine/'..id..'.aspx '..(label or '이탈리아')..']'..p.getCatForId( 'Marina Militare' )
	else
		return false
	end
end

function p.mathsnLink( id, label )
	--P4955's format regex: [1-9]\d{4,6} (e.g. 175270)
	if not id:match( '^[1-9]%d%d%d%d%d?%d?$' ) then
		return false
	end
	return '[https://mathscinet.ams.org/mathscinet/MRAuthorID/'..id..' '..(label or 'MathSciNet')..']'..p.getCatForId( 'MATHSN' )
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 '[[MBA (식별자)|뮤직브레인즈]] ['..url..' 아티스트]'..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 '[[MBAREA (식별자)|뮤직브레인즈]] ['..url..' 지역]'..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 '[[MBI (식별자)|뮤직브레인즈]] ['..url..' 악기]'..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 '[[MBL (식별자)|뮤직브레인즈]] ['..url..' 레이블]'..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 '[[MBP (식별자)|뮤직브레인즈]] ['..url..' 장소]'..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 '[[MBRG (식별자)|뮤직브레인즈]] ['..url..' 릴리스 그룹]'..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 '[[MBS (식별자)|뮤직브레인즈]] ['..url..' 시리즈]'..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 '[[MBW (식별자)|뮤직브레인즈]] ['..url..' 작품]'..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://www.mathgenealogy.org/id.php?id='..id..' '..(label or '수학 계보 프로젝트')..']'..p.getCatForId( 'MGP' )
end

function p.mtLink( id, label )
	--P3601's format regex: \d{10} (e.g. 1000004707)
	if id:match( '^%d%d%d%d%d%d%d%d%d%d$' ) then
		return '[https://www.marinetraffic.com/en/ais/details/lights/'..id..' '..(label or 'MarineTraffic')..']'..p.getCatForId( 'MarineTraffic' )
	else
		return false
	end
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 '국립문서기록관리청 (미국)')..']'..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 '타이완')..']'..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 '일본')..']'..p.getCatForId( 'NDL' )
end

function p.ngaLink(id,label)
	--P3563's format rgex: 11[0-6]-\d+(\.\d+)? (e.g. 114-7721.2)
	if not id:match('^11[0-6]%-%d+%.?%d*$') then
		return false
	end
	return '[https://wikidata-externalid-url.toolforge.org/?url=https%3A%2F%2Fmsi.nga.mil%2FqueryResults%3Fpublications%2Fngalol%2Flights-buoys%3Fvolume%3D%251%26featureNumber%3D%252%26includeRemovals%3Dfalse%26output%3Dhtml&exp=(%5Cd%7B3%7D)-(.*)&id='..id..' '..(label or 'NGA')..']'..p.getCatForId( 'NGA' )
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 '빅토리아')..']'..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 '체코')..']'..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 '오스트레일리아')..']'..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 '그리스')..']'..p.getCatForId( 'NLG' )
end

function p.nlkLink( id, label )
	--P5034's format regex: (KAB|KAC|KSH)([0-9]{4}|[0-9]{4}[a-zA-Z])[0-9]{4,6} (e.g. KAC201501465)
	if not id:match( '^KAB%d%d%d%d%a?%d%d%d%d%d?%d?$' ) and
		not id:match( '^KAC%d%d%d%d%a?%d%d%d%d%d?%d?$' ) and
		not id:match( '^KSH%d%d%d%d%a?%d%d%d%d%d?%d?$' ) then
		return false
	end
	return '[https://lod.nl.go.kr/resource/'..id..' '..(label or '한국')..']'..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 '폴란드')..']'..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 '루마니아')..']'..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 '크로아티아')..']'..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 '네덜란드')..']'..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 '폴란드')..']'..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 (프랑스)')..']'..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 (스위스)')..']'..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 (네덜란드)')..']'..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 (네덜란드)')..']'..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 '러시아')..']'..p.getCatForId( 'RSL' ) --no https as of 9/2019
end

function p.scopusLink( id, label )
	--P1153's format regex: [1-9]\d{9,10} (e.g. 35247902700)
	if not id:match( '^[1-9]%d%d%d%d%d%d%d%d%d%d?$' ) then
		return false
	end
	return '[https://www.scopus.com/authid/detail.uri?authorId='..id..' '..(label or 'Scopus author')..']'..p.getCatForId( 'Scopus' )
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 '스웨덴')..']'..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 (스위스)')..']'..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 (프랑스)')..']'..p.getCatForId( 'SUDOC' )
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: [0-9a-z/-]+] (e.g. barkan-omer-lutfi)
	if not id:match( '^[%d%l/-]+$' ) then
		return false
	end
	return '[https://islamansiklopedisi.org.tr/'..id..' '..(label or '이슬람 백과사전')..']'..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 (뉴질랜드)')..']'..p.getCatForId( 'TePapa' )
end

function p.tlsLink( id, label )
	id = id:gsub(' +', '_')
	--P1362's format regex: \p{Lu}[\p{L}\d_',\.\-\(\)\*\/–&]{3,89} (e.g. Abcd)
	--Mediawiki page title partial URL so consider validation with mw.title or "[^#<>%[%] {|}]"
	local class = "[%w_',%.%-%(%)%*%/–&]"
	local idlen = mw.ustring.len (id)
	if idlen < 4 or idlen > 90 then
		return false
	end
	local regex = '^%u'..string.rep(class, idlen - 1)..'$'
	if not mw.ustring.match( id, regex ) then
		return false
	end
	return '[http://tls.theaterwissenschaft.ch/wiki/'..id..' '..(label or 'Theaterlexikon (스위스)')..']'..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 (오스트레일리아)')..']'..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 '영국 의회')..']'..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.uscgLink( id, label )
	--P3723's format regex: [1-7]-\d{1,5}(.[1-9])? (e.g. 6-0695)
	if not id:match( '^[1-7]%-%d%d?%d?%d?%d?$' ) and
	   not id:match( '^[1-7]%-%d%d?%d?%d?%d?%.%d*[1-9]$' ) then
		return false
	end
	return '[[USCG (식별자)|USCG]] ([https://www.navcen.uscg.gov/pdf/lightlists/LightList%20V'..mw.ustring.sub(id,1,1)..'.pdf '..id..'])'..p.getCatForId( 'USCG' )
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 '미국 의회')..']'..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 '바티칸')..']'..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

function p.worldcatidLink( id, label )
	--P7859's format regex: viaf-\d+|lccn-n[a-z]?[0-9\-]+|n[cps]-.+ (e.g. viaf-100181709, lccn-n78-95332, np-verbeck,%20william$1861)
	if not id:match( '^viaf%-%d+$' ) and
	   not id:match( '^lccn%-n[a-z]?[0-9%-]+$' ) and
	   not id:match( '^n[cps]%-.+$' ) then
		return false
	end
	return '[https://www.worldcat.org/identities/'..mw.uri.encode(id, 'PATH')..'/ '..(label or 'WorldCat')..']'..p.getCatForId( 'WORLDCATID' )
end

function p.zbmathLink( id, label )
	--P1556's format regex: [a-z][a-z\-]*(\.[a-z][a-z\-]*)?(\.[0-9]*)? (e.g. turing.alan-m)
	local ps = {'%l[%l%-]*', '%.%l[%l%-]*', '%.%d*'}
	if not id:match( '^'..ps[1]..'$' ) and -- prefix with no capture options
	   not id:match( '^'..ps[1]..ps[2]..'$' ) and -- prefix with first capture option
	   not id:match( '^'..ps[1]..ps[3]..'$' ) and -- prefix with second capture option
	   not id:match( '^'..ps[1]..ps[2]..ps[3]..'$' ) then -- prefix and both capture options
		return false
	end
	return '[https://zbmath.org/authors/?q=ai:'..id..' '..(label or 'zbMATH')..']'..p.getCatForId( 'ZBMATH' )
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 = {}
	if not mw.wikibase then
		return ids
	end
	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

function p.checkcat( category,label )
	local ret='[[:Category:'..category..'|'..label..']]'
	if mw.title.new(category, 14).exists == false then
		ret = ret..' <span class="plainlinks" style="font-size:85%;">&#91;['..tostring(mw.uri.fullUrl('분류:'..category,'action=edit&preload=틀:전거 통제/preload'))..' 만들기]&#93;</span>'
	end
	return ret
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 = '<table class="wikitable sortable">'..
	  '<tr><th rowspan=2>변수</th>'..
	  '<th rowspan=2>문단</th>'..
	  '<th rowspan=2>표시</th>'..
	  '<th rowspan=2 data-sort-type=number>위키데이터 속성</th>'..
	  '<th colspan=2>추적용 분류와 문서 수</th></tr>'..
	  '<tr><th>[[:분류:전거 통제 정보를 포함한 위키백과 문서|문서]]</th>'..
	  '<th>[[:분류:잘못된 전거 통제 정보를 포함한 위키백과 문서|잘못된 ID]]</th></tr>'
	local lang = mw.getContentLanguage()
	local a, f, P = 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 conf.prefix then
			appearsAs = conf.prefix
		else
			appearsAs = conf[3](conf[5])
		end
		local link = conf.link or param..' (식별자)'
		local category = conf.category or param
		local args = { id = 'f', pid }
		local wpl = frame:expandTemplate{ title = '위키데이터 속성 링크', args = args }
		--cats
		local articleCat = category..' 식별자를 포함한 위키백과 문서'
		local faultyCat =  '잘못된 '..category..' 식별자를 포함한 위키백과 문서'
		--counts
		local articleCount = lang:formatNum( mw.site.stats.pagesInCategory(articleCat, 'pages') )
		local faultyCount =  lang:formatNum( mw.site.stats.pagesInCategory(faultyCat, 'pages') )
		--calcs
		P = P + 1 --property count
		a = a + lang:parseFormattedNumber(articleCount)
		f = f + lang:parseFormattedNumber(faultyCount)
		--concat
		wikiTable = wikiTable..'<tr><td>[['..link..'|'..param..']]</td>'..
			'<td>'..section..'</td>'..
			'<td>'..appearsAs..'</td>'..
			'<td data-sort-value='..pid..'>'..wpl..'</td>'..
			'<td style="text-align: right;">'..p.checkcat(articleCat,articleCount)..'</td>'..
			'<td style="text-align: right;">'..p.checkcat(faultyCat,faultyCount)..'</td></tr>'
	end

	--append derivative WorldCat cats
	local wcd = { 'WorldCat-LCCN', 'WorldCat-VIAF' }
	for _, w in pairs(wcd) do
		local articleCat = w.. ' 식별자를 포함한 위키백과 문서'
		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 월드캣 (미국 의회도서관을 통해)]'
		else
			appearsAs = '[https://www.worldcat.org/identities/containsVIAFID/12345789 월드캣 (VIAF를 통해)]'
		end
		a = a + lang:parseFormattedNumber(articleCount)
		wikiTable = wikiTable..'<tr><td>-</td>'..
			'<td>일반</td>'..
			'<td>'..appearsAs..'</td>'..
			'<td data-sort-value='..w..'>—</td>'..
			'<td style="text-align: right;">[[:분류:'..articleCat..'|'..articleCount..']]</td>'..
			'<td style="text-align: right;">—</td></tr>'
	end

	--append sums
	wikiTable = wikiTable..'<tr><th style="text-align: right;" colspan=3>전체</th>'..
		'<th style="text-align: right;">'..lang:formatNum(P)..'</th>'..
		'<th style="text-align: right;">'..lang:formatNum(a)..'</th>'..
		'<th style="text-align: right;">'..lang:formatNum(f)..'</th></tr></table>'

	return require('Module:Suppress categories').main(wikiTable)
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 (식별자)' },
	{ 'ADB', 1907, p.adbLink,'인명 사전', 'barton-sir-edmund-toby-71' },
	{ 'admiralty', 3562, p.admiraltyLink, '등대 식별자', 'D1204.1', prefix='[[:en:Admiralty number|Admiralty]]'},
	{ 'AGSA', 6804, p.agsaLink, '미술관', '3625' },
	{ 'ARLHS', 2980, p.ARLHSLink, '등대 식별자', 'LAT023'},
	{ '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' },
	{ 'BNMM', 3788, p.bnmmLink, '국립도서관', '000024044' },
	{ 'Botanist', 428, p.botanistLink , '학술 데이터베이스', 'L.' },
	{ 'BPN', 651, p.bpnLink , '인명 사전', '12345678' },
	{ 'CANTIC', 1273, p.canticLink, '국립도서관', 'a12345678' },
	{ 'CANTICN', 9984, p.canticnLink, '국립도서관', '981058515460906706' },
	{ 'CCG', 3920, p.ccgLink, '등대 식별자', 'A1761', prefix='[[CCG (식별자)|CCG]]' },
	{ 'CINII', 271, p.ciniiLink, '학술 데이터베이스', 'DA12345678', link = 'CiNii (식별자)' },
	{ 'CWGC', 1908, p.cwgcLink, '기타', '1234567' },
	{ 'DAAO', 1707, p.daaoLink, '미술 연구소', 'rolf-harris' },
	{ 'DBLP', 2456, p.dblpLink, '학술 데이터베이스', '123/123' },
	{ 'DIB',  6829, p.dibLink, '인명 사전', '001953' },
	{ 'DSI', 2349, p.dsiLink, '미술 연구소', '1538' },
	{ 'DTBIO', 7902, p.dtbioLink, '인명 사전', '118554700' },
	{ 'EMU', 4613, p.emuLink, '국립도서관', '15409' },
	{ 'FAST', 2163, p.fastLink, '기타', '1' },
	{ 'FNZA', 6792, p.fnzaLink, '미술 연구소', '12' },
	{ 'GND', 227, p.gndLink, '국립도서관', '4079154-3' },
	{ 'Google Scholar', 1960, p.googleLink, '학술 데이터베이스', 'QPdLuj8AAAAJ' },
	{ 'HDS', 902, p.hdsLink, '기타', '050123' },
	{ 'IAAF', 1146, p.iaafLink, '기타', '123' },
	{ 'ICCU', 396, p.iccuLink, '국립도서관', 'CFIV000163' }, --formerly SBN
	{ 'ICIA', 1736, p.iciaLink, '미술 연구소', '1' },
	{ 'IEU', 9070, p.ieuLink, '기타', 'N\\A\\NationalAcademyofArtandArchitecture' },
	{ 'ISNI', 213, p.isniLink, '일반', '0000-0000-6653-4145', prefix = '[[ISNI (식별자)|ISNI]]' },
	{ 'J9U', 8189, p.j9uLink, '국립도서관', '987007305652505171' },
	{ 'Joconde', 347, p.jocondeLink, '미술 연구소', '12345678901' },
	{ 'KULTURNAV', 1248, p.kulturnavLink, '미술 연구소', '12345678-1234-1234-1234-1234567890AB', link='KulturNav (식별자)' },
	{ 'LCCN', 244, p.lccnLink, '국립도서관', 'n78039510' },
	{ 'LIR', 886, p.lirLink, '기타', '1' },
	{ 'LNB', 1368, p.lnbLink, '국립도서관', '123456789' },
	{ 'Marina Militare', 3863, p.marinaMilitareLink, '등대 식별자', '3856' },
	{ 'MarineTraffic', 3601, p.mtLink, '등대 식별자', '1000004707' },
	{ 'MATHSN', 4955, p.mathsnLink, '학술 데이터베이스', '175270' },
	{ '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' },
	{ 'NGA', 3563, p.ngaLink, '등대 식별자', '114-5592'},
	{ 'NGV', 2041, p.ngvLink, '미술관', '12354' },
	{ 'NKC', 691, p.nkcLink, '국립도서관', 'abcd12345678901234' },
	{ 'NLA', 409, p.nlaLink, '국립도서관', '123456789012' },
	{ 'NLG', 3348, p.nlgLink, '국립도서관', '12345678' },
	{ '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 = '[[ORCID (식별자)|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 = '[[RISM (식별자)|RISM (프랑스)]]' },
	{ 'RERO', 3065, p.reroLink, '기타', '02-A012345678', prefix = '[[RERO (식별자)|RERO (스위스)]]' },
	{ 'RKDartists', 650, p.rkdartistsLink, '미술 연구소', '123456' },
	{ 'RKDID', 350, p.rkdidLink, '미술 연구소', '123456' },
	{ 'RSL', 947, p.rslLink, '국립도서관', '123456789' },
	{ 'Scopus', 1153, p.scopusLink, '학술 데이터베이스', '7005487412' },
	{ 'SELIBR', 906, p.selibrLink, '국립도서관', '123456' },
	{ 'SIKART', 781, p.sikartLink, '미술 연구소', '123456789' },
	{ 'SNAC-ID', 3430, p.snacLink, '기타', 'A' },
	{ 'SUDOC', 269, p.sudocLink, '기타', '026927608', prefix = '[[SUDOC (식별자)|SUDOC (프랑스)]]' },
	{ '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 = '[[Trove (식별자)|Trove (오스트레일리아)]]' }, --formerly NLA-person
	{ 'UKPARL', 6213, p.ukparlLink, '기타', 'AQUupyiR' },
	{ 'ULAN', 245, p.ulanLink, '미술 연구소', '500123456' },
	{ 'USCG', 3723, p.uscgLink, '등대 식별자', '6-0695'},
	{ 'USCongress', 1157, p.uscongressLink, '기타', 'A000123', link = 'US Congress (식별자)' },
	{ 'VcBA', 8034, p.vcbaLink, '국립도서관', '494/9793' },
	{ 'VIAF', 214, p.viafLink, '일반', '123456789', prefix = '[[VIAF (식별자)|VIAF]]' },
	{ 'WORLDCATID', 7859, p.worldcatidLink, '일반', 'lccn-n78-95332', link = 'WorldCat Identities (식별자)' },
	{ 'ZBMATH', 1556, p.zbmathLink, '학술 데이터베이스', 'turing.alan-m' },
}

-- Legitimate aliases to p.conf, for convenience
-- Format: { 'alias', 'parameter name in p.conf' }
p.aliases = {
	{ 'DNB', 'GND' }, --Deutsche Nationalbibliothek -> Gemeinsame Normdatei
	{ '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 = '[[분류:구식의 전거 통제 식별자가 포함된 문서|'..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
	elseif mw.wikibase then
		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 = '[[분류:전거 통제 식별자가 생략된 위키백과 문서|'..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 = '[[분류:위키데이터와 다른 변수를 포함한 전거 통제를 사용하는 문서|'..params[1]..']]'
		end	end	end	end	end
		if iMatches > 0 and iMatches == iParentArgs then
			sameOnWDCat = '[[분류:위키데이터와 모두 일치하는 변수를 포함한 전거 통제를 사용하는 문서]]'
		end
		if parentArgs['arts'] == 'arts' and suppressedIdCount > 0 then
			if namespace == 0 or testcases then
				local sCat = suppressedIdCount..'개 요소가 생략된 ACArt'
				suppressedIdCatArts = addCat(sCat)
			end
		end
	end

	--configure rows
	local rct = 0
	local sectionOrder = {
		'일반',
		'국립도서관',
		'미술관',
		'미술 연구소',
		'인명 사전',
		'학술 데이터베이스',
		'등대 식별자',
		'기타'
	}
	local sections = {
		['일반'] = {},
		['국립도서관'] = {},
		['미술관'] = {},
		['미술 연구소'] = {},
		['인명 사전'] = {},
		['학술 데이터베이스'] = {},
		['등대 식별자'] = {},
		['기타'] = {}
	}
	--don't show CANTIC if CANTICN is present, since they both go to the Library of Catalonia
	--and the library has deprecated CANTIC IDs in favor of CANTICN IDs
	if parentArgs.CANTICN or parentArgs.canticn then
		parentArgs.CANTIC = ''
		parentArgs.cantic = ''
	end
	-- 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( '여러' )
			end
		end

	end

	--WorldCat-VIAF & WorldCat-LCCN
	local worldcatId = parentArgs['worldcatid'] or parentArgs['WORLDCATID']
	if 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..' 월드캣 (VIAF를 통해)]', nil, false ) )
			if namespace == 0 then
				worldcatCat = '[[분류:WorldCat-VIAF 식별자를 포함한 위키백과 문서]]'
			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..' 월드캣 (미국 의회도서관을 통해)]', nil, false ) )
				if namespace == 0 then
					worldcatCat = '[[분류:WorldCat-LCCN 식별자를 포함한 위키백과 문서]]'
				end
			end
			rct = rct + 1
		end
	end

	--configure Navbox
	local outString = ''
	local extrap = true
	local extra = parentArgs.extralist
	if extra == nil or extra == '' then
		extrap = false
	end
	if rct > 0 or extrap then
		local Navbox = require('Module:Navbox')
		local sectionID = 1
		local args = { pid = 'identifiers' } -- #target the list of identifiers
		if testcases and itemId then args.qid = itemId end --expensive
		local pencil = require('Module:EditAtWikidata')._showMessage(args)
		local navboxArgs = {
			name  = 'Authority control',
			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 extrap then
			if parentArgs.extragroup then
				navboxArgs['group'..sectionID] = parentArgs.extragroup
			else
				navboxArgs['group'..sectionID] = '추가'
			end
			navboxArgs['list'..sectionID] = extra
			sectionID = sectionID + 1
		end
		if navboxArgs.list2 then
			navboxArgs.title = '[[위키백과:전거 통제|전거 통제]]'..pencil
		else
			local sect = navboxArgs.group1
			if sect == '일반' or sect == '기타' or sect == '추가' then
				-- Just say 'Authority control' with no label if only general or only other IDs are present
				-- since 'general' is redundant and 'other' is silly when there's nothing to contrast it with
				navboxArgs.group1 = '[[위키백과:전거 통제|전거 통제]]' .. pencil
			else
				navboxArgs.group1 = '[[위키백과:전거 통제|전거 통제: ' .. 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 = rct..'개의 요소가 포함된 전거 통제'
			elementsCat = addCat(eCat)
		end
	end
	if parentArgs.state then
		if namespace == 0 or testcases then
			local sCat
			if parentArgs.state == 'collapsed' then sCat = 'collapsed 상태 변수를 사용하는 전거 통제'
			elseif parentArgs.state == 'expanded' then sCat = 'expanded 상태 변수를 사용하는 전거 통제'
			elseif parentArgs.state == 'autocollapse' then sCat = 'autocollapse 상태 변수를 사용하는 전거 통제'
			else sCat = '기타 상태 변수를 사용하는 전거 통제'
			end
			stateCat = addCat(sCat)
		end
	end
	local auxCats = worldcatCat..elementsCat..multipleIdCat..suppressedIdCat..suppressedIdCatArts..
					deprecatedIdCat..differentOnWDCat..sameOnWDCat..stateCat
	if testcases then
		auxCats = mw.ustring.gsub(auxCats, '(%[%[)(분류)', '%1:%2') --for easier checking
	end

	--out
	outString = outString..auxCats
	if namespace ~= 0 then
		outString = mw.ustring.gsub(outString, '(%[%[)(분류:.* 문서)$', '%1:%2') --by definition
	end

	return outString
end

return p