“模块:Authority control”与“模块:Color contrast”:页面之间的差异

(页面间差异)
(导入1个版本)
 
(导入1个版本)
 
第1行: 第1行:
require('Module:No globals')
--
 
-- This module implements
--  {{Color contrast ratio}}
--  {{Greater color contrast ratio}}
--  {{ColorToLum}}
--  {{RGBColorToLum}}
--
local p = {}
local p = {}
local title = mw.title.getCurrentTitle()
local HTMLcolor = mw.loadData( 'Module:Color contrast/colors' )
local namespace = title.namespace
local testcases = (string.sub(title.subpageText,1,9) == 'testcases')
 
--[[==========================================================================]]
--[[                            Category functions                            ]]
--[[==========================================================================]]


function p.getCatForId( id )
local function sRGB (v)
local catName = ''
if (v <= 0.03928) then
if namespace == 0 then
v = v / 12.92
catName = 'Wikipedia articles with '..id..' identifiers'
elseif namespace == 2 and not title.isSubpage then
catName = 'User pages with '..id..' identifiers'
else
else
catName = 'Miscellaneous pages with '..id..' identifiers'
v = math.pow((v+0.055)/1.055, 2.4)
end
end
return '[[Category:'..catName..']]'..p.redCatLink(catName)
return v
end
end


function p.redCatLink( catName ) --catName == 'Blah', not 'Category:Blah', not '[[Category:Blah]]'
local function rgbdec2lum(R, G, B)
if catName and catName ~= '' and
if ( 0 <= R and R < 256 and 0 <= G and G < 256 and 0 <= B and B < 256 ) then
  testcases == false and
return 0.2126 * sRGB(R/255) + 0.7152 * sRGB(G/255) + 0.0722 * sRGB(B/255)
  mw.title.new(catName, 14).exists == false
else
then
return ''
return '[[Category:Pages with red-linked authority control categories]]'
end
end
return ''
end
end


--[[==========================================================================]]
local function hsl2lum(h, s, l)
--[[                      Property formatting functions                      ]]
if ( 0 <= h and h < 360 and 0 <= s and s <= 1 and 0 <= l and l <= 1 ) then
--[[==========================================================================]]
local c = (1 - math.abs(2*l - 1))*s
local x = c*(1 - math.abs( math.fmod(h/60, 2) - 1) )
local m = l - c/2


function p.aagLink( id )
local r, g, b = m, m, m
--P3372's format regex: \d+ (e.g. 1)
if( 0 <= h and h < 60 ) then
if not id:match( '^%d+$' ) then
r = r + c
return false
g = g + x
elseif( 60 <= h and h < 120 ) then
r = r + x
g = g + c
elseif( 120 <= h and h < 180 ) then
g = g + c
b = b + x
elseif( 180 <= h and h < 240 ) then
g = g + x
b = b + c
elseif( 240 <= h and h < 300 ) then
r = r + x
b = b + c
elseif( 300 <= h and h < 360 ) then
r = r + c
b = b + x
end
return rgbdec2lum(255*r, 255*g, 255*b)
else
return ''
end
end
return '[https://www.aucklandartgallery.com/explore-art-and-ideas/artist/'..id..'/ '..id..']'..p.getCatForId( 'AAG' )
end
end


function p.acmLink( id )
local function color2lum(c)
--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..' '..id..']'..p.getCatForId( 'ACM-DL' )
end


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


function p.agsaLink( id )
-- html '#' entity
--P6804's format regex: [1-9]\d* (e.g. 3625)
c = c:gsub("&#35;", "#")
if not id:match( '^[1-9]%d*$' ) then
return false
end
return '[https://www.agsa.sa.gov.au/collection-publications/collection/creators/_/'..id..'/ '..id..']'..p.getCatForId( 'AGSA' )
end


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


function p.awrLink( id )
-- unstrip nowiki strip markers
--P4186's format regex: (([A-Z]{3}\d{4})|([A-Z]{2}\d{5}))[a-z] (e.g. PR00768b)
c = mw.text.unstripNoWiki(c)
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 '..id..']'..p.getCatForId( 'AWR' )
end


function p.balatLink( id )
-- lowercase
--P3293's format regex: \d+ (e.g. 1)
c = c:lower()
if not id:match( '^%d+$' ) then
return false
end
return '[http://balat.kikirpa.be/object/104257'..id..' '..id..']'..p.getCatForId( 'BALaT' ) --no https as of 9/2019
end


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


function p.bildLink( id )
-- convert from hsl
--P2092's format regex: \d+ (e.g. 1)
if mw.ustring.match(c,'^hsl%([%s]*[0-9][0-9%.]*[%s]*,[%s]*[0-9][0-9%.]*%%[%s]*,[%s]*[0-9][0-9%.]*%%[%s]*%)$') then
if not id:match( '^%d+$' ) then
local h, s, l = mw.ustring.match(c,'^hsl%([%s]*([0-9][0-9%.]*)[%s]*,[%s]*([0-9][0-9%.]*)%%[%s]*,[%s]*([0-9][0-9%.]*)%%[%s]*%)$')
return false
return hsl2lum(tonumber(h), tonumber(s)/100, tonumber(l)/100)
end
end
return '[https://www.bildindex.de/document/obj'..id..' '..id..']'..p.getCatForId( 'Bildindex' )
end


function p.bncLink( id )
-- convert from rgb
--P1890's format regex: \d{9} (e.g. 123456789)
if mw.ustring.match(c,'^rgb%([%s]*[0-9][0-9]*[%s]*,[%s]*[0-9][0-9]*[%s]*,[%s]*[0-9][0-9]*[%s]*%)$') then
if not id:match( '^%d%d%d%d%d%d%d%d%d$' ) then
local R, G, B = mw.ustring.match(c,'^rgb%([%s]*([0-9][0-9]*)[%s]*,[%s]*([0-9][0-9]*)[%s]*,[%s]*([0-9][0-9]*)[%s]*%)$')
return false
return rgbdec2lum(tonumber(R), tonumber(G), tonumber(B))
end
end
return '[http://www.bncatalogo.cl/F?func=direct&local_base=red10&doc_number='..id..' '..id..']'..p.getCatForId( 'BNC' )
end


function p.bneLink( id )
-- convert from rgb percent
--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 mw.ustring.match(c,'^rgb%([%s]*[0-9][0-9%.]*%%[%s]*,[%s]*[0-9][0-9%.]*%%[%s]*,[%s]*[0-9][0-9%.]*%%[%s]*%)$') then
if not id:match( '^[XF][XF]%d%d%d%d%d?%d?%d?$' ) and
local R, G, B = mw.ustring.match(c,'^rgb%([%s]*([0-9][0-9%.]*)%%[%s]*,[%s]*([0-9][0-9%.]*)%%[%s]*,[%s]*([0-9][0-9%.]*)%%[%s]*%)$')
  not id:match( '^a%d%d%d%d%d?%d?%d?$' ) and
return rgbdec2lum(255*tonumber(R)/100, 255*tonumber(G)/100, 255*tonumber(B)/100)
  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
end
return '[http://catalogo.bne.es/uhtbin/authoritybrowse.cgi?action=display&authority_id='..id..' '..id..']'..p.getCatForId( 'BNE' ) --no https as of 9/2019
end


function p.bnfLink( id )
-- remove leading # (if there is one) and whitespace
--P268's format regex: \d{8}[0-9bcdfghjkmnpqrstvwxz] (e.g. 123456789)
c = mw.ustring.match(c, '^[%s#]*([a-f0-9]*)[%s]*$')
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..' '..id..'] [https://data.bnf.fr/ark:/12148/'..id..' (data)]'..p.getCatForId( 'BNF' )
end


function p.botanistLink( id )
-- split into rgb
--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.)
local cs = mw.text.split(c or '', '')
--not easily/meaningfully implementable in Lua's regex since "(this)?" is not allowed...
if( #cs == 6 ) then
if not mw.ustring.match( id, "^[%u%l%d%. '-]+$" ) then --better than nothing
local R = 16*tonumber('0x' .. cs[1]) + tonumber('0x' .. cs[2])
return false
local G = 16*tonumber('0x' .. cs[3]) + tonumber('0x' .. cs[4])
end
local B = 16*tonumber('0x' .. cs[5]) + tonumber('0x' .. cs[6])
local id2 = id:gsub(' +', '%%20')
return '[https://www.ipni.org/ipni/advAuthorSearch.do?find_abbreviation='..id2..' '..id..']'..p.getCatForId( 'Botanist' )
end


function p.bpnLink( id )
return rgbdec2lum(R, G, B)
--P651's format regex: \d{6,8} (e.g. 00123456)
elseif ( #cs == 3 ) then
if not id:match( '^%d%d%d%d%d%d%d%d$' ) and --original format regex, changed 8/2019 to
local R = 16*tonumber('0x' .. cs[1]) + tonumber('0x' .. cs[1])
  not id:match( '^0?%d%d%d%d%d%d%d$' ) and --allow 1-2 leading 0s, allowed by the website
local G = 16*tonumber('0x' .. cs[2]) + tonumber('0x' .. cs[2])
  not id:match( '^0?0?%d%d%d%d%d%d$' ) then
local B = 16*tonumber('0x' .. cs[3]) + tonumber('0x' .. cs[3])
return false
end
return '[http://www.biografischportaal.nl/en/persoon/'..id..' '..id..']'..p.getCatForId( 'BPN' ) --no https as of 9/2019
end


function p.canticLink( id )
return rgbdec2lum(R, G, B)
--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
end
return '[http://cantic.bnc.cat/registres/CUCId/'..id..' '..id..']'..p.getCatForId( 'CANTIC' ) --no https as of 10/2019
end


function p.ciniiLink( id )
-- failure, return blank
--P271's format regex: DA\d{7}[\dX] (e.g. DA12345678)
return ''
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 '..id..']'..p.getCatForId( 'CINII' )
end
end


function p.daaoLink( id )
-- This exports the function for use in other modules.
--P1707's format regex: [a-z\-]+\d* (e.g. rolf-harris)
-- The colour is passed as a string.
if not id:match( '^[a-z%-]+%d*$' ) then
function p._lum(color)
return false
return color2lum(color)
end
return '[https://www.daao.org.au/bio/'..id..' '..id..']'..p.getCatForId( 'DAAO' )
end
end


function p.dblpLink( id )
function p._greatercontrast(args)
--P2456's format regex: \d{2,3} /\d+(-\d+)?|[a-z] /[a-zA-Z][0-9A-Za-z]*(-\d+)? (e.g. 123/123)
local bias = tonumber(args['bias'] or '0') or 0
if not id:match( '^%d%d%d?/%d+$' ) and
local css = (args['css'] and args['css'] ~= '') and true or false
  not id:match( '^%d%d%d?/%d+%-%d+$' ) and
local v1 = color2lum(args[1] or '')
  not id:match( '^[a-z]/[a-zA-Z][0-9A-Za-z]*$' ) and
local c2 = args[2] or '#FFFFFF'
  not id:match( '^[a-z]/[a-zA-Z][0-9A-Za-z]*%-%d+$' ) then
local v2 = color2lum(c2)
return false
local c3 = args[3] or '#000000'
local v3 = color2lum(c3)
local ratio1 = -1;
local ratio2 = -1;
if (type(v1) == 'number' and type(v2) == 'number') then
ratio1 = (v2 + 0.05)/(v1 + 0.05)
ratio1 = (ratio1 < 1) and 1/ratio1 or ratio1
end
end
return '[https://dblp.org/pid/'..id..' '..id..']'..p.getCatForId( 'DBLP' )
if (type(v1) == 'number' and type(v3) == 'number') then
end
ratio2 = (v3 + 0.05)/(v1 + 0.05)
 
ratio2 = (ratio2 < 1) and 1/ratio2 or ratio2
function p.dsiLink( id )
--P2349's format regex: [1-9]\d* (e.g. 1538)
if not id:match( '^[1-9]%d*$' ) then
return false
end
end
return '[http://www.uni-stuttgart.de/hi/gnt/dsi2/index.php?table_name=dsi&function=details&where_field=id&where_value='..id..' '..id..']'..p.getCatForId( 'DSI' )
end


function p.fnzaLink( id )
if css then
--P6792's format regex: [1-9]\d* (e.g. 9785)
local c1 = args[1] or ''
if not id:match( '^[1-9]%d*$' ) then
if mw.ustring.match(c1, '^[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]$') or
return false
mw.ustring.match(c1, '^[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]$') then
c1 = '#' .. c1
end
if mw.ustring.match(c2, '^[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]$') or
mw.ustring.match(c2, '^[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]$') then
c2 = '#' .. c2
end
if mw.ustring.match(v3, '^[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]$') or
mw.ustring.match(v3, '^[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]$') then
c3 = '#' .. c3
end
return 'background-color:' .. c1 .. '; color:' .. ((ratio1 > 0) and (ratio2 > 0) and ((ratio1 + bias > ratio2) and c2 or c3) or '') .. ';'
end
end
return '[https://findnzartists.org.nz/artist/'..id..'/ '..id..']'..p.getCatForId( 'FNZA' )
end


function p.gndLink( id )
return (ratio1 > 0) and (ratio2 > 0) and ((ratio1 + bias > ratio2) and c2 or c3) or ''
--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..' '..id..']'..p.getCatForId( 'GND' )
end
end


function p.hdsLink( id )
function p._ratio(args)
--P902's format regex: \d{6} (e.g. 050123)
local v1 = color2lum(args[1])
if not id:match( '^%d%d%d%d%d%d$' ) then
local v2 = color2lum(args[2])
return false
if (type(v1) == 'number' and type(v2) == 'number') then
-- v1 should be the brighter of the two.
if v2 > v1 then
v1, v2 = v2, v1
end
return (v1 + 0.05)/(v2 + 0.05)
else
return args['error'] or '?'
end
end
return '[https://hls-dhs-dss.ch/fr/articles/'..id..' '..id..']'..p.getCatForId( 'HDS' )
end
end


function p.iaafLink( id )
function p._styleratio(args)
--P1146's format regex: [0-9][0-9]* (e.g. 012)
local style = (args[1] or ''):lower()
if not id:match( '^%d+$' ) then
local bg, fg = 'white', 'black'
return false
local lum_bg, lum_fg = 1, 0
end
return '[https://www.iaaf.org/athletes/_/'..id..' '..id..']'..p.getCatForId( 'IAAF' )
end


function p.iciaLink( id )
if args[2] then
--P1736's format regex: \d+ (e.g. 1)
local lum = color2lum(args[2])
if not id:match( '^%d+$' ) then
if lum ~= '' then bg, lum_bg = args[2], lum end
return false
end
end
return '[https://www.imj.org.il/artcenter/newsite/en/?artist='..id..' '..id..']'..p.getCatForId( 'ICIA' )
if args[3] then
end
local lum = color2lum(args[3])
 
if lum ~= '' then fg, lum_fg = args[3], lum end
function p.isniLink( id )
id = p.validateIsni( id ) --e.g. 0000-0000-6653-4145
if not id then
return false
end
end
return '[http://isni.org/isni/'..id..' '..id:sub( 1, 4 )..' '..id:sub( 5, 8 )..' '..id:sub( 9, 12 )..' '..id:sub( 13, 16 )..']'..p.getCatForId( 'ISNI' ) --no https as of 9/2019
end


function p.jocondeLink( id )
local slist = mw.text.split(mw.ustring.gsub(mw.ustring.gsub(style or '', '&#[Xx]23;', '#'), '&#35;', '#'), ';')
--P347's format regex: [\-0-9A-Za-z]{11} (e.g. 12345678901)
for k = 1,#slist do
local regex = '^'..string.rep('[%-0-9A-Za-z]', 11)..'$'
local s = slist[k]
if not id:match( regex ) then
local k,v = s:match( '^[%s]*([^:]-):([^:]-)[%s;]*$' )
return false
k = k or ''
v = v or ''
if (k:match('^[%s]*(background)[%s]*$') or k:match('^[%s]*(background%-color)[%s]*$')) then
local lum = color2lum(v)
if( lum ~= '' ) then bg, lum_bg = v, lum end
elseif (k:match('^[%s]*(color)[%s]*$')) then
local lum = color2lum(v)
if( lum ~= '' ) then bg, lum_fg = v, lum end
end
end
end
return '[https://www.pop.culture.gouv.fr/notice/joconde/'..id..' '..id..']'..p.getCatForId( 'Joconde' )
if lum_bg > lum_fg then
end
return (lum_bg + 0.05)/(lum_fg + 0.05)
 
else
function p.kulturnavLink( id )
return (lum_fg + 0.05)/(lum_bg + 0.05)
--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
end
return '[http://kulturnav.org/'..id..' '..id..']'..p.getCatForId( 'KULTURNAV' ) --no https as of 9/2019
end
end


function p.lccnLink( id )
--[[
local parts = p.splitLccn( id ) --e.g. n78039510
Use {{#invoke:Color contrast|somecolor}} directly or
if not parts then
{{#invoke:Color contrast}} from a wrapper template.
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..' '..id..']'..p.getCatForId( 'LCCN' )
end


function p.lirLink( id )
Parameters:
--P886's format regex: \d+ (e.g. 1)
-- |1= — required; A color to check.
if not id:match( '^%d+$' ) then
--]]
return false
function p.lum(frame)
end
local color = frame.args[1] or frame:getParent().args[1]
return '[http://www.e-lir.ch/e-LIR___Lexicon.'..id..'.450.0.html '..id..']'..p.getCatForId( 'LIR' ) --no https as of 9/2019
return p._lum(color)
end
end


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


function p.leonoreLink( id )
function p.styleratio(frame)
--P640's format regex: LH/\d{1,4}/\d{1,3}|19800035/\d{1,4}/\d{1,5}(Bis)?|C/0/\d{1,2} (e.g. LH/2064/18)
local args = frame.args[1] and frame.args or frame:getParent().args
if not id:match( '^LH/%d%d?%d?%d?/%d%d?%d?$' ) and            --IDs from      LH/1/1 to        LH/2794/54 (legionaries)
return p._styleratio(args)
  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( '^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..' '..id..']'..p.getCatForId( 'Léonore' ) --no https as of 9/2019
end
 
function p.mbaLink( id )
--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
return '[https://musicbrainz.org/artist/'..id..' '..id..']'..p.getCatForId( 'MusicBrainz' ) --special category name
end
end


function p.mbareaLink( id )
function p.greatercontrast(frame)
--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)
local args = frame.args[1] and frame.args or frame:getParent().args
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 p._greatercontrast(args)
return false
end
return '[https://musicbrainz.org/area/'..id..' '..id..']'..p.getCatForId( 'MusicBrainz area' ) --special category name
end
 
function p.mbiLink( id )
--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
return '[https://musicbrainz.org/instrument/'..id..' '..id..']'..p.getCatForId( 'MusicBrainz instrument' ) --special category name
end
 
function p.mblLink( id )
--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
return '[https://musicbrainz.org/label/'..id..' '..id..']'..p.getCatForId( 'MusicBrainz label' ) --special category name
end
 
function p.mbpLink( id )
--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
return '[https://musicbrainz.org/place/'..id..' '..id..']'..p.getCatForId( 'MusicBrainz place' ) --special category name
end
 
function p.mbrgLink( id )
--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
return '[https://musicbrainz.org/release-group/'..id..' '..id..']'..p.getCatForId( 'MusicBrainz release group' ) --special category name
end
 
function p.mbsLink( id )
--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
return '[https://musicbrainz.org/series/'..id..' '..id..']'..p.getCatForId( 'MusicBrainz series' ) --special category name
end
 
function p.mbwLink( id )
--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
return '[https://musicbrainz.org/work/'..id..' '..id..']'..p.getCatForId( 'MusicBrainz work' ) --special category name
end
 
function p.mgpLink( id )
--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..' '..id..']'..p.getCatForId( 'MGP' )
end
 
function p.naraLink( id )
--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..' '..id..']'..p.getCatForId( 'NARA' )
end
 
function p.nclLink( id )
--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 '..id..']'..p.getCatForId( 'NCL' ) --no https as of 9/2019
end
 
function p.ndlLink( id )
--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..' '..id..']'..p.getCatForId( 'NDL' )
end
 
function p.ngvLink( id )
--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..'/ '..id..']'..p.getCatForId( 'NGV' )
end
 
function p.nkcLink( id )
--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 '..id..']'..p.getCatForId( 'NKC' )
end
 
function p.nlaLink( id )
--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..' '..id..']'..p.getCatForId( 'NLA' )
end
 
function p.nlgLink( id )
--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..' '..id..']'..p.getCatForId( 'NLG' )
end
 
function p.nliLink( id )
--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'..' '..id..']'..p.getCatForId( 'NLI' )
end
 
function p.nlkLink( id )
--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..' '..id..']'..p.getCatForId( 'NLK' )
end
 
function p.nlpLink( id )
--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..' '..id..']'..p.getCatForId( 'NLP' )
end
 
function p.nlrLink( id )
--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://alephnew.bibnat.ro:8991/F?func=find-b&request='..id..'&find_code=SYS&adjacent=Y&local_base=NLR10 '..id..']'..p.getCatForId( 'NLR' )
end
 
function p.nskLink( id )
--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 '..id..']'..p.getCatForId( 'NSK' ) --no https as of 9/2019
end
 
function p.ntaLink( id )
--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..' '..id..']'..p.getCatForId( 'NTA' )
end
 
function p.orcidLink( id )
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..' '..id..']'..p.getCatForId( 'ORCID' )
end
 
function p.picLink( id )
--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..' '..id..']'..p.getCatForId( 'PIC' )
end
 
function p.ridLink( id )
--P1053's format regex: [A-Z]-\d{4}-(19|20)\d\d (e.g. A-1234-1934)
if not id:match( '^[A-Z]%-%d%d%d%d%-19%d%d$' ) and
  not id:match( '^[A-Z]%-%d%d%d%d%-20%d%d$' ) then
return false
end
return '[https://www.researcherid.com/rid/'..id..' '..id..']'..p.getCatForId( 'RID' )
end
 
function p.reroLink( id )
--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..' '..id..']'..p.getCatForId( 'RERO' )
end
 
function p.rkdartistsLink( id )
--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..' '..id..']'..p.getCatForId( 'RKDartists' )
end
 
function p.rkdidLink( id )
--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..' '..id..']'..p.getCatForId( 'RKDID' )
end
 
function p.rslLink( id )
--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 '..id..']'..p.getCatForId( 'RSL' ) --no https as of 9/2019
end
 
function p.sbnLink( id )
--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..' '..id..']'..p.getCatForId( 'SBN' )
end
 
function p.selibrLink( id )
--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..' '..id..']'..p.getCatForId( 'SELIBR' )
end
 
function p.sikartLink( id )
--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 '..id..']'..p.getCatForId( 'SIKART' ) --no https as of 9/2019
end
 
function p.snacLink( id )
--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..' '..id..']'..p.getCatForId( 'SNAC-ID' )
end
 
function p.sudocLink( id )
--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..' '..id..']'..p.getCatForId( 'SUDOC' )
end
 
function p.s2authoridLink( id )
--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..' '..id..']'..p.getCatForId( 'Semantic Scholar author' ) --special category name
end
 
function p.ta98Link( id )
--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
return '[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='..id..' '..id..']'..p.getCatForId( 'TA98' )
end
 
function p.tdviaLink( id )
--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..' '..id..']'..p.getCatForId( 'TDVİA' )
end
 
function p.teLink( id )
--P1693's format regex: E[1-8]\.\d{1,2}\.\d{1,2}\.\d{1,2}\.\d{1}\.\d{1}\.\d{1,3} (e.g. E1.23.45.67.8.9.0)
local e1, e2 = id:match( '^E([1-8])%.(%d%d?)%.%d%d?%.%d%d?%.%d%.%d%.%d%d?%d?$' )
if not e1 then
return false
end
local TEnum = 'TEe0'..e1 --no formatter URL in WD, probably due to this complexity
if e1 == '5' or e1 == '7' then
if #e2 == 1 then e2 = '0'..e2 end
TEnum = TEnum..e2
end
return '[http://www.unifr.ch/ifaa/Public/EntryPage/ViewTE/'..TEnum..'.html '..id..']'..p.getCatForId( 'TE' )
end
 
function p.tepapaLink( id )
--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..' '..id..']'..p.getCatForId( 'TePapa' )
end
 
function p.thLink( id )
--P1694's format regex: H\d\.\d{2}\.\d{2}\.\d\.\d{5} (e.g. H1.23.45.6.78901)
local h1, h2 = id:match( '^H(%d)%.(%d%d)%.%d%d%.%d%.%d%d%d%d%d$' )
if not h1 then
return false
end
local THnum = 'THh'..h1..h2 --no formatter URL in WD, probably due to this complexity
return '[http://www.unifr.ch/ifaa/Public/EntryPage/ViewTH/'..THnum..'.html '..id..']'..p.getCatForId( 'TH' )
end
 
function p.tlsLink( id )
local id2 = 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( id2, regex ) then
return false
end
return '[http://tls.theaterwissenschaft.ch/wiki/'..id2..' '..id..']'..p.getCatForId( 'TLS' ) --no https as of 9/2019
end
 
function p.troveLink( id )
--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..' '..id..']'..p.getCatForId( 'Trove' )
end
 
function p.ulanLink( id )
--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..' '..id..']'..p.getCatForId( 'ULAN' )
end
 
function p.uscongressLink( id )
--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..' '..id..']'..p.getCatForId( 'USCongress' ) --no https as of 9/2019
end
 
function p.viafLink( id )
--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
return '[https://viaf.org/viaf/'..id..' '..id..']'..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, navigation bar, and 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
 
function p.matchesWikidataRequirements( itemId, reqs )
for _, group in ipairs( reqs ) do
local property = 'P'..group[1]
local qid = group[2]
local statements = mw.wikibase.getBestStatements( itemId, property )
if statements then
for _, statement in ipairs( statements ) do
if statement.mainsnak.datavalue then
if statement.mainsnak.datavalue.value['numeric-id'] == qid then
return true
end end end end end
return false
end
 
function p.createRow( id, label, rawValue, link, withUid, specialCat )
if link then
if withUid then
return '*<span class="nowrap">'..label..' <span class="uid">'..link..'</span></span>\n'
end
return '*<span class="nowrap">'..label..' '..link..'</span>\n'
end
 
local catName = 'Wikipedia articles with faulty '..(specialCat or id)..' identifiers'
return '* <span class="error">The '..id..' id '..rawValue..' is not valid.</span>[[Category:'..catName..']]'..p.redCatLink(catName)..'\n'
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 | Label\n'..
  '! rowspan=2; data-sort-type=number | Wikidata property\n'..
  '! colspan=4 | Tracking categories and page counts\n'..
  '|-\n'..
  '! [[:Category:Wikipedia 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:Wikipedia articles with faulty authority control information|'..'Faulty IDs]]\n'..
  '|-\n'
local lang = mw.getContentLanguage()
for _, conf in pairs( p.conf ) do
local param, link, pid = conf[1], conf[2], conf[3]
local category = conf.category or param
local args = { id = 'f', pid }
local wpl = frame:expandTemplate{ title = 'Wikidata property link', args = args }
--cats
local articleCat = 'Wikipedia articles with '..category..' identifiers'
local userCat =    'User pages with '..category..' identifiers'
local miscCat =    'Miscellaneous pages with '..category..' identifiers'
local faultyCat =  'Wikipedia 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') )
--concat
wikiTable = wikiTable..'\n'..
'|-\n'..
'||'..param..
'||'..link..
'||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
return wikiTable..'\n|}'
end
 
--[[==========================================================================]]
--[[                              Configuration                              ]]
--[[==========================================================================]]
 
-- If a specific "(identifier) redirect" exists for an identifier, please route through this particular redirect rather than linking directly to the target page. This reduces clutter in "What links here" and improves reverse lookup of articles where a manifestation of this particular identifier is used.
 
-- Check that the Wikidata item has this property-->value before adding it
local reqs = {}
 
-- Parameter format: { 'parameter name', 'label', propertyId # in Wikidata, formatting/validation function }
p.conf = {
{ 'AAG', '[[Auckland Art Gallery Toi o Tāmaki|AAG]]', 3372, p.aagLink },
{ 'ACM-DL', '[[ACM Digital Library|ACM DL]]', 864, p.acmLink },
{ 'ADB', '[[Australian Dictionary of Biography|ADB]]', 1907, p.adbLink },
{ 'AGSA', '[[Art Gallery of South Australia|AGSA]]', 6804, p.agsaLink },
{ 'autores.uy', '[[autores.uy]]', 2558, p.autoresuyLink },
{ 'AWR', '[[Australian Women\'s Register|AWR]]', 4186, p.awrLink },
{ 'BALaT', '[[Royal Institute for Cultural Heritage#Online artworks pages|BALaT]]', 3293, p.balatLink },
{ 'BIBSYS', '[[Bibsys|BIBSYS]]', 1015, p.bibsysLink },
{ 'Bildindex', '[[Marburg Picture Index|Bildindex]]', 2092, p.bildLink },
{ 'BNC', '[[Biblioteca Nacional de Chile|BNC]]', 1890, p.bncLink },
{ 'BNE', '[[Biblioteca Nacional de España|BNE]]', 950, p.bneLink },
{ 'BNF', '[[BNF (identifier)|BNF]]', 268, p.bnfLink },
{ 'Botanist', '[[Author citation (botany)|Botanist]]', 428, p.botanistLink },
{ 'BPN', '[[Biografisch Portaal|BPN]]', 651, p.bpnLink },
{ 'CANTIC', '[[Name and Title Authority File of Catalonia|CANTIC]]', 1273, p.canticLink },
{ 'CINII', '[[CiNii (identifier)|CiNii]]', 271, p.ciniiLink },
{ 'DAAO', '[[Dictionary of Australian Artists|DAAO]]', 1707, p.daaoLink },
{ 'DBLP', '[[DBLP]]', 2456, p.dblpLink },
{ 'DSI', '[[Stuttgart Database of Scientific Illustrators 1450–1950|DSI]]', 2349, p.dsiLink },
{ 'FNZA', '[[:d:Property:P6792|FNZA]]', 6792, p.fnzaLink },
{ 'GND', '[[GND (identifier)|GND]]', 227, p.gndLink },
{ 'HDS', '[[Historical Dictionary of Switzerland|HDS]]', 902, p.hdsLink },
{ 'IAAF', '[[World Athletics]]', 1146, p.iaafLink },
{ 'ICIA', '[[Information Center for Israeli Art|ICIA]]', 1736, p.iciaLink },
{ 'ISNI', '[[ISNI (identifier)|ISNI]]', 213, p.isniLink },
{ 'Joconde', '[[Joconde]]' , 347, p.jocondeLink },
{ 'KULTURNAV', '[[KulturNav]]', 1248, p.kulturnavLink },
{ 'LCCN', '[[LCCN (identifier)|LCCN]]', 244, p.lccnLink },
{ 'LIR', '[[Historical Dictionary of Switzerland#Lexicon_Istoric_Retic|LIR]]', 886, p.lirLink },
{ 'LNB', '[[National Library of Latvia|LNB]]', 1368, p.lnbLink },
{ 'Léonore', '[[Base Léonore|Léonore]]', 640, p.leonoreLink },
{ 'MBA', '[[MusicBrainz]]', 434, p.mbaLink, category = 'MusicBrainz' }, --special category name
{ 'MBAREA', '[[MusicBrainz]]', 982, p.mbareaLink, category = 'MusicBrainz area' }, --special category name
{ 'MBI', '[[MusicBrainz]]', 1330, p.mbiLink, category = 'MusicBrainz instrument' }, --special category name
{ 'MBL', '[[MusicBrainz]]', 966, p.mblLink, category = 'MusicBrainz label' }, --special category name
{ 'MBP', '[[MusicBrainz]]', 1004, p.mbpLink, category = 'MusicBrainz place' }, --special category name
{ 'MBRG', '[[MusicBrainz]] release group', 436, p.mbrgLink, category = 'MusicBrainz release group' }, --special category name
{ 'MBS', '[[MusicBrainz]]', 1407, p.mbsLink, category = 'MusicBrainz series' }, --special category name
{ 'MBW', '[[MusicBrainz]] work', 435, p.mbwLink, category = 'MusicBrainz work' }, --special category name
{ 'MGP', '[[Mathematics Genealogy Project|MGP]]', 549, p.mgpLink },
{ 'NARA', '[[National Archives and Records Administration|NARA]]', 1225, p.naraLink },
{ 'NCL', '[[National Central Library|NCL]]', 1048, p.nclLink },
{ 'NDL', '[[National Diet Library|NDL]]', 349, p.ndlLink },
{ 'NGV', '[[National Gallery of Victoria|NGV]]', 2041, p.ngvLink },
{ 'NKC', '[[National Library of the Czech Republic|NKC]]', 691, p.nkcLink },
{ 'NLA', '[[National Library of Australia|NLA]]', 409, p.nlaLink },
{ 'NLG', '[[National Library of Greece|NLG]]', 3348, p.nlgLink },
{ 'NLI', '[[National Library of Israel|NLI]]', 949, p.nliLink },
{ 'NLK', '[[National Library of Korea|NLK]]', 5034, p.nlkLink },
{ 'NLP', '[[National Library of Poland|NLP]]', 1695, p.nlpLink },
{ 'NLR', '[[National Library of Romania|NLR]]', 1003, p.nlrLink },
{ 'NSK', '[[National and University Library in Zagreb|NSK]]', 1375, p.nskLink },
{ 'NTA', '[[Royal Library of the Netherlands|NTA]]', 1006, p.ntaLink },
{ 'ORCID', '[[ORCID (identifier)|ORCID]]', 496, p.orcidLink },
{ 'PIC', '[[:d:Q23892012|PIC]]', 2750, p.picLink },
{ 'RID', '[[ResearcherID]]', 1053, p.ridLink },
{ 'RERO', '[[RERO (Library Network of Western Switzerland)|RERO]]', 3065, p.reroLink },
{ 'RKDartists', '[[Netherlands Institute for Art History#Online artist pages|RKD]]', 650, p.rkdartistsLink },
{ 'RKDID', '[[:d:Q17299580|RKDimages ID]]', 350, p.rkdidLink },
{ 'RSL', '[[Russian State Library|RSL]]', 947, p.rslLink },
{ 'SBN', '[[ICCU (identifier)|ICCU]]', 396, p.sbnLink },
{ 'SELIBR', '[[SELIBR (identifier)|SELIBR]]', 906, p.selibrLink },
{ 'SIKART', '[[SIKART]]', 781, p.sikartLink },
{ 'SNAC-ID', '[[SNAC]]', 3430, p.snacLink },
{ 'SUDOC', '[[SUDOC (identifier)|SUDOC]]', 269, p.sudocLink },
{ 'S2AuthorId', '[[Semantic Scholar|S2AuthorId]]', 4012, p.s2authoridLink, category = 'Semantic Scholar author' }, --special category name
{ 'TA98', '[[Terminologia Anatomica|TA98]]', 1323, p.ta98Link },
{ 'TDVİA', '[[:d:Q21527102|TDVİA]]', 7314, p.tdviaLink },
{ 'TE', '[[Terminologia Embryologica|TE]]', 1693, p.teLink },
{ 'TePapa', '[[Museum of New Zealand Te Papa Tongarewa|TePapa]]', 3544, p.tepapaLink },
{ 'TH', '[[Terminologia Histologica|TH]]', 1694, p.thLink },
{ 'TLS', '[[Theaterlexikon der Schweiz|TLS]]', 1362, p.tlsLink },
{ 'Trove', '[[Trove]]', 1315, p.troveLink }, --formerly NLA-person
{ 'ULAN', '[[Union List of Artist Names|ULAN]]', 245, p.ulanLink },
{ 'USCongress', '[[Biographical Directory of the United States Congress|US Congress]]', 1157, p.uscongressLink },
{ 'VIAF', '[[VIAF (identifier)|VIAF]]', 214, p.viafLink },
{ 'WORLDCATID', '[[WorldCat Identities]]', 7859, nil },
}
 
-- Legitimate aliases to p.conf, for convenience
-- Format: { 'alias', 'parameter name in p.conf' }
p.aliases = {
{ 'RLS', 'RSL' },
{ 'MusicBrainz', 'MBA' },
{ 'MusicBrainz artist', 'MBA' },
{ 'MusicBrainz label', 'MBL' },
{ 'MusicBrainz release group', 'MBRG' },
{ 'MusicBrainz work', 'MBW' },
{ 'Leonore', 'Léonore' },
{ 'TDVIA', 'TDVİA' },
}
 
-- Deprecated aliases to p.conf; tracked in [[Category:Wikipedia articles with deprecated authority control identifiers]]
-- Format: { 'deprecated parameter name', 'replacement parameter name in p.conf' }
p.deprecated = {
{ 'GKD', 'GND' },
{ 'PND', 'GND' },
{ 'SWD', 'GND' },
{ 'NARA-organization', 'NARA' },
{ 'NARA-person', 'NARA' },
}
 
--[[==========================================================================]]
--[[                                  Main                                  ]]
--[[==========================================================================]]
 
function p.authorityControl( frame )
local resolveEntity = require( "Module:ResolveEntityId" )
local parentArgs = frame:getParent().args
local elements = {} --create/insert rows later
local worldcatCat = ''
local suppressedIdCat = ''
local deprecatedIdCat = ''
--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:Wikipedia 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 requested
if itemId then
for _, params in ipairs( p.conf ) do
if params[3] > 0 then
local val = parentArgs[params[1]]
if val == nil or val == '' then
local canUseWikidata = nil
if reqs[params[1]] then
canUseWikidata = p.matchesWikidataRequirements( itemId, reqs[params[1]] )
else
canUseWikidata = true
end
if canUseWikidata then
local wikidataIds = p.getIdsFromWikidata( itemId, 'P'..params[3] )
if wikidataIds[1] then
if val == '' and (namespace == 0 or testcases) then
suppressedIdCat = '[[Category:Wikipedia articles with suppressed authority control identifiers|'..params[1]..']]'
else
parentArgs[params[1]] = wikidataIds[1]
end end end end end end end
--Configured rows
local rct = 0
for _, params in ipairs( p.conf ) do
local val = parentArgs[params[1]]
if val and val ~= '' and type(params[4]) == 'function' then
table.insert( elements, p.createRow( params[1], params[2]..':', val, params[4]( val ), true, params.category ) )
rct = rct + 1
end
end
--WorldCat
local worldcatId = parentArgs['WORLDCATID']
if worldcatId and worldcatId ~= '' then --if WORLDCATID present & unsuppressed
table.insert( elements, p.createRow( 'WORLDCATID', '', worldcatId, '[[WorldCat Identities]]: [https://www.worldcat.org/identities/'..mw.uri.encode(worldcatId, 'PATH')..' '..worldcatId..']', false ) ) --Validation?
worldcatCat = '[[Category:Wikipedia articles with WorldCat identifiers]]'
elseif worldcatId == nil then --if WORLDCATID absent but unsuppressed
local viafId = parentArgs['VIAF']
local lccnId = parentArgs['LCCN']
if viafId and viafId ~= '' and p.viafLink( viafId ) then --VIAF must be present, unsuppressed, & validated
table.insert( elements, p.createRow( 'VIAF', '', viafId, '[[WorldCat Identities]] (via VIAF): [https://www.worldcat.org/identities/containsVIAFID/'..viafId..' '..viafId..']', false ) )
if namespace == 0 then
worldcatCat = '[[Category:Wikipedia articles with WorldCat-VIAF identifiers]]'
end
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( elements, p.createRow( 'LCCN', '', lccnId, '[[WorldCat Identities]] (via LCCN): [https://www.worldcat.org/identities/lccn-'..lccnIdFmtd..' '..lccnIdFmtd..']', false ) )
if namespace == 0 then
worldcatCat = '[[Category:Wikipedia articles with WorldCat-LCCN identifiers]]'
end
end
end
elseif worldcatId == '' then --if WORLDCATID suppressed
suppressedIdCat = '[[Category:Wikipedia articles with suppressed authority control identifiers|WORLDCATID]]'
end
local Navbox = require('Module:Navbox')
local elementsCat = ''
if rct >= 25 then
local eCat = 'AC with '..rct..' elements'
elementsCat  = '[[Category:'..eCat..']]'..p.redCatLink(eCat)
end
local outString = ''
if #elements > 0 then
local args = {}
if testcases and itemId then args = { qid = itemId } end --expensive
local pencil = frame:expandTemplate{ title = 'EditAtWikidata', args = args}
outString = Navbox._navbox( {
name  = 'Authority control',
navboxclass = 'authority-control',
bodyclass = 'hlist',
group1 = '[[Help:Authority control|Authority control]]'..pencil,
list1 = table.concat( elements )
} )
local auxCats = worldcatCat .. elementsCat .. suppressedIdCat .. deprecatedIdCat
if testcases then
auxCats = mw.ustring.gsub(auxCats, '(%[%[)(Category)', '%1:%2') --for easier checking
end
outString = outString .. auxCats
if namespace ~= 0 then
outString = mw.ustring.gsub(outString, '(%[%[)(Category:Wikipedia articles)', '%1:%2') --by definition
end
end
return outString
end
end


return p
return p

2021年4月4日 (日) 15:31的最新版本

可在模块:Color contrast/doc创建此模块的帮助文档

--
-- This module implements
--  {{Color contrast ratio}}
--  {{Greater color contrast ratio}}
--  {{ColorToLum}}
--  {{RGBColorToLum}}
--
local p = {}
local HTMLcolor = mw.loadData( 'Module:Color contrast/colors' )

local function sRGB (v)
	if (v <= 0.03928) then
		v = v / 12.92
	else
		v = math.pow((v+0.055)/1.055, 2.4)
	end
	return v
end

local function rgbdec2lum(R, G, B)
	if ( 0 <= R and R < 256 and 0 <= G and G < 256 and 0 <= B and B < 256 ) then
		return 0.2126 * sRGB(R/255) + 0.7152 * sRGB(G/255) + 0.0722 * sRGB(B/255)
	else
		return ''
	end
end

local function hsl2lum(h, s, l)
	if ( 0 <= h and h < 360 and 0 <= s and s <= 1 and 0 <= l and l <= 1 ) then
		local c = (1 - math.abs(2*l - 1))*s
		local x = c*(1 - math.abs( math.fmod(h/60, 2) - 1) )
		local m = l - c/2

		local r, g, b = m, m, m
		if( 0 <= h and h < 60 ) then
			r = r + c
			g = g + x
		elseif( 60 <= h and h < 120 ) then
			r = r + x
			g = g + c
		elseif( 120 <= h and h < 180 ) then
			g = g + c
			b = b + x
		elseif( 180 <= h and h < 240 ) then
			g = g + x
			b = b + c
		elseif( 240 <= h and h < 300 ) then
			r = r + x
			b = b + c
		elseif( 300 <= h and h < 360 ) then
			r = r + c
			b = b + x
		end
		return rgbdec2lum(255*r, 255*g, 255*b)
	else
		return ''
	end
end

local function color2lum(c)

	if (c == nil) then
		return ''
	end

	-- html '#' entity
	c = c:gsub("&#35;", "#")

	-- whitespace
	c = c:match( '^%s*(.-)[%s;]*$' )

	-- unstrip nowiki strip markers
	c = mw.text.unstripNoWiki(c)

	-- lowercase
	c = c:lower()

	-- first try to look it up
	local L = HTMLcolor[c]
	if (L ~= nil) then
		return L
	end

	-- convert from hsl
	if mw.ustring.match(c,'^hsl%([%s]*[0-9][0-9%.]*[%s]*,[%s]*[0-9][0-9%.]*%%[%s]*,[%s]*[0-9][0-9%.]*%%[%s]*%)$') then
		local h, s, l = mw.ustring.match(c,'^hsl%([%s]*([0-9][0-9%.]*)[%s]*,[%s]*([0-9][0-9%.]*)%%[%s]*,[%s]*([0-9][0-9%.]*)%%[%s]*%)$')
		return hsl2lum(tonumber(h), tonumber(s)/100, tonumber(l)/100)
	end

	-- convert from rgb
	if mw.ustring.match(c,'^rgb%([%s]*[0-9][0-9]*[%s]*,[%s]*[0-9][0-9]*[%s]*,[%s]*[0-9][0-9]*[%s]*%)$') then
		local R, G, B = mw.ustring.match(c,'^rgb%([%s]*([0-9][0-9]*)[%s]*,[%s]*([0-9][0-9]*)[%s]*,[%s]*([0-9][0-9]*)[%s]*%)$')
		return rgbdec2lum(tonumber(R), tonumber(G), tonumber(B))
	end

	-- convert from rgb percent
	if mw.ustring.match(c,'^rgb%([%s]*[0-9][0-9%.]*%%[%s]*,[%s]*[0-9][0-9%.]*%%[%s]*,[%s]*[0-9][0-9%.]*%%[%s]*%)$') then
		local R, G, B = mw.ustring.match(c,'^rgb%([%s]*([0-9][0-9%.]*)%%[%s]*,[%s]*([0-9][0-9%.]*)%%[%s]*,[%s]*([0-9][0-9%.]*)%%[%s]*%)$')
		return rgbdec2lum(255*tonumber(R)/100, 255*tonumber(G)/100, 255*tonumber(B)/100)
	end

	-- remove leading # (if there is one) and whitespace
	c = mw.ustring.match(c, '^[%s#]*([a-f0-9]*)[%s]*$')

	-- split into rgb
	local cs = mw.text.split(c or '', '')
	if( #cs == 6 ) then
		local R = 16*tonumber('0x' .. cs[1]) + tonumber('0x' .. cs[2])
		local G = 16*tonumber('0x' .. cs[3]) + tonumber('0x' .. cs[4])
		local B = 16*tonumber('0x' .. cs[5]) + tonumber('0x' .. cs[6])

		return rgbdec2lum(R, G, B)
	elseif ( #cs == 3 ) then
		local R = 16*tonumber('0x' .. cs[1]) + tonumber('0x' .. cs[1])
		local G = 16*tonumber('0x' .. cs[2]) + tonumber('0x' .. cs[2])
		local B = 16*tonumber('0x' .. cs[3]) + tonumber('0x' .. cs[3])

		return rgbdec2lum(R, G, B)
	end

	-- failure, return blank
	return ''
end

-- This exports the function for use in other modules.
-- The colour is passed as a string.
function p._lum(color)
	return color2lum(color)
end

function p._greatercontrast(args)
	local bias = tonumber(args['bias'] or '0') or 0
	local css = (args['css'] and args['css'] ~= '') and true or false
	local v1 = color2lum(args[1] or '')
	local c2 = args[2] or '#FFFFFF'
	local v2 = color2lum(c2)
	local c3 = args[3] or '#000000'
	local v3 = color2lum(c3)
	local ratio1 = -1;
	local ratio2 = -1;
	if (type(v1) == 'number' and type(v2) == 'number') then
		ratio1 = (v2 + 0.05)/(v1 + 0.05)
		ratio1 = (ratio1 < 1) and 1/ratio1 or ratio1
	end
	if (type(v1) == 'number' and type(v3) == 'number') then
		ratio2 = (v3 + 0.05)/(v1 + 0.05)
		ratio2 = (ratio2 < 1) and 1/ratio2 or ratio2
	end

	if css then
		local c1 = args[1] or ''
		if mw.ustring.match(c1, '^[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]$') or
			mw.ustring.match(c1, '^[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]$') then
				c1 = '#' .. c1
		end
		if mw.ustring.match(c2, '^[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]$') or
			mw.ustring.match(c2, '^[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]$') then
				c2 = '#' .. c2
		end
		if mw.ustring.match(v3, '^[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]$') or
			mw.ustring.match(v3, '^[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]$') then
				c3 = '#' .. c3
		end
		return 'background-color:' .. c1 .. '; color:' .. ((ratio1 > 0) and (ratio2 > 0) and ((ratio1 + bias > ratio2) and c2 or c3) or '') .. ';'
	end

	return (ratio1 > 0) and (ratio2 > 0) and ((ratio1 + bias > ratio2) and c2 or c3) or ''
end

function p._ratio(args)
	local v1 = color2lum(args[1])
	local v2 = color2lum(args[2])
	if (type(v1) == 'number' and type(v2) == 'number') then
		-- v1 should be the brighter of the two.
		if v2 > v1 then
			v1, v2 = v2, v1
		end
		return (v1 + 0.05)/(v2 + 0.05)
	else
		return args['error'] or '?'
	end
end

function p._styleratio(args)
	local style = (args[1] or ''):lower()
	local bg, fg = 'white', 'black'
	local lum_bg, lum_fg = 1, 0

	if args[2] then
		local lum = color2lum(args[2])
		if lum ~= '' then bg, lum_bg = args[2], lum end
	end
	if args[3] then
		local lum = color2lum(args[3])
		if lum ~= '' then fg, lum_fg = args[3], lum end
	end

	local slist = mw.text.split(mw.ustring.gsub(mw.ustring.gsub(style or '', '&#[Xx]23;', '#'), '&#35;', '#'), ';')
	for k = 1,#slist do
		local s = slist[k]
		local k,v = s:match( '^[%s]*([^:]-):([^:]-)[%s;]*$' )
		k = k or ''
		v = v or ''
		if (k:match('^[%s]*(background)[%s]*$') or k:match('^[%s]*(background%-color)[%s]*$')) then
			local lum = color2lum(v)
			if( lum ~= '' ) then bg, lum_bg = v, lum end
		elseif (k:match('^[%s]*(color)[%s]*$')) then
			local lum = color2lum(v)
			if( lum ~= '' ) then bg, lum_fg = v, lum end
		end
	end
	if lum_bg > lum_fg then
		return (lum_bg + 0.05)/(lum_fg + 0.05)
	else
		return (lum_fg + 0.05)/(lum_bg + 0.05)
	end
end

--[[
Use {{#invoke:Color contrast|somecolor}} directly or
{{#invoke:Color contrast}} from a wrapper template.

Parameters:
	-- |1=	— required; A color to check.
--]]
function p.lum(frame)
	local color = frame.args[1] or frame:getParent().args[1]
	return p._lum(color)
end

function p.ratio(frame)
	local args = frame.args[1] and frame.args or frame:getParent().args
	return p._ratio(args)
end

function p.styleratio(frame)
	local args = frame.args[1] and frame.args or frame:getParent().args
	return p._styleratio(args)
end

function p.greatercontrast(frame)
	local args = frame.args[1] and frame.args or frame:getParent().args
	return p._greatercontrast(args)
end

return p