モジュールの解説[作成]

-- Original module located at [[:en:Module:Wd]], [[:en:Module:Wd/i18n]] and [[:en:Module:Wd/aliasesP]].  local p = {} local arg = ... local i18n  function loadSubmodules(frame) 	local title 	 	if frame then 		-- current module invoked by page/template, get its title from frame 		title = frame:getTitle() 	else 		-- current module included by other module, get its title from ... 		title = arg 	end 	 	i18n = i18n or require(title .. "/i18n") 	p.aliasesP = p.aliasesP or mw.loadData(title .. "/aliasesP") end  p.claimCommands = { 	property   = "property", 	properties = "properties", 	qualifier  = "qualifier", 	qualifiers = "qualifiers", 	reference  = "reference", 	references = "references" }  p.generalCommands = { 	label      = "label", 	title      = "title", 	alias      = "alias", 	aliases    = "aliases", 	badge      = "badge", 	badges     = "badges" }  p.flags = { 	linked        = "linked", 	short         = "short", 	raw           = "raw", 	multilanguage = "multilanguage", 	unit          = "unit", 	------------- 	preferred     = "preferred", 	normal        = "normal", 	deprecated    = "deprecated", 	best          = "best", 	future        = "future", 	current       = "current", 	former        = "former", 	edit          = "edit", 	editAtEnd     = "edit@end", 	mdy           = "mdy", 	single        = "single", 	sourced       = "sourced" }  p.args = { 	eid = "eid" }  local aliasesQ = { 	percentage              = "Q11229", 	prolepticJulianCalendar = "Q1985786", 	citeWeb                 = "Q5637226", 	citeQ                   = "Q22321052" }  local parameters = { 	property  = "%p", 	qualifier = "%q", 	reference = "%r", 	alias     = "%a", 	badge     = "%b", 	separator = "%s", 	general   = "%x" }  local formats = { 	property              = "%p[%s][%r]", 	qualifier             = "%q[%s][%r]", 	reference             = "%r", 	propertyWithQualifier = "%p[ <span style=\"font-size:85%\">(%q)</span>][%s][%r]", 	alias                 = "%a[%s]", 	badge                 = "%b[%s]" }  local hookNames = {              -- {level_1, level_2} 	[parameters.property]         = {"getProperty"}, 	[parameters.reference]        = {"getReferences", "getReference"}, 	[parameters.qualifier]        = {"getAllQualifiers"}, 	[parameters.qualifier.."\\d"] = {"getQualifiers", "getQualifier"}, 	[parameters.alias]            = {"getAlias"}, 	[parameters.badge]            = {"getBadge"} }  -- default value objects, should NOT be mutated but instead copied local defaultSeparators = { 	["sep"]      = {" "}, 	["sep%s"]    = {","}, 	["sep%q"]    = {"; "}, 	["sep%q\\d"] = {", "}, 	["sep%r"]    = nil,  -- none 	["punc"]     = nil   -- none }  local rankTable = { 	["preferred"]  = 1, 	["normal"]     = 2, 	["deprecated"] = 3 }  local Config = {} Config.__index = Config  -- allows for recursive calls function Config.new() 	local cfg = {} 	setmetatable(cfg, Config) 	 	cfg.separators = { 		-- single value objects wrapped in arrays so that we can pass by reference 		["sep"]   = {copyTable(defaultSeparators["sep"])}, 		["sep%s"] = {copyTable(defaultSeparators["sep%s"])}, 		["sep%q"] = {copyTable(defaultSeparators["sep%q"])}, 		["sep%r"] = {copyTable(defaultSeparators["sep%r"])}, 		["punc"]  = {copyTable(defaultSeparators["punc"])} 	} 	 	cfg.entity = nil 	cfg.entityID = nil 	cfg.propertyID = nil 	cfg.propertyValue = nil 	cfg.qualifierIDs = {} 	cfg.qualifierIDsAndValues = {} 	 	cfg.bestRank = true 	cfg.ranks = {true, true, false}  -- preferred = true, normal = true, deprecated = false 	cfg.foundRank = #cfg.ranks 	cfg.flagBest = false 	cfg.flagRank = false 	 	cfg.periods = {true, true, true}  -- future = true, current = true, former = true 	cfg.flagPeriod = false 	 	cfg.mdyDate = false 	cfg.singleClaim = false 	cfg.sourcedOnly = false 	cfg.editable = false 	cfg.editAtEnd = false 	 	cfg.inSitelinks = false 	 	cfg.langCode = mw.language.getContentLanguage().code 	cfg.langName = mw.language.fetchLanguageName(cfg.langCode, cfg.langCode) 	cfg.langObj = mw.language.new(cfg.langCode) 	 	-- somewhat reliable way of determining global site ID in the absence of a library function, targeting the Wikipedia project (i.e. appending "wiki") 	cfg.siteID = (function() for i,v in pairs(mw.site.interwikiMap("local")) do if v.isCurrentWiki and i~="w" then return mw.ustring.gsub(i,"-","_").."wiki" end end end)() 	 	cfg.states = {} 	cfg.states.qualifiersCount = 0 	cfg.curState = nil 	 	cfg.prefetchedRefs = nil 	 	return cfg end  local State = {} State.__index = State  function State.new(cfg) 	local stt = {} 	setmetatable(stt, State) 	 	stt.conf = cfg 	 	stt.results = {} 	 	stt.parsedFormat = {} 	stt.separator = {} 	stt.movSeparator = {} 	stt.puncMark = {} 	 	stt.linked = false 	stt.rawValue = false 	stt.shortName = false 	stt.anyLanguage = false 	stt.unitOnly = false 	stt.singleValue = false 	 	return stt end  function replaceAlias(id) 	if p.aliasesP[id] then 		id = p.aliasesP[id] 	end 	 	return id end  function errorText(code, param) 	local text = i18n["errors"][code] 	if param then text = mw.ustring.gsub(text, "$1", param) end 	return text end  function throwError(errorMessage, param) 	error(errorText(errorMessage, param)) end  function replaceDecimalMark(num) 	return mw.ustring.gsub(num, "[.]", i18n['numeric']['decimal-mark'], 1) end  function padZeros(num, numDigits) 	local numZeros 	local negative = false 	 	if num < 0 then 		negative = true 		num = num * -1 	end 	 	num = tostring(num) 	numZeros = numDigits - num:len() 	 	for i = 1, numZeros do 		num = "0"..num 	end 	 	if negative then 		num = "-"..num 	end 	 	return num end  function replaceSpecialChar(chr) 	if chr == '_' then 		-- replace underscores with spaces 		return ' ' 	else 		return chr 	end end  function replaceSpecialChars(str) 	local chr 	local esc = false 	local strOut = "" 	 	for i = 1, #str do 		chr = str:sub(i,i) 		 		if not esc then 			if chr == '\\' then 				esc = true 			else 				strOut = strOut .. replaceSpecialChar(chr) 			end 		else 			strOut = strOut .. chr 			esc = false 		end 	end 	 	return strOut end  function buildWikilink(target, label) 	if not label or target == label then 		return "[[" .. target .. "]]" 	else 		return "[[" .. target .. "|" .. label .. "]]" 	end end  -- used to make frame.args mutable, to replace #frame.args (which is always 0) -- with the actual amount and to simply copy tables function copyTable(tIn) 	if not tIn then 		return nil 	end 	 	local tOut = {} 	 	for i, v in pairs(tIn) do 		tOut[i] = v 	end 	 	return tOut end  -- used to merge output arrays together; -- note that it currently mutates the first input array function mergeArrays(a1, a2) 	for i = 1, #a2 do 		a1[#a1 + 1] = a2[i] 	end 	 	return a1 end  function split(str, del) 	local out = {} 	local i, j = str:find(del) 	 	if i and j then 		out[1] = str:sub(1, i - 1) 		out[2] = str:sub(j + 1) 	else 		out[1] = str 	end 	 	return out end  function parseWikidataURL(url) 	local id 	 	if url:match('^http[s]?://') then 		id = split(url, "Q") 		 		if id[2] then 			return "Q" .. id[2] 		end 	end 	 	return nil end  function parseDate(dateStr, precision) 	precision = precision or "d" 	 	local i, j, index, ptr 	local parts = {nil, nil, nil} 	 	if dateStr == nil then 		return parts[1], parts[2], parts[3]  -- year, month, day 	end 	 	-- 'T' for snak values, '/' for outputs with '/Julian' attached 	i, j = dateStr:find("[T/]") 	 	if i then 		dateStr = dateStr:sub(1, i-1) 	end 	 	local from = 1 	 	if dateStr:sub(1,1) == "-" then 		-- this is a negative number, look further ahead 		from = 2 	end 	 	index = 1 	ptr = 1 	 	i, j = dateStr:find("-", from) 	 	if i then 		-- year 		parts[index] = tonumber(mw.ustring.gsub(dateStr:sub(ptr, i-1), "^\+(.+)$", "%1"), 10)  -- remove '+' sign (explicitly give base 10 to prevent error) 		 		if parts[index] == -0 then 			parts[index] = tonumber("0")  -- for some reason, 'parts[index] = 0' may actually store '-0', so parse from string instead 		end 		 		if precision == "y" then 			-- we're done 			return parts[1], parts[2], parts[3]  -- year, month, day 		end 		 		index = index + 1 		ptr = i + 1 		 		i, j = dateStr:find("-", ptr) 		 		if i then 			-- month 			parts[index] = tonumber(dateStr:sub(ptr, i-1), 10) 			 			if precision == "m" then 				-- we're done 				return parts[1], parts[2], parts[3]  -- year, month, day 			end 			 			index = index + 1 			ptr = i + 1 		end 	end 	 	if dateStr:sub(ptr) ~= "" then 		-- day if we have month, month if we have year, or year 		parts[index] = tonumber(dateStr:sub(ptr), 10) 	end 	 	return parts[1], parts[2], parts[3]  -- year, month, day end  function datePrecedesDate(aY, aM, aD, bY, bM, bD) 	if aY == nil or bY == nil then 		return nil 	end 	aM = aM or 1 	aD = aD or 1 	bM = bM or 1 	bD = bD or 1 	 	if aY < bY then 		return true 	end 	 	if aY > bY then 		return false 	end 	 	if aM < bM then 		return true 	end 	 	if aM > bM then 		return false 	end 	 	if aD < bD then 		return true 	end 	 	return false end  function getHookName(param, index) 	if hookNames[param] then 		return hookNames[param][index] 	elseif param:len() > 2 then 		return hookNames[param:sub(1, 2).."\\d"][index] 	else 		return nil 	end end  function alwaysTrue() 	return true end  -- The following function parses a format string. -- -- The example below shows how a parsed string is structured in memory. -- Variables other than 'str' and 'child' are left out for clarity's sake. -- -- Example: -- "A %p B [%s[%q1]] C [%r] D" -- -- Structure: -- [ --   { --     str = "A " --   }, --   { --     str = "%p" --   }, --   { --     str = " B ", --     child = --     [ --       { --         str = "%s", --         child = --         [ --           { --             str = "%q1" --           } --         ] --       } --     ] --   }, --   { --     str = " C ", --     child = --     [ --       { --         str = "%r" --       } --     ] --   }, --   { --     str = " D" --   } -- ] -- function parseFormat(str) 	local chr, esc, param, root, cur, prev, new 	local params = {} 	 	local function newObject(array) 		local obj = {}  -- new object 		obj.str = "" 		 		array[#array + 1] = obj  -- array{object} 		obj.parent = array 		 		return obj 	end 	 	local function endParam() 		if param > 0 then 			if cur.str ~= "" then 				cur.str = "%"..cur.str 				cur.param = true 				params[cur.str] = true 				cur.parent.req[cur.str] = true 				prev = cur 				cur = newObject(cur.parent) 			end 			param = 0 		end 	end 	 	root = {}  -- array 	root.req = {} 	cur = newObject(root) 	prev = nil 	 	esc = false 	param = 0 	 	for i = 1, #str do 		chr = str:sub(i,i) 		 		if not esc then 			if chr == '\\' then 				endParam() 				esc = true 			elseif chr == '%' then 				endParam() 				if cur.str ~= "" then 					cur = newObject(cur.parent) 				end 				param = 2 			elseif chr == '[' then 				endParam() 				if prev and cur.str == "" then 					table.remove(cur.parent) 					cur = prev 				end 				cur.child = {}  -- new array 				cur.child.req = {} 				cur.child.parent = cur 				cur = newObject(cur.child) 			elseif chr == ']' then 				endParam() 				if cur.parent.parent then 					new = newObject(cur.parent.parent.parent) 					if cur.str == "" then 						table.remove(cur.parent) 					end 					cur = new 				end 			else 				if param > 1 then 					param = param - 1 				elseif param == 1 then 					if not chr:match('%d') then 						endParam() 					end 				end 				 				cur.str = cur.str .. replaceSpecialChar(chr) 			end 		else 			cur.str = cur.str .. chr 			esc = false 		end 		 		prev = nil 	end 	 	endParam() 	 	-- make sure that at least one required parameter has been defined 	if not next(root.req) then 		throwError("missing-required-parameter") 	end 	 	-- make sure that the separator parameter "%s" is not amongst the required parameters 	if root.req[parameters.separator] then 		throwError("extra-required-parameter", parameters.separator) 	end 	 	return root, params end  function sortOnRank(claims) 	local rankPos 	local ranks = {{}, {}, {}, {}}  -- preferred, normal, deprecated, (default) 	local sorted = {} 	 	for i, v in ipairs(claims) do 		rankPos = rankTable[v.rank] or 4 		ranks[rankPos][#ranks[rankPos] + 1] = v 	end 	 	sorted = ranks[1] 	sorted = mergeArrays(sorted, ranks[2]) 	sorted = mergeArrays(sorted, ranks[3]) 	 	return sorted end  -- if id == nil then item connected to current page is used function Config:getLabel(id, raw, link, short) 	local label = nil 	local title = nil 	local prefix= "" 	local lang 	 	if not id then 		id = mw.wikibase.getEntityIdForCurrentPage() 		 		if not id then 			return "" 		end 	end 	 	id = id:upper()  -- just to be sure 	 	if raw then 		-- check if given id actually exists 		if mw.wikibase.getEntity(id) then 			label = id 			 			if id:sub(1,1) == "P" then 				prefix = "Property:" 			end 		end 		 		prefix = "d:" .. prefix 		 		title = label  -- may be nil 	else 		-- try short name first if requested 		if short then 			label = p._property({p.aliasesP.shortName, [p.args.eid] = id})  -- get short name 			 			if label == "" then 				label = nil 			end 		end 		 		-- get label 		if not label then 			label, lang = mw.wikibase.getLabelWithLang(id) 			 			-- don't allow language fallback 			if lang ~= self.langCode then 				label = nil 			end 		end 	end 	 	if not label then 		label = "" 	elseif link then 		-- build a link if requested 		if not title then 			if id:sub(1,1) == "Q" then 				title = mw.wikibase.sitelink(id) 			elseif id:sub(1,1) == "P" then 				-- properties have no sitelink, link to Wikidata instead 				title = id 				prefix = "d:Property:" 			end 		end 		 		if title then 			label = buildWikilink(prefix .. title, label) 		end 	end 	 	return label end  function Config:getEditIcon() 	local value = "" 	local prefix = "" 	local front = " " 	local back = "" 	 	if self.entityID:sub(1,1) == "P" then 		prefix = "Property:" 	end 	 	if self.editAtEnd then 		front = '<span style="float:' 		 		if self.langObj:isRTL() then 			front = front .. 'left' 		else 			front = front .. 'right' 		end 		 		front = front .. '">' 		back = '</span>' 	end 	 	value = "[[File:Blue pencil.svg|frameless|text-top|10px|alt=" .. i18n['info']['edit-on-wikidata'] .. "|link=https://www.wikidata.org/wiki/" .. prefix .. self.entityID .. "?uselang=" .. self.langCode 	 	if self.propertyID then 		value = value .. "#" .. self.propertyID 	elseif self.inSitelinks then 		value = value .. "#sitelinks-wikipedia" 	end 	 	value = value .. "|" .. i18n['info']['edit-on-wikidata'] .. "]]" 	 	return front .. value .. back end  -- used to create the final output string when it's all done, so that for references the -- function extensionTag("ref", ...) is only called when they really ended up in the final output function Config:concatValues(valuesArray) 	local outString = "" 	local j, skip 	 	for i = 1, #valuesArray do 		-- check if this is a reference 		if valuesArray[i].refHash then 			j = i - 1 			skip = false 			 			-- skip this reference if it is part of a continuous row of references that already contains the exact same reference 			while valuesArray[j] and valuesArray[j].refHash do 				if valuesArray[i].refHash == valuesArray[j].refHash then 					skip = true 					break 				end 				j = j - 1 			end 			 			if not skip then 				-- add <ref> tag with the reference's hash as its name (to deduplicate references) 				outString = outString .. mw.getCurrentFrame():extensionTag("ref", valuesArray[i][1], {name = "wikidata-" .. valuesArray[i].refHash .. "-v" .. i18n['cite']['version']}) 			end 		else 			outString = outString .. valuesArray[i][1] 		end 	end 	 	return outString end  function Config:convertUnit(unit, raw, link, short, unitOnly) 	local space = " " 	local label = "" 	 	if unit == "" or unit == "1" then 		return nil 	end 	 	if unitOnly then 		space = "" 	end 	 	itemID = parseWikidataURL(unit) 	 	if itemID then 		if itemID == aliasesQ.percentage then 			return "%" 		else 			label = self:getLabel(itemID, raw, link, short) 			 			if label ~= "" then 				return space .. label 			end 		end 	end 	 	return "" end  function Config:getValue(snak, raw, link, short, anyLang, unitOnly, noSpecial) 	if snak.snaktype == 'value' then 		local datatype = snak.datavalue.type 		local subtype = snak.datatype 		local datavalue = snak.datavalue.value 		 		if datatype == 'string' then 			if subtype == 'url' and link then 				-- create link explicitly 				if raw then 					-- will render as a linked number like [1] 					return "[" .. datavalue .. "]" 				else 					return "[" .. datavalue .. " " .. datavalue .. "]" 				end 			elseif subtype == 'commonsMedia' then 				if link then 					return buildWikilink("c:File:" .. datavalue, datavalue) 				elseif not raw then 					return "[[File:" .. datavalue .. "]]" 				else 					return datavalue 				end 			elseif subtype == 'geo-shape' and link then 				return buildWikilink("c:" .. datavalue, datavalue) 			elseif subtype == 'math' and not raw then 				return mw.getCurrentFrame():extensionTag("math", datavalue) 			elseif subtype == 'external-id' and link then 				local url = p._property({p.aliasesP.formatterURL, [p.args.eid] = snak.property})  -- get formatter URL 				 				if url ~= "" then 					url = mw.ustring.gsub(url, "$1", datavalue) 					return "[" .. url .. " " .. datavalue .. "]" 				else 					return datavalue 				end 			else 				return datavalue 			end 		elseif datatype == 'monolingualtext' then 			if anyLang then 				return datavalue['text'], datavalue['language'] 			elseif datavalue['language'] == self.langCode then 				return datavalue['text'] 			else 				return nil 			end 		elseif datatype == 'quantity' then 			local value = "" 			local unit 			 			if not unitOnly then 				-- get value and strip + signs from front 				value = mw.ustring.gsub(datavalue['amount'], "^\+(.+)$", "%1") 				 				if raw then 					return value 				end 				 				-- replace decimal mark based on locale 				value = replaceDecimalMark(value) 				 				-- add delimiters for readability 				value = i18n.addDelimiters(value) 			end 			 			unit = self:convertUnit(datavalue['unit'], raw, link, short, unitOnly) 			 			if unit then 				value = value .. unit 			end 			 			return value 		elseif datatype == 'time' then 			local y, m, d, p, yDiv, yRound, yFull, value, calendarID, dateStr 			local yFactor = 1 			local sign = 1 			local prefix = "" 			local suffix = "" 			local mayAddCalendar = false 			local calendar = "" 			local precision = datavalue['precision'] 			 			if precision == 11 then 				p = "d" 			elseif precision == 10 then 				p = "m" 			else 				p = "y" 				yFactor = 10^(9-precision) 			end 			 			y, m, d = parseDate(datavalue['time'], p) 			 			if y < 0 then 				sign = -1 				y = y * sign 			end 			 			-- if precision is tens/hundreds/thousands/millions/billions of years 			if precision <= 8 then 				yDiv = y / yFactor 				 				-- if precision is tens/hundreds/thousands of years 				if precision >= 6 then 					mayAddCalendar = true 					 					if precision <= 7 then 						-- round centuries/millenniums up (e.g. 20th century or 3rd millennium) 						yRound = math.ceil(yDiv) 						 						if not raw then 							if precision == 6 then 								suffix = i18n['datetime']['suffixes']['millennium'] 							else 								suffix = i18n['datetime']['suffixes']['century'] 							end 							 							suffix = i18n.getOrdinalSuffix(yRound) .. suffix 						else 							-- if not verbose, take the first year of the century/millennium 							-- (e.g. 1901 for 20th century or 2001 for 3rd millennium) 							yRound = (yRound - 1) * yFactor + 1 						end 					else 						-- precision == 8 						-- round decades down (e.g. 2010s) 						yRound = math.floor(yDiv) * yFactor 						 						if not raw then 							prefix = i18n['datetime']['prefixes']['decade-period'] 							suffix = i18n['datetime']['suffixes']['decade-period'] 						end 					end 					 					if raw and sign < 0 then 						-- if BCE then compensate for "counting backwards" 						-- (e.g. -2019 for 2010s BCE, -2000 for 20th century BCE or -3000 for 3rd millennium BCE) 						yRound = yRound + yFactor - 1 					end 				else 					local yReFactor, yReDiv, yReRound 					 					-- round to nearest for tens of thousands of years or more 					yRound = math.floor(yDiv + 0.5) 					 					if yRound == 0 then 						if precision <= 2 and y ~= 0 then 							yReFactor = 1e6 							yReDiv = y / yReFactor 							yReRound = math.floor(yReDiv + 0.5) 							 							if yReDiv == yReRound then 								-- change precision to millions of years only if we have a whole number of them 								precision = 3 								yFactor = yReFactor 								yRound = yReRound 							end 						end 						 						if yRound == 0 then 							-- otherwise, take the unrounded (original) number of years 							precision = 5 							yFactor = 1 							yRound = y 							mayAddCalendar = true 						end 					end 					 					if precision >= 1 and y ~= 0 then 						yFull = yRound * yFactor 						 						yReFactor = 1e9 						yReDiv = yFull / yReFactor 						yReRound = math.floor(yReDiv + 0.5) 						 						if yReDiv == yReRound then 							-- change precision to billions of years if we're in that range 							precision = 0 							yFactor = yReFactor 							yRound = yReRound 						else 							yReFactor = 1e6 							yReDiv = yFull / yReFactor 							yReRound = math.floor(yReDiv + 0.5) 							 							if yReDiv == yReRound then 								-- change precision to millions of years if we're in that range 								precision = 3 								yFactor = yReFactor 								yRound = yReRound 							end 						end 					end 					 					if not raw then 						if precision == 3 then 							suffix = i18n['datetime']['suffixes']['million-years'] 						elseif precision == 0 then 							suffix = i18n['datetime']['suffixes']['billion-years'] 						else 							yRound = yRound * yFactor 							if yRound == 1 then 								suffix = i18n['datetime']['suffixes']['year'] 							else 								suffix = i18n['datetime']['suffixes']['years'] 							end 						end 					else 						yRound = yRound * yFactor 					end 				end 			else 				yRound = y 				mayAddCalendar = true 			end 			 			if mayAddCalendar then 				calendarID = parseWikidataURL(datavalue['calendarmodel']) 				 				if calendarID and calendarID == aliasesQ.prolepticJulianCalendar then 					if not raw then 						if link then 							calendar = " ("..buildWikilink(i18n['datetime']['julian-calendar'], i18n['datetime']['julian'])..")" 						else 							calendar = " ("..i18n['datetime']['julian']..")" 						end 					else 						calendar = "/"..i18n['datetime']['julian'] 					end 				end 			end 			 			if not raw then 				local ce = nil 				 				if sign < 0 then 					ce = i18n['datetime']['BCE'] 				elseif precision <= 5 then 					ce = i18n['datetime']['CE'] 				end 				 				if ce then 					if link then 						ce = buildWikilink(i18n['datetime']['common-era'], ce) 					end 					suffix = suffix .. " " .. ce 				end 				 				value = tostring(yRound) 				 				if m then 					dateStr = self.langObj:formatDate("F", "1-"..m.."-1") 					 					if d then 						if self.mdyDate then 							dateStr = dateStr .. " " .. d .. "," 						else 							dateStr = d .. " " .. dateStr 						end 					end 					 					value = dateStr .. " " .. value 				end 				 				value = prefix .. value .. suffix .. calendar 			else 				value = padZeros(yRound * sign, 4) 				 				if m then 					value = value .. "-" .. padZeros(m, 2) 					 					if d then 						value = value .. "-" .. padZeros(d, 2) 					end 				end 				 				value = value .. calendar 			end 			 			return value 		elseif datatype == 'globecoordinate' then 			-- logic from https://github.com/DataValues/Geo 			 			local precision, numDigits, strFormat, value, globe 			local latValue, latitude, latDegrees, latMinutes, latSeconds 			local lonValue, longitude, lonDegrees, lonMinutes, lonSeconds 			local latDirection, latDirectionN, latDirectionS, latDirectionEN 			local lonDirection, lonDirectionE, lonDirectionW, lonDirectionEN 			 			local latDirectionEN_N = "N" 			local latDirectionEN_S = "S" 			local lonDirectionEN_E = "E" 			local lonDirectionEN_W = "W" 			 			if not raw then 				latDirectionN = i18n['coord']['latitude-north'] 				latDirectionS = i18n['coord']['latitude-south'] 				lonDirectionE = i18n['coord']['longitude-east'] 				lonDirectionW = i18n['coord']['longitude-west'] 				 				degSymbol = i18n['coord']['degrees'] 				minSymbol = i18n['coord']['minutes'] 				secSymbol = i18n['coord']['seconds'] 				separator = i18n['coord']['separator'] 			else 				latDirectionN = latDirectionEN_N 				latDirectionS = latDirectionEN_S 				lonDirectionE = lonDirectionEN_E 				lonDirectionW = lonDirectionEN_W 				 				degSymbol = "/" 				minSymbol = "/" 				secSymbol = "/" 				separator = "/" 			end 			 			latitude = datavalue['latitude'] 			longitude = datavalue['longitude'] 			 			if latitude < 0 then 				latDirection = latDirectionS 				latDirectionEN = latDirectionEN_S 				latitude = math.abs(latitude) 			else 				latDirection = latDirectionN 				latDirectionEN = latDirectionEN_N 			end 			 			if longitude < 0 then 				lonDirection = lonDirectionW 				lonDirectionEN = lonDirectionEN_W 				longitude = math.abs(longitude) 			else 				lonDirection = lonDirectionE 				lonDirectionEN = lonDirectionEN_E 			end 			 			precision = datavalue['precision'] 			 			if not precision or precision == 0 then 				precision = 1 / 3600  -- precision unspecified, set to arcsecond 			end 			 			latitude = math.floor(latitude / precision + 0.5) * precision 			longitude = math.floor(longitude / precision + 0.5) * precision 			 			numDigits = math.ceil(-math.log10(3600 * precision)) 			 			if numDigits < 0 or numDigits == -0 then 				numDigits = tonumber("0")  -- for some reason, 'numDigits = 0' may actually store '-0', so parse from string instead 			end 			 			strFormat = "%." .. numDigits .. "f" 			 			-- use string.format() to strip decimal point followed by a zero (.0) for whole numbers 			latSeconds = tonumber(strFormat:format(math.floor(latitude * 3600 * 10^numDigits + 0.5) / 10^numDigits)) 			lonSeconds = tonumber(strFormat:format(math.floor(longitude * 3600 * 10^numDigits + 0.5) / 10^numDigits)) 			 			latMinutes = math.floor(latSeconds / 60) 			lonMinutes = math.floor(lonSeconds / 60) 			 			latSeconds = latSeconds - (latMinutes * 60) 			lonSeconds = lonSeconds - (lonMinutes * 60) 			 			latDegrees = math.floor(latMinutes / 60) 			lonDegrees = math.floor(lonMinutes / 60) 			 			latMinutes = latMinutes - (latDegrees * 60) 			lonMinutes = lonMinutes - (lonDegrees * 60) 			 			latValue = latDegrees .. degSymbol 			lonValue = lonDegrees .. degSymbol 			 			if precision < 1 then 				latValue = latValue .. latMinutes .. minSymbol 				lonValue = lonValue .. lonMinutes .. minSymbol 			end 			 			if precision < (1 / 60) then 				latSeconds = strFormat:format(latSeconds) 				lonSeconds = strFormat:format(lonSeconds) 				 				if not raw then 					-- replace decimal marks based on locale 					latSeconds = replaceDecimalMark(latSeconds) 					lonSeconds = replaceDecimalMark(lonSeconds) 				end 				 				latValue = latValue .. latSeconds .. secSymbol 				lonValue = lonValue .. lonSeconds .. secSymbol 			end 			 			latValue = latValue .. latDirection 			lonValue = lonValue .. lonDirection 			 			value = latValue .. separator .. lonValue 			 			if link then 				globe = parseWikidataURL(datavalue['globe']) 				 				if globe then 					globe = mw.wikibase.getEntity(globe):getLabel("en"):lower() 				else 					globe = "earth" 				end 				 				value = "[https://geohack.toolforge.org/geohack.php?language="..self.langCode.."&params="..latitude.."_"..latDirectionEN.."_"..longitude.."_"..lonDirectionEN.."_globe:"..globe.." "..value.."]" 			end 			 			return value 		elseif datatype == 'wikibase-entityid' then 			local label 			local itemID = datavalue['numeric-id'] 			 			if subtype == 'wikibase-item' then 				itemID = "Q" .. itemID 			elseif subtype == 'wikibase-property' then 				itemID = "P" .. itemID 			else 				return '<strong class="error">' .. errorText('unknown-data-type', subtype) .. '</strong>' 			end 			 			label = self:getLabel(itemID, raw, link, short) 			 			if label == "" then 				label = nil 			end 			 			return label 		else 			return '<strong class="error">' .. errorText('unknown-data-type', datatype) .. '</strong>' 		end 	elseif snak.snaktype == 'somevalue' and not noSpecial then 		if raw then 			return " "  -- single space represents 'somevalue' 		else 			return i18n['values']['unknown'] 		end 	elseif snak.snaktype == 'novalue' and not noSpecial then 		if raw then 			return ""  -- empty string represents 'novalue' 		else 			return i18n['values']['none'] 		end 	else 		return nil 	end end  function Config:getSingleRawQualifier(claim, qualifierID) 	local qualifiers 	 	if claim.qualifiers then qualifiers = claim.qualifiers[qualifierID] end 	 	if qualifiers and qualifiers[1] then 		return self:getValue(qualifiers[1], true)  -- raw = true 	else 		return nil 	end end  function Config:snakEqualsValue(snak, value) 	local snakValue = self:getValue(snak, true)  -- raw = true 	 	if snakValue and snak.snaktype == 'value' and snak.datavalue.type == 'wikibase-entityid' then value = value:upper() end 	 	return snakValue == value end  function Config:setRank(rank) 	local rankPos 	 	if rank == p.flags.best then 		self.bestRank = true 		self.flagBest = true  -- mark that 'best' flag was given 		return 	end 	 	if rank:sub(1,9) == p.flags.preferred then 		rankPos = 1 	elseif rank:sub(1,6) == p.flags.normal then 		rankPos = 2 	elseif rank:sub(1,10) == p.flags.deprecated then 		rankPos = 3 	else 		return 	end 	 	-- one of the rank flags was given, check if another one was given before 	if not self.flagRank then 		self.ranks = {false, false, false}  -- no other rank flag given before, so unset ranks 		self.bestRank = self.flagBest       -- unsets bestRank only if 'best' flag was not given before 		self.flagRank = true                -- mark that a rank flag was given 	end 	 	if rank:sub(-1) == "+" then 		for i = rankPos, 1, -1 do 			self.ranks[i] = true 		end 	elseif rank:sub(-1) == "-" then 		for i = rankPos, #self.ranks do 			self.ranks[i] = true 		end 	else 		self.ranks[rankPos] = true 	end end  function Config:setPeriod(period) 	local periodPos 	 	if period == p.flags.future then 		periodPos = 1 	elseif period == p.flags.current then 		periodPos = 2 	elseif period == p.flags.former then 		periodPos = 3 	else 		return 	end 	 	-- one of the period flags was given, check if another one was given before 	if not self.flagPeriod then 		self.periods = {false, false, false}  -- no other period flag given before, so unset periods 		self.flagPeriod = true                -- mark that a period flag was given 	end 	 	self.periods[periodPos] = true end  function Config:qualifierMatches(claim, id, value) 	local qualifiers 	 	if claim.qualifiers then qualifiers = claim.qualifiers[id] end 	if qualifiers then 		for i, v in pairs(qualifiers) do 			if self:snakEqualsValue(v, value) then 				return true 			end 		end 	elseif value == "" then 		-- if the qualifier is not present then treat it the same as the special value 'novalue' 		return true 	end 	 	return false end  function Config:rankMatches(rankPos) 	if self.bestRank then 		return (self.ranks[rankPos] and self.foundRank >= rankPos) 	else 		return self.ranks[rankPos] 	end end  function Config:timeMatches(claim) 	local startTime = nil 	local startTimeY = nil 	local startTimeM = nil 	local startTimeD = nil 	local endTime = nil 	local endTimeY = nil 	local endTimeM = nil 	local endTimeD = nil 	 	if self.periods[1] and self.periods[2] and self.periods[3] then 		-- any time 		return true 	end 	 	local now = os.date('!*t') 	 	startTime = self:getSingleRawQualifier(claim, p.aliasesP.startTime) 	if startTime and startTime ~= "" and startTime ~= " " then 		startTimeY, startTimeM, startTimeD = parseDate(startTime) 	end 	 	endTime = self:getSingleRawQualifier(claim, p.aliasesP.endTime) 	if endTime and endTime ~= "" and endTime ~= " " then 		endTimeY, endTimeM, endTimeD = parseDate(endTime) 	elseif endTime == " " then 		-- end time is 'unknown', assume it is somewhere in the past; 		-- we can do this by taking the current date as a placeholder for the end time 		endTimeY = now['year'] 		endTimeM = now['month'] 		endTimeD = now['day'] 	end 	 	if startTimeY ~= nil and endTimeY ~= nil and datePrecedesDate(endTimeY, endTimeM, endTimeD, startTimeY, startTimeM, startTimeD) then 		-- invalidate end time if it precedes start time 		endTimeY = nil 		endTimeM = nil 		endTimeD = nil 	end 	 	if self.periods[1] then 		-- future 		if startTimeY and datePrecedesDate(now['year'], now['month'], now['day'], startTimeY, startTimeM, startTimeD) then 			return true 		end 	end 	 	if self.periods[2] then 		-- current 		if (startTimeY == nil or not datePrecedesDate(now['year'], now['month'], now['day'], startTimeY, startTimeM, startTimeD)) and 		   (endTimeY == nil or datePrecedesDate(now['year'], now['month'], now['day'], endTimeY, endTimeM, endTimeD)) then 			return true 		end 	end 	 	if self.periods[3] then 		-- former 		if endTimeY and not datePrecedesDate(now['year'], now['month'], now['day'], endTimeY, endTimeM, endTimeD) then 			return true 		end 	end 	 	return false end  function Config:processFlag(flag) 	if not flag then 		return false 	else 		flag = mw.text.trim(flag) 	end 	 	if flag == p.flags.linked then 		self.curState.linked = true 		return true 	elseif flag == p.flags.raw then 		self.curState.rawValue = true 		 		if self.curState == self.states[parameters.reference] then 			-- raw reference values end with periods and require a separator (other than none) 			self.separators["sep%r"][1] = {" "} 		end 		 		return true 	elseif flag == p.flags.short then 		self.curState.shortName = true 		return true 	elseif flag == p.flags.multilanguage then 		self.curState.anyLanguage = true 		return true 	elseif flag == p.flags.unit then 		self.curState.unitOnly = true 		return true 	elseif flag == p.flags.mdy then 		self.mdyDate = true 		return true 	elseif flag == p.flags.single then 		self.singleClaim = true 		return true 	elseif flag == p.flags.sourced then 		self.sourcedOnly = true 		return true 	elseif flag == p.flags.edit then 		self.editable = true 		return true 	elseif flag == p.flags.editAtEnd then 		self.editable = true 		self.editAtEnd = true 		return true 	elseif flag == p.flags.best or flag:match('^'..p.flags.preferred..'[+-]?$') or flag:match('^'..p.flags.normal..'[+-]?$') or flag:match('^'..p.flags.deprecated..'[+-]?$') then 		self:setRank(flag) 		return true 	elseif flag == p.flags.future or flag == p.flags.current or flag == p.flags.former then 		self:setPeriod(flag) 		return true 	elseif flag == "" then 		-- ignore empty flags and carry on 		return true 	else 		return false 	end end  function Config:processFlagOrCommand(flag) 	local param = "" 	 	if not flag then 		return false 	else 		flag = mw.text.trim(flag) 	end 	 	if flag == p.claimCommands.property or flag == p.claimCommands.properties then 		param = parameters.property 	elseif flag == p.claimCommands.qualifier or flag == p.claimCommands.qualifiers then 		self.states.qualifiersCount = self.states.qualifiersCount + 1 		param = parameters.qualifier .. self.states.qualifiersCount 		self.separators["sep"..param] = {copyTable(defaultSeparators["sep%q\\d"])} 	elseif flag == p.claimCommands.reference or flag == p.claimCommands.references then 		param = parameters.reference 	else 		return self:processFlag(flag) 	end 	 	if self.states[param] then 		return false 	end 	 	-- create a new state for each command 	self.states[param] = State.new(self) 	 	-- use "%x" as the general parameter name 	self.states[param].parsedFormat = parseFormat(parameters.general)  -- will be overwritten for param=="%p" 	 	-- set the separator 	self.states[param].separator = self.separators["sep"..param]  -- will be nil for param=="%p", which will be set separately 	 	if flag:sub(-1) ~= 's' then 		self.states[param].singleValue = true 	end 	 	self.curState = self.states[param] 	 	return true end  function Config:processSeparators(args) 	local sep 	 	for i, v in pairs(self.separators) do 		if args[i] then 			sep = replaceSpecialChars(args[i]) 			 			if sep ~= "" then 				self.separators[i][1] = {sep} 			else 				self.separators[i][1] = nil 			end 		end 	end end  function Config:setFormatAndSeparators(state, parsedFormat) 	state.parsedFormat = parsedFormat 	state.separator = self.separators["sep"] 	state.movSeparator = self.separators["sep"..parameters.separator] 	state.puncMark = self.separators["punc"] end  -- determines if a claim has references by prefetching them from the claim using getReferences, -- which applies some filtering that determines if a reference is actually returned, -- and caches the references for later use function State:isSourced(claim) 	self.conf.prefetchedRefs = self:getReferences(claim) 	return (#self.conf.prefetchedRefs > 0) end  function State:resetCaches() 	-- any prefetched references of the previous claim must not be used 	self.conf.prefetchedRefs = nil end  function State:claimMatches(claim) 	local matches, rankPos 	 	-- first of all, reset any cached values used for the previous claim 	self:resetCaches() 	 	-- if a property value was given, check if it matches the claim's property value 	if self.conf.propertyValue then 		matches = self.conf:snakEqualsValue(claim.mainsnak, self.conf.propertyValue) 	else 		matches = true 	end 	 	-- if any qualifier values were given, check if each matches one of the claim's qualifier values 	for i, v in pairs(self.conf.qualifierIDsAndValues) do 		matches = (matches and self.conf:qualifierMatches(claim, i, v)) 	end 	 	-- check if the claim's rank and time period match 	rankPos = rankTable[claim.rank] or 4 	matches = (matches and self.conf:rankMatches(rankPos) and self.conf:timeMatches(claim)) 	 	-- if only claims with references must be returned, check if this one has any 	if self.conf.sourcedOnly then 		matches = (matches and self:isSourced(claim))  -- prefetches and caches references 	end 	 	return matches, rankPos end  function State:out() 	local result  -- collection of arrays with value objects 	local valuesArray  -- array with value objects 	local sep = nil  -- value object 	local out = {}  -- array with value objects 	 	local function walk(formatTable, result) 		local valuesArray = {}  -- array with value objects 		 		for i, v in pairs(formatTable.req) do 			if not result[i] or not result[i][1] then 				-- we've got no result for a parameter that is required on this level, 				-- so skip this level (and its children) by returning an empty result 				return {} 			end 		end 		 		for i, v in ipairs(formatTable) do 			if v.param then 				valuesArray = mergeArrays(valuesArray, result[v.str]) 			elseif v.str ~= "" then 				valuesArray[#valuesArray + 1] = {v.str} 			end 			 			if v.child then 				valuesArray = mergeArrays(valuesArray, walk(v.child, result)) 			end 		end 		 		return valuesArray 	end 	 	-- iterate through the results from back to front, so that we know when to add separators 	for i = #self.results, 1, -1 do 		result = self.results[i] 		 		-- if there is already some output, then add the separators 		if #out > 0 then 			sep = self.separator[1]  -- fixed separator 			result[parameters.separator] = {self.movSeparator[1]}  -- movable separator 		else 			sep = nil 			result[parameters.separator] = {self.puncMark[1]}  -- optional punctuation mark 		end 		 		valuesArray = walk(self.parsedFormat, result) 		 		if #valuesArray > 0 then 			if sep then 				valuesArray[#valuesArray + 1] = sep 			end 			 			out = mergeArrays(valuesArray, out) 		end 	end 	 	-- reset state before next iteration 	self.results = {} 	 	return out end  -- level 1 hook function State:getProperty(claim) 	local value = {self.conf:getValue(claim.mainsnak, self.rawValue, self.linked, self.shortName, self.anyLanguage, self.unitOnly)}  -- create one value object 	 	if #value > 0 then 		return {value}  -- wrap the value object in an array and return it 	else 		return {}  -- return empty array if there was no value 	end end  -- level 1 hook function State:getQualifiers(claim, param) 	local qualifiers 	 	if claim.qualifiers then qualifiers = claim.qualifiers[self.conf.qualifierIDs[param]] end 	if qualifiers then 		-- iterate through claim's qualifier statements to collect their values; 		-- return array with multiple value objects 		return self.conf.states[param]:iterate(qualifiers, {[parameters.general] = hookNames[parameters.qualifier.."\\d"][2], count = 1})  -- pass qualifier state with level 2 hook 	else 		return {}  -- return empty array 	end end  -- level 2 hook function State:getQualifier(snak) 	local value = {self.conf:getValue(snak, self.rawValue, self.linked, self.shortName, self.anyLanguage, self.unitOnly)}  -- create one value object 	 	if #value > 0 then 		return {value}  -- wrap the value object in an array and return it 	else 		return {}  -- return empty array if there was no value 	end end  -- level 1 hook function State:getAllQualifiers(claim, param, result, hooks) 	local out = {}  -- array with value objects 	local sep = self.conf.separators["sep"..parameters.qualifier][1]  -- value object 	 	-- iterate through the output of the separate "qualifier(s)" commands 	for i = 1, self.conf.states.qualifiersCount do 		 		-- if a hook has not been called yet, call it now 		if not result[parameters.qualifier..i] then 			self:callHook(parameters.qualifier..i, hooks, claim, result) 		end 		 		-- if there is output for this particular "qualifier(s)" command, then add it 		if result[parameters.qualifier..i] and result[parameters.qualifier..i][1] then 			 			-- if there is already some output, then add the separator 			if #out > 0 and sep then 				out[#out + 1] = sep 			end 			 			out = mergeArrays(out, result[parameters.qualifier..i]) 		end 	end 	 	return out end  -- level 1 hook function State:getReferences(claim) 	if self.conf.prefetchedRefs then 		-- return references that have been prefetched by isSourced 		return self.conf.prefetchedRefs 	end 	 	if claim.references then 		-- iterate through claim's reference statements to collect their values; 		-- return array with multiple value objects 		return self.conf.states[parameters.reference]:iterate(claim.references, {[parameters.general] = hookNames[parameters.reference][2], count = 1})  -- pass reference state with level 2 hook 	else 		return {}  -- return empty array 	end end  -- level 2 hook function State:getReference(statement) 	local key, citeWeb, citeQ, label 	local params = {} 	local citeParams = {['web'] = {}, ['q'] = {}} 	local citeMismatch = {} 	local useCite = nil 	local useParams = nil 	local value = "" 	local ref = {} 	 	if statement.snaks then 		-- don't include "imported from", which is added by a bot 		if statement.snaks[p.aliasesP.importedFrom] then 			statement.snaks[p.aliasesP.importedFrom] = nil 		end 		 		-- don't include "language" if it is equal to the local one 		if self:getReferenceDetail(statement.snaks, p.aliasesP.language) == self.conf.langName then 			statement.snaks[p.aliasesP.language] = nil 		end 		 		-- retrieve all the parameters 		for i in pairs(statement.snaks) do 			label = "" 			 			-- multiple authors may be given 			if i == p.aliasesP.author then 				params[i] = self:getReferenceDetails(statement.snaks, i, false, self.linked, true)  -- link = true/false, anyLang = true 			else 				params[i] = {self:getReferenceDetail(statement.snaks, i, false, (self.linked or (i == p.aliasesP.statedIn)) and (statement.snaks[i][1].datatype ~= 'url'), true)}  -- link = true/false, anyLang = true 			end 			 			if #params[i] == 0 then 				params[i] = nil 			else 				if statement.snaks[i][1].datatype == 'external-id' then 					key = "external-id" 					label = self.conf:getLabel(i) 					 					if label ~= "" then 						label = label .. " " 					end 				else 					key = i 				end 				 				-- add the parameter to each matching type of citation 				for j in pairs(citeParams) do 					-- do so if there was no mismatch with a previous parameter 					if not citeMismatch[j] then 						-- check if this parameter is not mismatching itself 						if i18n['cite'][j][key] then 							-- continue if an option is available in the corresponding cite template 							if i18n['cite'][j][key] ~= "" then 								citeParams[j][i18n['cite'][j][key]] = label .. params[i][1] 								 								-- if there are multiple parameter values (authors), add those too 								for k=2, #params[i] do 									citeParams[j][i18n['cite'][j][key]..k] = label .. params[i][k] 								end 							end 						else 							citeMismatch[j] = true 						end 					end 				end 			end 		end 		 		-- get title of general template for citing web references 		citeWeb = split(mw.wikibase.sitelink(aliasesQ.citeWeb) or "", ":")[2]  -- split off namespace from front 		 		-- get title of template that expands stated-in references into citations 		citeQ = split(mw.wikibase.sitelink(aliasesQ.citeQ) or "", ":")[2]  -- split off namespace from front 		 		-- (1) use the general template for citing web references if there is a match and if at least both "reference URL" and "title" are present 		if citeWeb and not citeMismatch['web'] and citeParams['web'][i18n['cite']['web'][p.aliasesP.referenceURL]] and citeParams['web'][i18n['cite']['web'][p.aliasesP.title]] then 			useCite = citeWeb 			useParams = citeParams['web'] 			 		-- (2) use the template that expands stated-in references into citations if there is a match and if at least "stated in" is present 		elseif citeQ and not citeMismatch['q'] and citeParams['q'][i18n['cite']['q'][p.aliasesP.statedIn]] then 			-- we need the raw "stated in" Q-identifier for the this template 			citeParams['q'][i18n['cite']['q'][p.aliasesP.statedIn]] = self:getReferenceDetail(statement.snaks, p.aliasesP.statedIn, true)  -- raw = true 			 			useCite = citeQ 			useParams = citeParams['q'] 		end 		 		if useCite and useParams then 			-- if this module is being substituted then build a regular template call, otherwise expand the template 			if mw.isSubsting() then 				for i, v in pairs(useParams) do 					value = value .. "|" .. i .. "=" .. v 				end 				 				value = "{{" .. useCite .. value .. "}}" 			else 				value = mw.getCurrentFrame():expandTemplate{title=useCite, args=useParams} 			end 			 		-- (3) else, do some default rendering of name-value pairs, but only if at least "stated in", "reference URL" or "title" is present 		elseif params[p.aliasesP.statedIn] or params[p.aliasesP.referenceURL] or params[p.aliasesP.title] then 			citeParams['default'] = {} 			 			-- start by adding authors up front 			if params[p.aliasesP.author] and #params[p.aliasesP.author] > 0 then 				citeParams['default'][#citeParams['default'] + 1] = table.concat(params[p.aliasesP.author], " & ") 			end 			 			-- combine "reference URL" and "title" into one link if both are present 			if params[p.aliasesP.referenceURL] and params[p.aliasesP.title] then 				citeParams['default'][#citeParams['default'] + 1] = '[' .. params[p.aliasesP.referenceURL][1] .. ' "' .. params[p.aliasesP.title][1] .. '"]' 			elseif params[p.aliasesP.referenceURL] then 				citeParams['default'][#citeParams['default'] + 1] = params[p.aliasesP.referenceURL][1] 			elseif params[p.aliasesP.title] then 				citeParams['default'][#citeParams['default'] + 1] = '"' .. params[p.aliasesP.title][1] .. '"' 			end 			 			-- then add "stated in" 			if params[p.aliasesP.statedIn] then 				citeParams['default'][#citeParams['default'] + 1] = "''" .. params[p.aliasesP.statedIn][1] .. "''" 			end 			 			-- remove previously added parameters so that they won't be added a second time 			params[p.aliasesP.author] = nil 			params[p.aliasesP.referenceURL] = nil 			params[p.aliasesP.title] = nil 			params[p.aliasesP.statedIn] = nil 			 			-- add the rest of the parameters 			for i, v in pairs(params) do 				i = self.conf:getLabel(i) 				 				if i ~= "" then 					citeParams['default'][#citeParams['default'] + 1] = i .. ": " .. v[1] 				end 			end 			 			value = table.concat(citeParams['default'], "; ") 			 			if value ~= "" then 				value = value .. "." 			end 		end 		 		if value ~= "" then 			value = {value}  -- create one value object 			 			if not self.rawValue then 				-- this should become a <ref> tag, so safe the reference's hash for later 				value.refHash = statement.hash 			end 			 			ref = {value}  -- wrap the value object in an array 		end 	end 	 	return ref end  -- gets a detail of one particular type for a reference function State:getReferenceDetail(snaks, dType, raw, link, anyLang) 	local switchLang = anyLang 	local value = nil 	 	if not snaks[dType] then 		return nil 	end 	 	-- if anyLang, first try the local language and otherwise any language 	repeat 		for i, v in ipairs(snaks[dType]) do 			value = self.conf:getValue(v, raw, link, false, anyLang and not switchLang, false, true)  -- noSpecial = true 			 			if value then 				break 			end 		end 		 		if value or not anyLang then 			break 		end 		 		switchLang = not switchLang 	until anyLang and switchLang 	 	return value end  -- gets the details of one particular type for a reference function State:getReferenceDetails(snaks, dType, raw, link, anyLang) 	local values = {} 	 	if not snaks[dType] then 		return {} 	end 	 	for i, v in ipairs(snaks[dType]) do 		-- if nil is returned then it will not be added to the table 		values[#values + 1] = self.conf:getValue(v, raw, link, false, anyLang, false, true)  -- noSpecial = true 	end 	 	return values end  -- level 1 hook function State:getAlias(object) 	local value = object.value 	local title = nil 	 	if value and self.linked then 		if self.conf.entityID:sub(1,1) == "Q" then 			title = mw.wikibase.sitelink(self.conf.entityID) 		elseif self.conf.entityID:sub(1,1) == "P" then 			title = "d:Property:" .. self.conf.entityID 		end 		 		if title then 			value = buildWikilink(title, value) 		end 	end 	 	value = {value}  -- create one value object 	 	if #value > 0 then 		return {value}  -- wrap the value object in an array and return it 	else 		return {}  -- return empty array if there was no value 	end end  -- level 1 hook function State:getBadge(value) 	value = self.conf:getLabel(value, self.rawValue, self.linked, self.shortName) 	 	if value == "" then 		value = nil 	end 	 	value = {value}  -- create one value object 	 	if #value > 0 then 		return {value}  -- wrap the value object in an array and return it 	else 		return {}  -- return empty array if there was no value 	end end  function State:callHook(param, hooks, statement, result) 	local valuesArray, refHash 	 	-- call a parameter's hook if it has been defined and if it has not been called before 	if not result[param] and hooks[param] then 		valuesArray = self[hooks[param]](self, statement, param, result, hooks)  -- array with value objects 		 		-- add to the result 		if #valuesArray > 0 then 			result[param] = valuesArray 			result.count = result.count + 1 		else 			result[param] = {}  -- an empty array to indicate that we've tried this hook already 			return true  -- miss == true 		end 	end 	 	return false end  -- iterate through claims, claim's qualifiers or claim's references to collect values function State:iterate(statements, hooks, matchHook) 	matchHook = matchHook or alwaysTrue 	 	local matches = false 	local rankPos = nil 	local result, gotRequired 	 	for i, v in ipairs(statements) do