From Wikipedia, the free encyclopedia

-- version 20210304 from master @cawiki



local p = {}



-- Initialization of variables --------------------



local i18n = {						-- internationalisation at [[Module:Wikidata/i18n]]

	"errors" = {

		"property-not-found" = "Property not found.",

		"qualifier-not-found" = "Qualifier not found.",

	},

	

	"datetime" = {

		-- $1 is a placeholder for the actual number

		"beforenow" = "$1 BCE",	-- how to format negative numbers for precisions 0 to 5

		"afternow" = "$1 CE",		-- how to format positive numbers for precisions 0 to 5

		"bc" = "$1 BCE",			-- how print negative years

		"ad" = "$1",				-- how print 1st century AD dates

		

		0 = "$1 billion years",	-- precision: billion years

		1 = "$100 million years",	-- precision: hundred million years

		2 = "$10 million years",	-- precision: ten million years

		3 = "$1 million years",	-- precision: million years

		4 = "$100000 years",		-- precision: hundred thousand years; thousand separators added afterwards

		5 = "$10000 years",		-- precision: ten thousand years; thousand separators added afterwards

		6 = "$1 millennium",		-- precision: millennium

		7 = "$1 century",			-- precision: century

		8 = "$1s",				-- precision: decade

		-- the following use the format of #time parser function

		9 = "Y",					-- precision: year, 

		10 = "F Y",				-- precision: month

		11 = "F j, Y",			-- precision: day

		

		"hms" = {["hours" = "h", "minutes" = "m", "seconds" = "s"},	-- duration: xh xm xs

	},

	

	"years-old" = {

		"singular" = "",			-- year old, as in {{PLURAL:$1|singular|plural}}

		"plural" = "",			-- years old

		"paucal" = "",			-- for languages with 3 plural forms as in {{PLURAL:$1|singular|paucal|plural}}

	},

	

	"cite" = {					-- cite parameters

		"title" = "title",

		"author" = "author",

		"date" = "date",

		"pages" = "pages",

		"language" = "language",

		-- cite web parameters

		"url" = "url",

		"website" = "website",

		"access-date" = "access-date",

		"archive-url" = "archive-url",

		"archive-date" = "archive-date",

		"publisher" = "publisher",

		"quote" = "quote",

		-- cite journal parameters

		"work" = "work",

		"issue" = "issue",

		"issn" = "issn",

		"doi" = "doi"

	},

	

	-- default local wiki settings

	"addpencil" = false, -- adds a pencil icon linked to Wikidata statement, planned to overwrite by Wikidata Bridge

	"categorylabels" = "", -- Category:Pages with Wikidata labels not translated (void for no local category)

	"categoryprop" = "", -- Category:Pages using Wikidata property $1 (void for no local category)

	"categoryref" = "", -- Category:Pages with references from Wikidata (void for no local category)

	"addfallback" = {} -- additional fallback language codes

}



local cases = {} -- functions for local grammatical cases defined at [[Module:Wikidata/i18n]]



local required = ... -- variadic arguments from require function

local wiki = 

{

	langcode = mw.language.getContentLanguage().code,

	module_title = required or mw.getCurrentFrame():getTitle()

}



local untranslated -- used in infobox modules: nil or true

local _ -- variable for unused returned values, avoiding globals



-- Module local functions --------------------------------------------



-- Credit to http://stackoverflow.com/a/1283608/2644759, cc-by-sa 3.0

local function tableMerge(t1, t2)

	for k, v in pairs(t2) do

		if type(v) == "table" then

			if type(t1k or false) == "table" then

				tableMerge(t1k or {}, t2k or {})

			else

				t1k = v

			end

		else

			t1k = v

		end

	end

	return t1

end



local function loadI18n(lang)

	local exist, res = pcall(require, wiki.module_title .. "/i18n")

	if exist and next(res) ~= nil then

		tableMerge(i18n, res.i18n)

		cases = res.cases

	end

	if lang ~= wiki.langcode then

		exist, res = pcall(require, wiki.module_title .. "/i18n/" .. lang)

		if exist and next(res) ~= nil then

			tableMerge(i18n, res.i18n)

			tableMerge(cases, res.cases)

		end

	end

end



-- Table of language codes: requested or default and its fallbacks

local function findLang(langcode)

	if mw.language.isKnownLanguageTag(langcode or '') == false then

		local cframe = mw.getCurrentFrame()

		local pframe = cframe:getParent()

		langcode = pframe and pframe.args.lang

		if mw.language.isKnownLanguageTag(langcode or '') == false then

			if not mw.title.getCurrentTitle().isContentPage then

				langcode = cframe:preprocess('{{int:lang}}')

			end

			if mw.language.isKnownLanguageTag(langcode or '') == false then

				langcode = wiki.langcode

			end

		end

	end

	

	loadI18n(langcode)

	

	local languages = mw.language.getFallbacksFor(langcode)

	table.insert(languages, 1, langcode)

	if langcode == wiki.langcode then

		for _, l in ipairs(i18n.addfallback) do

			table.insert(languages, l)

		end

	end

	

	return languages

end



-- Argument is 'set' when it exists (not nil) or when it is not an empty string.

local function isSet(var)

	return not (var == nil or (type(var) == 'string' and mw.text.trim(var) == ''))

end



-- Set local case to a label

local function case(localcase, label, ...)

	if not isSet(label) then return label end

	

	if type(localcase) == "function" then

		return localcase(label)

	elseif localcase == "smallcaps" then

		return '<span style="font-variant: small-caps;">' .. label .. '</span>'

	elseif caseslocalcase then

		return caseslocalcase](label, ...)

	end

	

	return label

end



-- get safely a serialized snak

local function getSnak(statement, snaks)

	local ret = statement

	for i, v in ipairs(snaks) do

		if not ret then return end

		ret = retv

	end

	return ret

end



-- mw.wikibase.getLabelWithLang or getLabelByLang with a table of languages

local function getLabelByLangs(id, languages)

	local label

	local lang

	for _, l in ipairs(languages) do

		if l == wiki.langcode then

			-- using getLabelWithLang when possible instead of getLabelByLang, do not solve redirects pending phab:T157868

			label, l = mw.wikibase.getLabelWithLang(id)

		else

			label = mw.wikibase.getLabelByLang(id, l)

		end

		if label then

			lang = l

			break

		end

	end

	return label, lang

end



-- getBestStatements if bestrank=true, else getAllStatements with no deprecated

local function getStatements(entityId, property, bestrank)

	local claims = {}

	if not (entityId and mw.ustring.match(property, "^P%d+$")) then return claims end

	if bestrank then

		claims = mw.wikibase.getBestStatements(entityId, property)

	else

		local allclaims = mw.wikibase.getAllStatements(entityId, property)

		for _, c in ipairs(allclaims) do

			if c.rank ~= "deprecated" then

				table.insert(claims, c)

			end

		end

	end

	return claims

end



-- Is gender femenine? true or false

local function feminineGender(id)

	local claims = mw.wikibase.getBestStatements(id or mw.wikibase.getEntityIdForCurrentPage(),'P21')

	local gender_id = getSnak(claims, {1, "mainsnak", "datavalue", "value", "id"})

	if gender_id == "Q6581072" or gender_id == "Q1052281" or gender_id == "Q43445" then -- female, transgender female, female organism

		return true

	end

	return false

end



-- Fetch female form of label

local function feminineForm(id, lang)

	local feminine_claims = getStatements(id, 'P2521')

	for _, feminine_claim in ipairs(feminine_claims) do

		if getSnak(feminine_claim, {'mainsnak', 'datavalue', 'value', 'language'}) == lang then

			return feminine_claim.mainsnak.datavalue.value.text

		end

	end

end



-- Add an icon for no label in requested language

local function addLabelIcon(label_id, lang, uselang, icon)

	local ret_lang, ret_icon = '', ''

	if icon then

		if lang and lang ~= uselang then

			ret_lang = " <sup>(" .. lang .. ")</sup>"

		end

		if label_id and (lang == nil or lang ~= uselang) then

			local namespace = ''

			if string.sub(label_id, 1, 1) == 'P' then

				namespace = 'Property:'

			end

			ret_icon = " [[File:Noun Project label icon 1116097 cc mirror.svg|10px|baseline|"

				.. mw.message.new('Translate-taction-translate'):inLanguage(uselang):plain()

				.. "|link=https://www.wikidata.org/wiki/" .. namespace .. label_id .. "?uselang=" .. uselang .. "]]"

			untranslated = true

		end

		if isSet(i18n.categorylabels) and lang ~= uselang and uselang == wiki.langcode then

			ret_icon = ret_icon .. '[[' .. i18n.categorylabels .. (lang and ']]' or '/Q]]')

		end

	end

	return ret_lang .. ret_icon

end



-- editicon values: true/false (no=false), right, void defaults to i18n.addpencil

-- labelicon only by parameter

local function setIcons(arg, parg)

	local val = arg == nil and parg or arg

	local edit_icon, label_icon

	if not isSet(val) then

		edit_icon, label_icon = i18n.addpencil, true

	elseif val == false or val == "false" or val == "no" then

		edit_icon, label_icon = false, false

	else

		edit_icon, label_icon = val, true

	end

	return edit_icon, label_icon

end



-- Add an icon for editing a statement with requirements for Wikidata Bridge

local function addEditIcon(parameters)

	local ret = ''

	if parameters.editicon and parameters.id and parameters.property then

		local icon_style = parameters.editicon == "right" and ' style="float: right;"' or ''

		ret = ' <span class="penicon" data-bridge-edit-flow="single-best-value"' .. icon_style .. '>'

			.. "[[File:Arbcom ru editing.svg|10px|baseline|"

			.. string.gsub(mw.message.new('Wikibase-client-data-bridge-bailout-suggestion-go-to-repo-button'):inLanguage(parameters.lang1]):plain(), '{{WBREPONAME}}', 'Wikidata')

			.. "|link=https://www.wikidata.org/wiki/" .. parameters.id .. "?uselang=" .. parameters.lang1 .. "#" .. parameters.property .. "]]"

			.. "</span>"

		if isSet(i18n.categoryprop) then

			ret = ret .. "[[" .. string.gsub(i18n.categoryprop, '$1', parameters.property) .. "]]"

		end

	end

	return ret

end

-- add edit icon to the last element of a table

local function addEditIconTable(thetable, parameters)

	if #thetable == 0 or parameters.editicon == false then

		return thetable

	end

	local last_element = thetable#thetable

	local the_icon = addEditIcon(parameters)

	-- add it before last html closing tags

	local tags = ''

	local rev_element = string.reverse(last_element)

	for tag in string.gmatch(rev_element, '(>%l+/<)') do

		if string.match(rev_element, '^' .. tags .. tag) then

			tags = tags .. tag

		else

			break

		end

	end

	local last_tags = string.reverse(tags)

	local offset = string.find(last_element, last_tags .. '$')

	if offset then

		thetable#thetable = string.sub(last_element, 1, offset - 1) .. the_icon .. last_tags

	else

		thetable#thetable = last_element .. the_icon

	end

	return thetable

end



-- Escape Lua captures

local function captureEscapes(text)

	return mw.ustring.gsub(text, "(%%%d)", "%%%1")

end



-- expandTemplate or callParserFunction

local function expandBraces(text, formatting)

	if text == nil or formatting == nil then return text end

	-- only expand braces if provided in argument, not included in value as in Q1164668

	if mw.ustring.find(formatting, '{{', 1, true) == nil then return text end

	if type(text) ~= "string" then

		text = tostring(text)

	end

	

	for braces in mw.ustring.gmatch(text, "{{(.-)}}") do

		local parts = mw.text.split(braces, "|")

		local title_part = parts1

		local parameters = {}

		for i = 2, #parts do

			local subparts = mw.ustring.find(partsi], "=")

			if subparts then

				local param_name = mw.ustring.sub(partsi], 1, subparts - 1)

				local param_value = mw.ustring.sub(partsi], subparts + 1, -1)

				-- reconstruct broken links by parts

				if i < #parts and mw.ustring.find(param_value, "[[", 1, true) and not mw.ustring.find(param_value, "]]", 1, true) then

					parametersparam_name = param_value

					local part_next = i + 1

					while partspart_next and mw.ustring.find(partspart_next], "]]", 1, true) do

						parametersparam_name = parametersparam_name .. "|" .. partspart_next

						part_next = part_next + 1

					end

				else

					parametersparam_name = param_value

				end

			elseif not mw.ustring.find(partsi], "]]", 1, true) then

				table.insert(parameters, partsi])

			end

		end

		

		local braces_expanded

		if mw.ustring.find(title_part, ":")

			and mw.text.split(title_part, ":")[1 ~= mw.site.namespaces10].name -- not a prefix Template:

			then

			braces_expanded = mw.getCurrentFrame():callParserFunction{name=title_part, args=parameters}

		else

			braces_expanded = mw.getCurrentFrame():expandTemplate{title=title_part, args=parameters}

		end

		braces = mw.ustring.gsub(braces, "([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1") -- escape magic characters

		braces_expanded = captureEscapes(braces_expanded)

		text = mw.ustring.gsub(text, "{{" .. braces .. "}}", braces_expanded)

	end

	

	return text

end



-- Resolve Wikidata redirects, pending phab:T157868

local function resolveEntityId(id)

	if not id or not mw.wikibase.isValidEntityId(id) then return id end

	-- if no label in English, maybe it is a redirect

	-- not using mw.title.new(id).isRedirect as it is expensive

	-- currently getLabelByLang does not follows redirects

	if mw.wikibase.getLabelByLang(id, 'en') == nil then

		local entity = mw.wikibase.getEntity(id) -- expensive function

		if not entity then return nil end

		if id ~= entity.id then

			-- Qid redirected to be fixed

			-- see [[Special:WhatLinksHere/Template:Track/wikidata/redirect]]

			require(wiki.module_title .. '/debug').track('redirect')

			require(wiki.module_title .. '/debug').track('redirect/' .. id)

		else

			-- no redirect and no English label, fix it to avoid expensive functions

			require(wiki.module_title .. '/debug').track('label')

			require(wiki.module_title .. '/debug').track('label/' .. id)

		end

		return entity.id

	end

	return id

end



-- format data type math

local function printDatatypeMath(data)

	return mw.getCurrentFrame():callParserFunction('#tag:math', data)

end



-- format data type musical-notation

local function printDatatypeMusical(data, formatting)

	local attr = {}

	if formatting == 'sound' then

		attr.sound = 1

	end

	return mw.getCurrentFrame():extensionTag('score', data, attr)

end



-- format data type string

local function printDatatypeString(data, parameters)

	if mw.ustring.find((parameters.formatting or ''), '$1', 1, true) then -- formatting = a pattern

		return expandBraces(mw.ustring.gsub(parameters.formatting, '$1', {['$1' = data}), parameters.formatting)

	elseif parameters.case then

		return case(parameters.case, data, parameters.lang1], feminineGender(parameters.id))

	end

	local data_number = string.match(data, "^%d+")

	if data_number then -- sort key by initial number and remaining string

		local sortkey = string.format("%019d", data_number * 1000)

		return data, sortkey .. string.sub(data, #data_number + 1)

	end

	return data

end



-- format data type url

local function printDatatypeUrl(data, parameters)

	if parameters.formatting == 'weblink' then

		local label_parts = mw.text.split(string.gsub(data, '/$', ''), '/')

		local label = string.gsub(label_parts3], '^www%.', '')

		if #label_parts > 3 then

			label = label .. '…'

		end

		return '[' .. data .. ' ' .. label .. ']'

	end

	return printDatatypeString(data, parameters)

end



-- format data type external-id

local function printDatatypeExternal(data, parameters)

	if parameters.formatting == 'externalid' then

		local p_stat = mw.wikibase.getBestStatements(parameters.property, 'P1630') -- formatter URL

		local p_link_pattern = getSnak(p_stat, {1, "mainsnak", "datavalue", "value"})

		if p_link_pattern then

			local p_link = mw.ustring.gsub(p_link_pattern, '$1', {['$1' = data})

			return '[' .. p_link .. ' ' .. data .. ']'

		end

	end

	return printDatatypeString(data, parameters)

end



-- format data type commonsMedia and geo-shape

local function printDatatypeMedia(data, parameters)

	local icon

	if not string.find((parameters.formatting or ''), '$1', 1, true) then

		icon = "no-icon"

		if not string.find(data, '^Data:') then

			data = mw.uri.encode(data, 'PATH') -- encode special characters in filename

		end

	end

	return printDatatypeString(data, parameters), icon

end



-- format data type globe-coordinate

local function printDatatypeCoordinate(data, formatting)

	local function globes(globe_id)

		local globes = {['Q3134'='callisto',['Q596'='ceres',['Q15040'='dione',['Q2'='earth',['Q3303'='enceladus',

			'Q3143'='europa',['Q17975'='phoebe',['Q3169'='ganymede',['Q3123'='io',['Q17958'='iapetus',

			'Q308'='mercury',['Q15034'='mimas',['Q405'='moon',['Q15050'='rhea',['Q15047'='tethys',

			'Q111'='mars',['Q2565'='titan',['Q3359'='triton',['Q313'='venus',['Q3030'='vesta'}

		return globesglobe_id

	end

	

	local function roundPrecision(num, prec)

		if prec == nil or prec <= 0 then return num end

		local sig = 10^math.floor(math.log10(prec)+.5) -- significant figure from sexagesimal precision: 0.00123 -> 0.001

		return math.floor(num / sig + 0.5) * sig

	end

	

	local precision = data.precision

	local latitude = roundPrecision(data.latitude, precision)

	local longitude = roundPrecision(data.longitude, precision)

	if formatting and string.find(formatting, '$lat', 1, true) and string.find(formatting, '$lon', 1, true) then

		local ret = mw.ustring.gsub(formatting, '$l[ao][tn]', {['$lat' = latitude, '$lon' = longitude})

		if string.find(formatting, '$globe', 1, true) then

			local myglobe = 'earth'

			if isSet(data.globe) then

				local globenum = mw.text.split(data.globe, 'entity/')[2 -- http://www.wikidata.org/wiki/Q2

				myglobe = globes(globenum) or 'earth'

			end

			ret = mw.ustring.gsub(ret, '$globe', myglobe)

		end

		return expandBraces(ret, formatting)

	elseif formatting == 'latitude' then

		return latitude, "no-icon"

	elseif formatting == 'longitude' then

		return longitude, "no-icon"

	elseif formatting == 'dimension' then

		return data.dimension, "no-icon"

	else --default formatting='globe'

		if isSet(data.globe) == false or data.globe == 'http://www.wikidata.org/entity/Q2' then

			return 'earth', "no-icon"

		else

			local globenum = mw.text.split(data.globe, 'entity/')[2

			return globes(globenum) or globenum, "no-icon"

		end

	end

end



-- Local functions for data value quantity

local function unitSymbol(id, lang) -- get unit symbol or code

	local unit_symbol = ''

	if lang == wiki.langcode and pcall(require, wiki.module_title .. "/Units") then

		unit_symbol = require(wiki.module_title .. "/Units").getUnit(0, '', id, true)

	end

	if unit_symbol == '' then

		-- fetch it

		local claims = mw.wikibase.getBestStatements(id, 'P5061')

		if #claims > 0 then

			local langclaims = {}

			table.insert(lang, 'mul') -- multilingual as last try

			for _, snak in ipairs(claims) do

				local snak_language = getSnak(snak, {"mainsnak", "datavalue", "value", "language"})

				if snak_language and not langclaimssnak_language then -- just the first one by language

					langclaimssnak_language = snak.mainsnak.datavalue.value.text

				end

			end

			for _, l in ipairs(lang) do

				if langclaimsl then

					return langclaimsl

				end

			end

		end

	end

	return unit_symbol

end



local function getUnit(amount, id, parameters) -- get unit symbol or name

	local suffix = ''

	if parameters.formatting == "unitcode" then

		-- get unit symbol

		local unit_symbol = unitSymbol(id, parameters.lang)

		if isSet(unit_symbol) then

			suffix = unit_symbol

		end

	end

	if suffix == '' then -- formatting=unit, or formatting=unitcode not found

		-- get unit name

		local unit_label, lang = getLabelByLangs(id, parameters.lang)

		if lang == wiki.langcode and pcall(require, wiki.module_title .. "/Units") then

			suffix = require(wiki.module_title .. "/Units").getUnit(amount, unit_label, id, false)

		else

			suffix = (unit_label or id) .. addLabelIcon(id, lang, parameters.lang1], parameters.labelicon)

		end

	end

	if suffix ~= '' then

		suffix = ' ' .. suffix

	end

	return suffix

end



local function roundDefPrecision(in_num, factor)

	-- rounds out_num with significant figures of in_num (default precision)

	local out_num = in_num * factor

	if factor/60 == math.floor(factor/60) or out_num == 0 then -- sexagesimal integer or avoiding NaN

		return out_num

	end

	-- first, count digits after decimal mark, handling cases like '12.345e6'

	local exponent, prec

	local integer, dot, decimals, expstr = in_num:match('^(%d*)(%.?)(%d*)(.*)')

	local e = expstr:sub(1, 1)

	if e == 'e' or e == 'E' then

		exponent = tonumber(expstr:sub(2))

	end

	if dot == '' then

		prec = -integer:match('0*$'):len()

	else

		prec = #decimals

	end

	if exponent then

		-- So '1230' and '1.23e3' both give prec = -1, and '0.00123' and '1.23e-3' give 5.

		prec = prec - exponent

	end

	-- significant figures

	local in_bracket = 10^-prec -- -1 -> 10, 5 -> 0.00001

	local out_bracket = in_bracket * out_num / in_num

	out_bracket = 10^math.floor(math.log10(out_bracket)+.5) -- 1230 -> 1000, 0.00123 -> 0.001

	-- round it (credit to Luc Bloom from http://lua-users.org/wiki/SimpleRound)

	return math.floor(out_num/out_bracket + (out_num >=0 and 1 or -1) * 0.5) * out_bracket

end



-- format data type quantity

local function printDatatypeQuantity(data, parameters)

	local amount = data.amount

	amount = mw.ustring.gsub(amount, "%+", "")

	local suffix = ""

	local conv_amount, conv_suffix

	if string.sub(parameters.formatting or '', 1, 4) == "unit" or string.sub(parameters.formatting or '', 1, 8) == "duration" or parameters.convert then

		local unit_id = data.unit

		unit_id = mw.ustring.sub(unit_id, mw.ustring.find(unit_id, "Q"), -1)

		if string.sub(unit_id, 1, 1) == "Q" then

			suffix = getUnit(amount, unit_id, parameters)

			local convert_to

			if parameters.convert == "default" or parameters.convert == "default2" then

				local exist, units = pcall(require, wiki.module_title .. "/Units")

				if exist and units.convert_default and next(units.convert_default) ~= nil then

					convert_to = units.convert_defaultunit_id

				end

			elseif string.sub(parameters.convert or '', 1, 1) == "Q" then

				convert_to = resolveEntityId(parameters.convert)

			elseif string.sub(parameters.formatting or '', 1, 8) == "duration" then

				convert_to = 'Q11574' -- seconds

			end

			if convert_to and convert_to ~= unit_id then

				-- convert units

				local conv_temp = { -- formulae for temperatures ºC, ºF, ªK: [from] = {[to] = 'formula'}

					'Q25267' = {['Q42289' = '$1*1.8+32', 'Q11597' = '$1+273.15'},

					'Q42289' = {['Q25267' = '($1-32)/1.8', 'Q11597' = '($1+459.67)*5/9'},

					'Q11597' = {['Q25267' = '$1-273.15', 'Q42289' = '($1-273.15)*1.8000+32.00'}

				}

				if conv_tempunit_id and conv_tempunit_id][convert_to then

					local amount_f = mw.getCurrentFrame():callParserFunction('#expr', mw.ustring.gsub(conv_tempunit_id][convert_to], "$1", amount))

					conv_amount = math.floor(tonumber(amount_f) + 0.5)

				else

					local conversions = getStatements(unit_id, 'P2442') -- conversion to standard unit

					table.insert(conversions, mw.wikibase.getBestStatements(unit_id, 'P2370')[1]) -- conversion to SI unit

					for _, conv in ipairs(conversions) do

						if conv.mainsnak.snaktype == 'value' then -- no somevalue nor novalue

							if conv.mainsnak.datavalue.value.unit == "http://www.wikidata.org/entity/" .. convert_to then

								conv_amount = roundDefPrecision(amount, tonumber(conv.mainsnak.datavalue.value.amount))

								break

							end

						end

					end

				end

				if conv_amount then

					conv_suffix = getUnit(conv_amount, convert_to, parameters)

				end

			elseif parameters.convert == 'M' and tonumber(amount) > 10^8 then

				conv_amount = math.floor(amount/10^6 + 0.5)

				conv_suffix = ' M' .. string.sub(suffix, 2)

			end

		end

	end

	local lang_obj = mw.language.new(parameters.lang1])

	local sortkey = string.format("%019d", tonumber(amount) * 1000)

	if string.sub(parameters.formatting or '', 1, 8) == "duration" then

		local sec = tonumber(conv_amount or amount)

		if parameters.formatting == 'durationhms' or parameters.formatting == 'durationh:m:s' then

			local intervals = {"hours", "minutes", "seconds"}

			local sec2table = lang_obj:getDurationIntervals(sec, intervals)

			sec2table"seconds" = (sec2table"seconds" or 0) + tonumber("." .. (tostring(sec):match("%.(%d+)") or "0")) -- add decimals

			local duration = ''

			for i, v in ipairs(intervals) do

				if parameters.formatting == 'durationh:m:s' then

					if i == 1 and sec2tablev then

						duration = duration .. sec2tablev .. ":"

					elseif i == 2 then

						duration = duration .. string.format("%02d", sec2tablev or 0) .. ":"

					elseif i == 3 then

						local sec_str = tostring(lang_obj:formatNum(sec2tablev or 0))

						duration = duration .. (sec2tablev < 10 and "0" or "") .. sec_str

					end

				elseif sec2tablev then

					duration = duration .. lang_obj:formatNum(sec2tablev]) .. i18n.datetime.hmsv .. (i < 3 and " " or "")

				end

			end

			return duration

		else

			return lang_obj:formatDuration(sec)

		end

	end

	if parameters.case then

		amount = case(parameters.case, amount, parameters.lang1])

	elseif parameters.formatting ~= 'raw' then

		amount = lang_obj:formatNum(tonumber(amount))

	end

	if conv_amount then

		local conv_sortkey = string.format("%019d", conv_amount * 1000)

		conv_amount = lang_obj:formatNum(conv_amount)

		if parameters.convert == 'default2' then

			return conv_amount .. conv_suffix .. ' (' .. amount .. suffix .. ')', conv_sortkey

		else

			return conv_amount .. conv_suffix, conv_sortkey

		end

	elseif mw.ustring.find((parameters.formatting or ''), '$1', 1, true) then -- formatting with pattern

		amount = mw.ustring.gsub(parameters.formatting, '$1', {['$1' = amount})

	end

	return amount .. suffix, sortkey

end



-- format data type time

local function printDatatypeTime(data, parameters)

	-- Dates and times are stored in ISO 8601 format

	local timestamp = data.time

	local post_format

	local calendar_add = ""

	local precision = data.precision or 11

	

	if string.sub(timestamp, 1, 1) == '-' then

		post_format = i18n.datetime"bc"

	elseif string.sub(timestamp, 2, 3) == '00' then

		post_format = i18n.datetime"ad"

	elseif precision > 8 then

		-- calendar model

		local calendar_model = {["Q12138" = "gregorian", "Q1985727" = "gregorian", "Q11184" = "julian", "Q1985786" = "julian"}

		local calendar_id = mw.text.split(data.calendarmodel, 'entity/')[2

		if (timestamp < "+1582-10-15T00:00:00Z" and calendar_modelcalendar_id == "gregorian")

			or (timestamp > "+1582-10-04T00:00:00Z" and calendar_modelcalendar_id == "julian")

			then

			calendar_add = " <sup>(" .. mw.message.new('Wikibase-time-calendar-' .. calendar_modelcalendar_id]):inLanguage(parameters.lang1]):plain() .. ")</sup>"

		end

	end

	

	local function formatTime(form, stamp)

		local pattern

		if type(form) == "function" then

			pattern = form(stamp)

		else

			pattern = form

		end

		stamp = tostring(stamp)

		if mw.ustring.find(pattern, "$1") then

			return mw.ustring.gsub(pattern, "$1", stamp)

		elseif string.sub(stamp, 1, 1) == '-' then -- formatDate() only supports years from 0

			stamp = '+' .. string.sub(stamp, 2)

		elseif string.sub(stamp, 1, 1) ~= '+' then -- not a valid timestamp, it is a number

			stamp = string.format("%04d", stamp)

		end

		local ret = mw.language.new(parameters.lang1]):formatDate(pattern, stamp)

		ret = string.gsub(ret, "^(%[?%[?)0+", "%1") -- supress leading zeros

		ret = string.gsub(ret, "( %[?%[?)0+", "%1")

		return ret

	end

	

	local function postFormat(t)

		if post_format and mw.ustring.find(post_format, "$1") then

			return mw.ustring.gsub(post_format, "$1", t)

		end

		return t

	end

	

	local intyear = tonumber(string.match(timestamp, "[+-](%d+)"))

	local ret = ""

	

	if precision <= 5 then -- precision is 10000 years or more

		local factor = 10 ^ ((5 - precision) + 4)

		local y2 = math.ceil(math.abs(intyear) / factor)

		local relative = formatTime(i18n.datetimeprecision], y2)

		if post_format == i18n.datetime"bc" then

			ret = mw.ustring.gsub(i18n.datetime.beforenow, "$1", relative)

		else

			ret = mw.ustring.gsub(i18n.datetime.afternow, "$1", relative)

		end

		local ret_number = string.match(ret, "%d+")

		if ret_number ~= nil then

			ret = mw.ustring.gsub(ret, ret_number, mw.language.new(parameters.lang1]):formatNum(tonumber(ret_number)))

		end

	elseif precision == 6 or precision == 7 then -- millennia or centuries

		local card = math.floor((intyear - 1) / 10^(9 - precision)) + 1

		ret = formatTime(i18n.datetimeprecision], card)

		ret = postFormat(ret)

	elseif precision == 8 then -- decades

		local card = math.floor(math.abs(intyear) / 10) * 10

		ret = formatTime(i18n.datetime8], card)

		ret = postFormat(ret)

	elseif intyear > 9999 then -- not a valid timestamp

		return

	elseif precision == 9 or parameters.formatting == 'Y' then -- precision is year

		ret = formatTime(i18n.datetime9], intyear)

		ret = postFormat(ret) .. calendar_add

	elseif precision == 10 then -- month

		ret = formatTime(i18n.datetime10], timestamp .. " + 1 day") -- formatDate yyyy-mm-00 returns the previous month

		ret = postFormat(ret) .. calendar_add

	else -- precision 11, day

		ret = formatTime(parameters.formatting or i18n.datetime11], timestamp)

		ret = postFormat(ret) .. calendar_add

	end

	return ret, timestamp

end



-- format data value wikibase-entityid: types wikibase-item, wikibase-property

local function printDatatypeEntity(data, parameters)

	local entity_id = data'id'

	if parameters.formatting == 'raw' then

		return entity_id, entity_id

	end

	local entity_page = 'Special:EntityPage/' .. entity_id

	local label, lang = getLabelByLangs(entity_id, parameters.lang)

	local sitelink = mw.wikibase.getSitelink(entity_id)

	local parameter = parameters.formatting

	local labelcase = label or sitelink

	if parameters.gender == 'feminineform' then

		labelcase = feminineForm(entity_id, lang) or labelcase

	end

	if parameters.case ~= 'gender' then

		labelcase = case(parameters.case, labelcase, lang, parameters.lang1], entity_id, parameters.id)

	end

	local ret1, ret2

	if parameter == 'label' then

		ret1 = labelcase or entity_id

		ret2 = labelcase or entity_id

	elseif parameter == 'sitelink' then

		ret1 = (sitelink or 'd:' .. entity_page)

		ret2 = sitelink or entity_id

	elseif mw.ustring.find((parameter or ''), '$1', 1, true) then -- formatting = a pattern

		ret1 = mw.ustring.gsub(parameter, '$1', labelcase or entity_id)

		ret1 = expandBraces(ret1, parameter)

		ret2 = labelcase or entity_id

	else

		if parameter == "ucfirst" or parameter == "ucinternallink" then

			if labelcase and lang then

				labelcase = mw.language.new(lang):ucfirst(labelcase)

			end

			-- only first of a list, reset formatting for next ones

			if parameter == "ucinterlanllink" then

				parameters.formatting = 'internallink'

			else

				parameters.formatting = nil -- default format

			end

		end

		

		if sitelink then

			ret1 = '[[' .. sitelink .. '|' .. labelcase .. ']]'

			ret2 = labelcase

		elseif label and string.match(parameter or '', 'internallink$') and not mw.wikibase.getEntityIdForTitle(label) then

			ret1 = '[[' .. label .. '|' .. labelcase .. ']]'

			ret2 = labelcase

		else

			ret1 = '[[d:' .. entity_page .. '|<span style="color:#5f9cbb;">' .. (labelcase or entity_id) .. '</span>]]'

			ret2 = labelcase or entity_id

		end

	end

	

	return ret1 .. addLabelIcon(entity_id, lang, parameters.lang1], parameters.labelicon), ret2

end



-- format data type monolingualtext

local function printDatatypeMonolingual(data, parameters)

	-- data fields: language [string], text [string]

	

	if parameters.list == "lang" and data"language" ~= parameters.lang1 then

		return

	elseif parameters.list == "notlang" and data"language" == parameters.lang1 then

		return

	elseif parameters.formatting == "language" or parameters.formatting == "text" then

		return dataparameters.formatting

	end

	local result = data"text"

	if data"language" ~= wiki.langcode then

		result = mw.ustring.gsub('<span lang="$1">$2</span>', '$[12]', {["$1"=data"language"], "$2"=data"text"]})

	end

	if mw.ustring.find((parameters.formatting or ''), '$', 1, true) then

		-- output format defined with $text, $language

		result = mw.ustring.gsub(parameters.formatting, '$text', result)

		result = mw.ustring.gsub(result, '$language', data"language"])

	end

	return result

end



local function getSnakValue(snak, parameters)

	if snak.snaktype == 'value' then

		-- see Special:ListDatatypes

		if snak.datatype == "string" then

			return printDatatypeString(snak.datavalue.value, parameters)

		-- other data value string, tabular-data not implemented

		elseif snak.datatype == "commonsMedia" or snak.datatype == "geo-shape" then

			return printDatatypeMedia(snak.datavalue.value, parameters)

		elseif snak.datatype == "url" then

			return printDatatypeUrl(snak.datavalue.value, parameters)

		elseif snak.datatype == "external-id" then

			return printDatatypeExternal(snak.datavalue.value, parameters)

		elseif snak.datatype == 'math' then

			return printDatatypeMath(snak.datavalue.value)

		elseif snak.datatype == 'musical-notation' then

			return printDatatypeMusical(snak.datavalue.value, parameters.formatting)

		-- other data types

		elseif snak.datatype == 'wikibase-item' or snak.datatype == 'wikibase-property' then

			return printDatatypeEntity(snak.datavalue.value, parameters)

		elseif snak.datatype == 'monolingualtext' then

			return printDatatypeMonolingual(snak.datavalue.value, parameters)

		elseif snak.datatype == "globe-coordinate" then

			return printDatatypeCoordinate(snak.datavalue.value, parameters.formatting)

		elseif snak.datatype == "quantity" then

			return printDatatypeQuantity(snak.datavalue.value, parameters)

		elseif snak.datatype == "time" then

			return printDatatypeTime(snak.datavalue.value, parameters)

		end

	elseif snak.snaktype == 'novalue' then

		if parameters.formatting == 'raw' or parameters.shownovalue == false then return end

		return mw.message.new('Wikibase-snakview-snaktypeselector-novalue'):inLanguage(parameters.lang1]):plain()

	elseif snak.snaktype == 'somevalue' then

		if parameters.formatting == 'raw' then return end

		return mw.message.new('Wikibase-snakview-snaktypeselector-somevalue'):inLanguage(parameters.lang1]):plain()

	end

	return mw.wikibase.renderSnak(snak)

end



local function printError(key)

	return '<span class="error">' .. i18n.errorskey .. '</span>'

end



local function getQualifierSnak(claim, qualifierId, parameters)

	-- a "snak" is Wikidata terminology for a typed key/value pair

	-- a claim consists of a main snak holding the main information of this claim,

	-- as well as a list of attribute snaks and a list of references snaks

	if qualifierId then

		-- search the attribute snak with the given qualifier as key

		if claim.qualifiers then

			local qualifier = claim.qualifiersqualifierId

			if qualifier then

				if qualifier1].datatype == "monolingualtext" then

					-- iterate over monolingualtext qualifiers to get local language

					for idx in pairs(qualifier) do

						if getSnak(qualifieridx], {"datavalue", "value", "language"}) == parameters.lang1 then

							return qualifieridx

						end

					end

				elseif parameters.list then

					return qualifier

				else

					return qualifier1

				end

			end

		end

		return nil, printError("qualifier-not-found")

	else

		-- otherwise return the main snak

		return claim.mainsnak

	end

end



local function getValueOfClaim(claim, qualifierId, parameters)

	local snak, error = getQualifierSnak(claim, qualifierId, parameters)

	if not snak then

		return nil, nil, error

	elseif snak1 then -- a multi qualifier

		local result, sortkey = {}, {}

		local maxvals = tonumber(parameters.list)

		for idx in pairs(snak) do

			result#result + 1], sortkey#sortkey + 1 = getSnakValue(snakidx], parameters)

			if maxvals and maxvals == #result then break end

		end

		return mw.text.listToText(result, parameters.qseparator, parameters.qconjunction), sortkey1

	else -- a property or a qualifier

		return getSnakValue(snak, parameters)

	end

end



local function getValueOfParentClaim(claim, qualifierId, parameters)

	local qids = mw.text.split(qualifierId, '/', true)

	local value, sortkey, valueraw = {}, {}, {}

	local parent_raw, value_text

	if qids1 == parameters.property then

		parent_raw, _, _ = getValueOfClaim(claim, nil, {["formatting"="raw", "lang"=parameters.lang})

	else

		parent_raw, _, _ = getValueOfClaim(claim, qids1], {["formatting"="raw", "lang"=parameters.lang, "list"=true, "qseparator"='/', "qconjunction"='/'})

	end

	if string.sub(parent_raw or '', 1, 1) == "Q" then -- protection for 'no value'

		local parent_qids = mw.text.split(parent_raw, '/', true)

		for idx, p_qid in ipairs(parent_qids) do

			local parent_claims = mw.wikibase.getBestStatements(p_qid, qids2])

			if parent_claims1 then

				valueidx], sortkeyidx], _ = getValueOfClaim(parent_claims1], nil, parameters)

				-- raw parent value needed for while/black lists, lang for avoiding an error on types other than entity

				valuerawidx], _, _ = getValueOfClaim(parent_claims1], nil, {["formatting"="raw", "lang"=parameters.lang})

			end

		end

	end

	if value1 then

		value_text = mw.text.listToText(value, parameters.qseparator, parameters.qconjunction)

	end

	return value_text, sortkey1], valueraw1

end



-- see d:Help:Sources

local function getReferences(claim, lang)

	local notproperref = {

		"P143" = true, -- imported from

		"P3452" = true, -- inferred from

		"P887" = true, -- based on heuristic

		"P4656" = true -- Wikimedia import URL

	}

	local result = ""

	-- traverse through all references

	for ref in pairs(claim.references or {}) do

		local refparts

		local refs = {}

		local validref = true

		local ref_name

		-- traverse through all parts of the current reference

		for snakkey, snakval in pairs(claim.referencesref].snaks or {}) do

			for partkey, _ in pairs(claim.referencesref].snakssnakkey or {}) do

				if notproperrefsnakkey then -- not a proper reference

					validref = false

					break

				end

			end

			if validref then

				for snakidx = 1, #snakval do

					if snakidx > 1 then refparts = refparts .. ", " end

					refparts = refparts or '' .. (getSnakValue(snakvalsnakidx], {lang=lang}) or '')

				end

				refssnakkey = refparts

				refparts = nil

				if snakkey == "P248" then -- stated in

					ref_name = getSnak(snakval, {1, "datavalue", "value", "id"})

				end

			end

		end

		

		-- fill missing values with parent item

		if ref_name then

			local function refParent(qid, pid, formatting)

				local snak = getSnak(mw.wikibase.getBestStatements(qid, pid), {1, "mainsnak"})

				return snak and getSnakValue(snak, {formatting=formatting, lang=lang})

			end

			

			refs'P50' = refs'P50' or refParent(ref_name, 'P50', 'label') -- author

			refs'P407' = refs'P407' or refParent(ref_name, 'P407', 'label') -- language of work

			refs'P123' = refs'P123' or refParent(ref_name, 'P123', 'label') -- publisher

			refs'P577' = refs'P577' or refParent(ref_name, 'P577') -- date

			refs'P1433' = refs'P1433' or refParent(ref_name, 'P1433', 'label') -- published in

			refs'P304' = refs'P304' or refParent(ref_name, 'P304') -- page(s)

			refs'P433' = refs'P433' or refParent(ref_name, 'P433') -- issue

			refs'P236' = refs'P236' or refParent(ref_name, 'P236') -- ISSN

			refs'P356' = refs'P356' or refParent(ref_name, 'P356') -- DOI

			

			ref_name = ref_name .. claim.referencesref].hash

		end

		

		-- get title of local templates for citing references

		local template_web = mw.wikibase.getSitelink('Q5637226') or ""

		template_web = mw.text.split(template_web, ":")[2 -- split off namespace from front

		local template_journal = mw.wikibase.getSitelink('Q5624899') or ""

		template_journal = mw.text.split(template_journal, ":")[2

		

		local citeParams = {}

		if refs'P854' and (refs'P1476' or refs'P248']) and template_web then

			-- if both "reference URL" and "title" (or "stated in") are present, then use cite web template

			citeParamsi18n'cite']['url']] = refs'P854'

			if refs'P248' and refs'P1476' == nil then

				citeParamsi18n'cite']['title']] = refs'P248']:match("^%[%[.-|(.-)%]%]")

			else

				citeParamsi18n'cite']['title']] = refs'P1476'

				citeParamsi18n'cite']['website']] = refs'P248'

			end

			citeParamsi18n'cite']['author']] = refs'P50'

			citeParamsi18n'cite']['language']] = refs'P407'

			citeParamsi18n'cite']['publisher']] = refs'P123'

			citeParamsi18n'cite']['date']] = refs'P577'

			citeParamsi18n'cite']['pages']] = refs'P304'

			citeParamsi18n'cite']['access-date']] = refs'P813'

			citeParamsi18n'cite']['archive-url']] = refs'P1065'

			citeParamsi18n'cite']['archive-date']] = refs'P2960'

			citeParamsi18n'cite']['quote']] = refs'P1683'

			refparts = mw.getCurrentFrame():expandTemplate{title=template_web, args=citeParams}

		elseif refs'P1433' and (refs'P1476' or refs'P248']) and template_journal then

			-- if both "published in" and "title" (or "stated in") are present, then use cite journal template

			citeParamsi18n'cite']['work']] = refs'P1433'

			citeParamsi18n'cite']['title']] = refs'P1476' or refs'P248'

			citeParamsi18n'cite']['author']] = refs'P50'

			citeParamsi18n'cite']['date']] = refs'P577'

			citeParamsi18n'cite']['issue']] = refs'P433'

			citeParamsi18n'cite']['pages']] = refs'P304'

			citeParamsi18n'cite']['language']] = refs'P407'

			citeParamsi18n'cite']['issn']] = refs'P236'

			citeParamsi18n'cite']['doi']] = refs'P356'

			refparts = mw.getCurrentFrame():expandTemplate{title=template_journal, args=citeParams}

		elseif validref then

			-- raw ouput

			local snaksorder = claim.referencesref]["snaks-order"

			local function indexed(a)

				for _, b in ipairs(snaksorder) do

					if b == a then return true end

				end

				return false

			end

			for k, _ in pairs(refs or {}) do

				if not indexed(k) then

					table.insert(snaksorder, k)

				end

			end

			local italics = "''"

			for _, k in ipairs(snaksorder) do

				if refsk then

					refparts = refparts and refparts .. " " or ""

					refparts = refparts .. mw.ustring.gsub(getLabelByLangs(k, lang), "^%l", mw.ustring.upper) .. ": "

					refparts = refparts .. italics .. refsk .. italics .. "."

					italics = ""

				end

			end

		end

		if refparts then result = mw.getCurrentFrame():extensionTag("ref", refparts, {name=ref_name}) end

	end

	if type(result) == 'string' and result ~= "" and isSet(i18n.categoryref) then

		result = result .. "[[" ..i18n.categoryref .. "]]"

	end

	return result

end



-- Set whitelist or blacklist values

local function setWhiteOrBlackList(num_qual, args)

	local lists = {['whitelist'={}, 'blacklist'={}, 'ignorevalue'={}, 'selectvalue'={}}

	for i = 0, num_qual do

		for k, _ in pairs(lists) do

			if isSet(argsk .. i]) then

				listsk][tostring(i)] = {}

				local pattern = 'Q%d+'

				if string.sub(argsk .. i], 1, 1) ~= 'Q' then

					pattern = '[^%p%s]+'

				end

				for q in string.gmatch(argsk .. i], pattern) do

					listsk][tostring(i)][resolveEntityId(q)] = true

				end

			end

		end

	end

	return lists'whitelist'], lists'blacklist'], lists'ignorevalue'], lists'selectvalue'

end



local function tableParameters(args, parameters, column)

	local column_params = mw.clone(parameters)

	column_params.formatting = args"colformat"..column]; if column_params.formatting == "" then column_params.formatting = nil end

	column_params.convert = args"convert" .. column

	if args"case" .. column then

		column_params.case = args"case" .. column

	end

	return column_params

end



local function getEntityId(args, pargs, unnamed)

	pargs = pargs or {}

	local id = args.item or args.from or (unnamed and mw.text.trim(args1 or '') or nil)

	if not isSet(id) then

		id = pargs.item or pargs.from or (unnamed and mw.text.trim(pargs1 or '') or nil)

	end

	if isSet(id) then

		if string.find(id, ":") then -- remove prefix as Property:Pid

			id = mw.text.split(id, ":")[2

		end

	else

		id = mw.wikibase.getEntityIdForCurrentPage()

	end

	return id

end



local function getArg(value, default, aliases)

	if type(value) == 'boolean' then return value

	elseif value == "false" or value == "no" then return false

	elseif value == "true" or value == "yes" then return true

	elseif value and aliases and aliasesvalue then return aliasesvalue

	elseif isSet(value) then return value

	elseif default then return default

	else return nil

	end

end



-- Main function claim ---------------------------------------------

-- on debug console use: =p.claim{item="Q...", property="P...", ...}

function p.claim(frame)

	local args = frame.args or frame -- via invoke or require

	local pargs = frame.args and frame:getParent().args or {}

	local is_sandbox = isSet(pargs.sandbox)

	if not required and is_sandbox then

		return require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).claim(frame)

	end

	--If a value is already set, use it

	if isSet(args.value) then

		if args.value == 'NONE' then

			return

		else

			return args.value

		end

	end

	

	-- arguments

	local parameters = {}

	parameters.id = getEntityId(args, pargs)

	if parameters.id == nil then return end

	parameters.property = string.upper(args.property or "")

	local qualifierId = {}

	qualifierId1 = getArg(string.upper(args.qualifier or ""))

	local i = 2

	while isSet(args"qualifier" .. i]) do

		qualifierIdi = string.upper(args"qualifier" .. i])

		i = i + 1

	end

	parameters.formatting = getArg(args.formatting)

	parameters.convert = getArg(args.convert)

	parameters.case = args.case

	parameters.list = getArg(args.list, true, {firstrank='bestrank'})

	parameters.shownovalue = getArg(args.shownovalue, true)

	parameters.separator = getArg(args.separator)

	parameters.conjunction = getArg(args.conjunction, parameters.separator)

	parameters.qseparator = parameters.separator

	parameters.qconjunction = parameters.conjunction

	local sorting_col = args.tablesort

	local sorting_up = (args.sorting or "") ~= "-1"

	local rowformat = args.rowformat

	local references = args.references

	local showerrors = args.showerrors

	local default = args.default

	if default then showerrors = nil end

	parameters.lang = findLang(args.lang)

	if parameters.formatting == "raw" then

		parameters.editicon, parameters.labelicon = false, false

	else

		parameters.editicon, parameters.labelicon = setIcons(args.editicon, pargs.editicon) -- needs loadI18n by findLand

	end

	

	-- fetch property

	local claims = {}

	local bestrank = (parameters.list == false or parameters.list == 'bestrank') and parameters.list ~= 'lang'

	for p in string.gmatch(parameters.property, 'P%d+') do

		claims = getStatements(parameters.id, p, bestrank)

		if #claims > 0 then

			parameters.property = p

			break

		end

	end

	if #claims == 0 then

		if showerrors then return printError("property-not-found") else return default end

	end

	

	-- defaults for table

	local preformat, postformat = "", ""

	local whitelisted = false

	local whitelist, blacklist, ignorevalue, selectvalue = {}, {}, {}, {}

	if parameters.formatting == "table" then

		parameters.separator = parameters.separator or "<br />"

		parameters.conjunction = parameters.conjunction or "<br />"

		parameters.qseparator = ", "

		parameters.qconjunction = ", "

		if not rowformat then

			rowformat = "$0 ($1"

			i = 2

			while qualifierIdi do

				rowformat = rowformat .. ", $" .. i

				i = i + 1

			end

			rowformat = rowformat .. ")"

		elseif mw.ustring.find(rowformat, "^[*#]") then

			parameters.separator = "</li><li>"

			parameters.conjunction = "</li><li>"

			if mw.ustring.match(rowformat, "^[*#]") == "*" then

				preformat = "<ul><li>"

				postformat = "</li></ul>"

			else

				preformat = "<ol><li>"

				postformat = "</li></ol>"

			end

			rowformat = mw.ustring.gsub(rowformat, "^[*#] ?", "")

		end

		

		-- set whitelist and blacklist values

		whitelist, blacklist, ignorevalue, selectvalue = setWhiteOrBlackList(#qualifierId, args)

		local next = next

		if next(whitelist) ~= nil then whitelisted = true end

	end

	

	-- set feminine case if gender is requested

	local itemgender = args.itemgender

	local idgender

	if itemgender then

		if string.match(itemgender, "^P%d+$") then

			local snak_id = getSnak(mw.wikibase.getBestStatements(parameters.id, itemgender), {1, "mainsnak", "datavalue", "value", "id"})

			if snak_id then

				idgender = snak_id

			end

		elseif string.match(itemgender, "^Q%d+$") then

			idgender = itemgender

		end

	end

	local gender_requested = false

	if parameters.case == "gender" or idgender then

		gender_requested = true

	elseif parameters.formatting == "table" then

		for i=0, #qualifierId do

			if args"case" .. i and args"case" .. i == "gender" then

				gender_requested = true

				break

			end

		end

	end

	if gender_requested then

		if feminineGender(idgender or parameters.id) then

			parameters.gender = "feminineform"

		end

	end

	

	-- get initial sort indices

	local sortindices = {}

	for idx in pairs(claims) do

		sortindices#sortindices + 1 = idx

	end

	-- sort by claim rank

	local comparator = function(a, b)

		local rankmap = { deprecated = 2, normal = 1, preferred = 0 }

		local ranka = rankmapclaimsa].rank or "normal" .. string.format("%08d", a)

		local rankb = rankmapclaimsb].rank or "normal" .. string.format("%08d", b)

		return ranka < rankb

	end

	table.sort(sortindices, comparator)

	

	local result, result2, result_query

	local error

	if parameters.list or parameters.formatting == "table" then

		-- convert LF to line feed, <br /> may not work on some cases

		parameters.separator = parameters.separator == "LF" and "\010" or parameters.separator

		parameters.conjunction = parameters.conjunction == "LF" and "\010" or parameters.conjunction

		-- i18n separators

		parameters.separator = parameters.separator or mw.message.new('Comma-separator'):inLanguage(parameters.lang1]):plain()

		parameters.conjunction = parameters.conjunction or (mw.message.new('And'):inLanguage(parameters.lang1]):plain() .. mw.message.new('Word-separator'):inLanguage(parameters.lang1]):plain())

		-- iterate over all elements and return their value (if existing)

		local value, valueq

		local sortkey, sortkeyq

		local values = {}

		local sortkeys = {}

		local refs = {}

		local rowlist = {} -- rows to list with whitelist or blacklist

		for idx in pairs(claims) do

			local claim = claimssortindicesidx]]

			local reference = {}

			if not whitelisted then rowlistidx = true end

			if parameters.formatting == "table" then

				local params = tableParameters(args, parameters, "0")

				value, sortkey, error = getValueOfClaim(claim, nil, params)

				if value then

					values#values + 1 = {}

					sortkeys#sortkeys + 1 = {}

					refs#refs + 1 = {}

					if whitelist"0" or blacklist"0" then

						local valueraw, _, _ = getValueOfClaim(claim, nil, {["formatting"="raw", "lang"=params.lang})

						if whitelist"0" and whitelist"0"][valueraw or "" then

							rowlist#values = true

						elseif blacklist"0" and blacklist"0"][valueraw or "" then

							rowlist#values = false

						end

					end

					for i, qual in ipairs(qualifierId) do

						local j = tostring(i)

						params = tableParameters(args, parameters, j)

						local valueq, sortkeyq, valueraw

						if qual == parameters.property then -- hack for getting the property with another formatting, i.e. colformat1=raw

							valueq, sortkeyq, _ = getValueOfClaim(claim, nil, params)

						else

							for q in mw.text.gsplit(qual, '%s*OR%s*') do

								if string.find(q, ".+/.+") then

									valueq, sortkeyq, valueraw = getValueOfParentClaim(claim, q, params)

								elseif string.find(q, "^/.+") then

									local claim2 = getStatements(parameters.id, string.sub(q, 2), bestrank)

									if #claim2 > 0 then

										valueq, sortkeyq, _ = getValueOfClaim(claim21], nil, params)

									end

								else

									valueq, sortkeyq, _ = getValueOfClaim(claim, q, params)

								end

								if valueq then

									qual = q

									break

								end

							end

						end

						values#values]["col" .. j = valueq

						sortkeys#sortkeys]["col" .. j = sortkeyq or valueq

						if whitelistj or blacklistj or ignorevaluej or selectvaluej then

							valueq = valueraw or getValueOfClaim(claim, qual, {["formatting"="raw", "lang"=params.lang})

							if whitelistj and whitelistj][valueq or "" then

								rowlist#values = true

							elseif blacklistj and blacklistj][valueq or "" then

								rowlist#values = false

							elseif ignorevaluej and ignorevaluej][valueq or "" then

								values#values]["col" .. j = nil

							elseif selectvaluej and not selectvaluej][valueq or "" then

								values#values]["col" .. j = nil

							end

						end

					end

				end

			else

				value, sortkey, error = getValueOfClaim(claim, qualifierId1], parameters)

				values#values + 1 = {}

				sortkeys#sortkeys + 1 = {}

				refs#refs + 1 = {}

			end

			if not value and showerrors then value = error end

			if value then

				if references and claim.references then reference = claim.references end

				refs#refs]["col0" = reference

				values#values]["col0" = value

				sortkeys#sortkeys]["col0" = sortkey or value

			end

		end

		-- sort and format results

		sortindices = {}

		for idx in pairs(values) do

			sortindices#sortindices + 1 = idx

		end

		if sorting_col then

			local sorting_table = mw.text.split(sorting_col, '%D+')

			local comparator = function(a, b)

				local valuea, valueb

				local i = 1

				while valuea == valueb and i <= #sorting_table do

					valuea = sortkeysa]["col" .. sorting_tablei]] or ''

					valueb = sortkeysb]["col" .. sorting_tablei]] or ''

					i = i + 1

				end

				

				if sorting_up then

					return valueb > valuea

				end

				return valueb < valuea

			end

			table.sort(sortindices, comparator)

		end

		local maxvals = tonumber(parameters.list)

		result = {}

		for idx in pairs(values) do

			local valuerow = valuessortindicesidx]]

			local reference = getReferences({["references" = refssortindicesidx]]["col0"]}, parameters.lang)

			

			value = valuerow"col0"

			if parameters.formatting == "table" then

				if not rowlistsortindicesidx]] then

					value = nil

				else

					local rowformatting = rowformat .. "$" -- fake end character added for easy gsub

					value = mw.ustring.gsub(rowformatting, "$0", {["$0" = value})

					value = mw.ustring.gsub(value, "$R0", reference) -- add reference

					for i, _ in ipairs(qualifierId) do

						local valueq = valuerow"col" .. i

						if args"rowsubformat" .. i and isSet(valueq) then

							-- add fake end character $

							-- gsub $i not followed by a number so $1 doesn't match $10, $11...

							-- remove fake end character

							valueq = captureEscapes(valueq)

							valueq = mw.ustring.gsub(args"rowsubformat" .. i .. "$", "$" .. i .. "(%D)", valueq .. "%1")

							valueq = string.sub(valueq, 1, -2)

							rowformatting = mw.ustring.gsub(rowformatting, "$" .. i .. "(%D)", args"rowsubformat" .. i .. "%1")

						end

						valueq = valueq and captureEscapes(valueq) or ''

						value = mw.ustring.gsub(value, "$" .. i .. "(%D)", valueq .. "%1")

					end

					value = string.sub(value, 1, -2) -- remove fake end character

					value = expandBraces(value, rowformatting)

				end

			elseif value then

				value = expandBraces(value, parameters.formatting)

				value = value .. reference

			end

			if isSet(value) then

				result#result + 1 = value

				if not parameters.list or (maxvals and maxvals == #result) then

					break

				end

			end

		end

		

		if args.query == 'num' then

			result_query = 0

			for _, v in pairs(rowlist) do

				result_query = result_query + (v and 1 or 0)

			end

		end

		if #result > 0 then

			if parameters.formatting == 'table' then

				result = addEditIconTable(result, parameters) -- in a table, add edit icon on last element

			end

			result = preformat .. mw.text.listToText(result, parameters.separator, parameters.conjunction) .. postformat

		else

			result = ''

		end

	else

		-- return first element

		local claim = claimssortindices1]]

		result, result2, error = getValueOfClaim(claim, qualifierId1], parameters)

		if result and references then result = result .. getReferences(claim, parameters.lang) end

		if args.query == 'num' then result_query = 1 end

	end

	

	if isSet(result) then

		if not (parameters.formatting == 'table' or (result2 and result2 == 'no-icon')) then

			-- add edit icon, except table added previously and except explicit no-icon internal flag

			result = result .. addEditIcon(parameters)

		end

	else

		if showerrors then result = error else result = default end

	end

	if args.query == 'untranslated' and required and not is_sandbox then

		result_query = untranslated

	end

	return result, result_query or ''

end



-- Local functions for getParentValues -----------------------



local function uc_first(word)

	if word == nil then return end

	return mw.ustring.upper(mw.ustring.sub(word, 1, 1)) .. mw.ustring.sub(word, 2)

end



local function getPropertyValue(id, property, parameter, langs, labelicon, case)

	local snaks = mw.wikibase.getBestStatements(id, property)

	local mysnak = getSnak(snaks, {1, "mainsnak"})

	if mysnak == nil then

		return

	end

	

	local entity_id

	local result = '-' -- default for 'no value'

	if mysnak.datavalue then

		entity_id = "Q" .. tostring(mysnak.datavalue.value'numeric-id'])

		result, _ = getSnakValue(mysnak, {formatting=parameter, lang=langs, labelicon=labelicon, case=case})

	end

	

	return entity_id, result

end



local function getParentObjects(id,

	prop_format,

	label_format,

	languages, 

	propertySupString, 

	propertyLabel,

	propertyLink,

	label_show,

	labelicon0,

	labelicon1,

	upto_number,

	upto_label,

	upto_value,

	last_only,

	grammatical_case,

	include_self)

	

	local propertySups = mw.text.split(propertySupString, '[^P%d]')

	

	local maxloop = 10

	if upto_number then

		maxloop = tonumber(upto_number)

	elseif next(upto_label) or next(upto_value) then

		maxloop = 50

	end

	

	local labels_filter = next(label_show)

	

	local result = {}

	local id_value = id

	for iter = 1, maxloop do

		local link, label, labelwicon, linktext, id_label

		for _, propertySup in pairs(propertySups) do 	

			local _id_value, _link = getPropertyValue(id_value, propertySup, prop_format, languages, labelicon1, grammatical_case)

			if _id_value and _link then id_value = _id_value; link = _link break end

		end

		

		if not id_value or not link then break end

		

		if propertyLink then

			_, linktext = getPropertyValue(id_value, propertyLink, "label", languages)

			if linktext then

				link = mw.ustring.gsub(link, "%[%[(.*)%|.+%]%]", "[[%1|" .. linktext .. "]]")

			end

		end

		

		id_label, label = getPropertyValue(id_value, propertyLabel, label_format, languages, false, "infoboxlabel")

		if labelicon0 then

			_, labelwicon = getPropertyValue(id_value, propertyLabel, label_format, languages, labelicon0, "infoboxlabel")

		else

			labelwicon = label

		end

		

		if labels_filter == nil or (label_showid_label or label_showlabel]) then

			result#result + 1 = {labelwicon, link}

			label_showid_label or 'none'], label_showlabel or 'none' = nil, nil -- only first label found

		end

		

		if upto_labelid_label or upto_labellabel or upto_valueid_value then

			break

		end

	end

	

	if last_only then

		result = {result#result]}

	end

	

	if include_self then

		local label_self, link_self

		_, label_self = getPropertyValue(id, propertyLabel, label_format, languages, labelicon0, "infoboxlabel")

		link_self, _ = getLabelByLangs(id, languages)

		table.insert(result, 1, {label_self, link_self})

	end

	

	return result

end



local function parentObjectsToString(result,

	rowformat,

	cascade,

	sorting)

	

	local ret = {}

	local first = 1

	local last = #result

	local iter = 1

	if sorting == "-1" then first = #result; last = 1; iter = -1 end

	for i = first, last, iter do

		local rowtext = mw.ustring.gsub(rowformat, "$[01]", {["$0" = resulti][1], "$1" = resulti][2]})

		ret#ret + 1 = expandBraces(rowtext, rowformat)

	end

	

	if cascade then

		local direction = mw.language.new(wiki.langcode):isRTL() and "right" or "left"

		local suffix = ""

		for i = 1, #ret do

			reti = '<ul style="line-height:100%; margin-' .. direction .. ':0.45em; padding-' .. direction .. ':0;"><li>' .. reti

			suffix = suffix .. '</li></ul>'

		end

		ret#ret = ret#ret .. suffix

	end

	

	return ret

end



-- Returns pairs of parent label and property value fetching a recursive tree

function p.getParentValues(frame)

	local args = frame.args or frame -- via invoke or require

	local pargs = frame.args and frame:getParent().args or {}

	if not required and isSet(pargs.sandbox) then

		return require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).getParentValues(frame)

	end

	local id = getEntityId(args, pargs)

	if id == nil then return end

	local languages = findLang(args.lang)

	local propertySup = getArg(args.property, "P131") --administrative entity

	local propertyLabel = getArg(args.label, "P31") --instance

	local propertyLink = getArg(args.valuetext)

	local property_format = getArg(args.formatting)

	local label_format = getArg(args.labelformat, "label")

	local upto_number = getArg(args.upto)

	local last_only = getArg(args.last_only, false)

	local editicon, labelicon = setIcons(args.editicon, pargs.editicon)

	local include_self = getArg(args.include_self, false)

	local case = getArg(args.case)

	

	local upto_label = {}

	for q in string.gmatch(args.uptolabelid or '', 'Q%d+') do

		local checked_q = resolveEntityId(q)

		if checked_q then

			upto_labelchecked_q = true

		end

	end

	if type(upto_number) == 'string' then

		upto_labeluc_first(upto_number)] = true

		upto_number = nil

		require(wiki.module_title .. '/debug').track('upto') -- replace upto by uptolabelid

	end

	

	local upto_value = {}

	for q in string.gmatch(args.uptovalueid or args.uptolinkid or '', 'Q%d+') do

		local checked_q = resolveEntityId(q)

		if checked_q then

			upto_valuechecked_q = true

		end

	end

	

	local label_show = {}

	for q in string.gmatch(args.showlabelid or '', 'Q%d+') do

		local checked_q = resolveEntityId(q)

		if checked_q then

			label_showchecked_q = true

		end

	end

	for _, v in ipairs(mw.text.split(args.labelshow or '', "/")) do

		if v ~= '' then

			label_showuc_first(v)] = true

			require(wiki.module_title .. '/debug').track('labelshow') -- replace labelshow by showlabelid

		end

	end

	

	local rowformat = args.rowformat; if not isSet(rowformat) then rowformat = "$0 = $1" end

	local labelicon0, labelicon1 = labelicon, labelicon

	if string.find(label_format, '{{.*$0.*}}') or (string.find(rowformat, '{{.*$0.*}}') and label_format ~= 'raw') then

		labelicon0 = false

	end

	

	local result = getParentObjects(id,

		property_format,

		label_format,

		languages, 

		propertySup, 

		propertyLabel,

		propertyLink,

		label_show,

		labelicon0,

		labelicon1,

		upto_number,

		upto_label,

		upto_value,

		last_only,

		case,

		include_self)

	if #result == 0 then return end

	

	local separator = args.separator; if not isSet(separator) then separator = "<br />" end

	local sorting = args.sorting; if sorting == "" then sorting = nil end

	local cascade = (args.cascade == "true" or args.cascade == "yes")

	

	local ret = parentObjectsToString(result,

		rowformat,

		cascade,

		sorting)

	ret = addEditIconTable(ret, {property=propertySup, editicon=editicon, id=id, lang=languages})

	return mw.text.listToText(ret, separator, separator)

end



-- Link with a parent label --------------------

function p.linkWithParentLabel(frame)

	local pargs = frame.args and frame:getParent().args or {}

	if not required and isSet(pargs.sandbox) then

		return require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).linkWithParentLabel(frame)

	end

	local args = {}

	if frame.args then

		for k, v in pairs(frame.args) do -- metatable

			argsk = v

		end

	else

		args = frame -- via require

	end

	if isSet(args.value) then

		return args.value

	end

	

	-- get id value of property/qualifier

	local largs = mw.clone(args)

	largs.list = tonumber(args.list) and args.list or true

	largs.formatting = "raw"

	largs.separator = "/·/"

	largs.editicon = false

	local items_list, _ = p.claim(largs)

	if not isSet(items_list) then return end

	local items_table = mw.text.split(items_list, "/·/", true)

	

	-- get internal link of property/qualifier

	largs.formatting = "internallink"

	local link_list, _ = p.claim(largs)

	local link_table = mw.text.split(link_list, "/·/", true)

	

	-- get label of parent property

	local parent_claim = getSnak(getStatements(items_table1], args.parent, true), {1, "mainsnak", "datatype"})

	if parent_claim == 'monolingualtext' then

		largs.formatting = nil

		largs.list = 'lang'

	else

		largs.formatting = "label"

		largs.list = false

	end

	largs.property = args.parent

	largs.qualifier = nil

	for i, v in ipairs(items_table) do

		largs.item = v

		local link_label, _ = p.claim(largs)

		if isSet(link_label) then

			link_tablei = mw.ustring.gsub(link_tablei or '', "%[%[(.*)%|.+%]%]", "[[%1|" .. link_label .. "]]")

		end

	end

	args.editicon, _ = setIcons(args.editicon, pargs.editicon)

	args.id = getEntityId(args, pargs)

	args.lang = findLang(args.lang)

	return mw.text.listToText(link_table) .. addEditIcon(args)

end



-- Calculate number of years old ----------------------------

function p.yearsOld(frame)

	if not required and frame.args and isSet(frame:getParent().args.sandbox) then

		return require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).yearsOld(frame)

	end

	local args = frame.args or frame -- via invoke or require

	local pargs = frame.args and frame:getParent().args or {}

	local id = getEntityId(args, pargs)

	if id == nil then return end

	local lang = mw.language.new('en')

	

	local function getBestValue(id, prop)

		return getSnak(mw.wikibase.getBestStatements(id, prop), {1, "mainsnak", "datavalue", "value"})

	end

	

	local birth = getBestValue(id, 'P569')

	if type(birth) ~= 'table' or birth.time == nil or birth.precision == nil or birth.precision < 8 then

		return

	end

	local death = getBestValue(id, 'P570')

	if type(death) ~= 'table' or death.time == nil or death.precision == nil then

		death = {['time' = lang:formatDate('c'), 'precision' = 11} -- current date

	elseif death.precision < 8 then

		return

	end

	

	local dates = {}

	dates1 = {['min' = {}, 'max' = {}, 'precision' = birth.precision}

	dates1].min.year = tonumber(mw.ustring.match(birth.time, "^[+-]?%d+"))

	dates1].min.month = tonumber(mw.ustring.match(birth.time, "\-(%d%d)\-"))

	dates1].min.day = tonumber(mw.ustring.match(birth.time, "\-(%d%d)T"))

	dates1].max = mw.clone(dates1].min)

	dates2 = {['min' = {}, 'max' = {}, 'precision' = death.precision}

	dates2].min.year = tonumber(mw.ustring.match(death.time, "^[+-]?%d+"))

	dates2].min.month = tonumber(mw.ustring.match(death.time, "\-(%d%d)\-"))

	dates2].min.day = tonumber(mw.ustring.match(death.time, "\-(%d%d)T"))

	dates2].max = mw.clone(dates2].min)

	

	for i, d in ipairs(dates) do

		if d.precision == 10 then -- month

			d.min.day = 1

			local timestamp = string.format("%04d", tostring(math.abs(d.max.year)))

				.. string.format("%02d", tostring(d.max.month))

				.. "01"

			d.max.day = tonumber(lang:formatDate("j", timestamp .. " + 1 month - 1 day"))

		elseif d.precision < 10 then -- year or decade

			d.min.day = 1

			d.min.month = 1

			d.max.day = 31

			d.max.month = 12

			if d.precision == 8 then -- decade

				d.max.year = d.max.year + 9

			end

		end

	end

	

	local function age(d1, d2)

		local years = d2.year - d1.year

		if d2.month < d1.month or (d2.month == d1.month and d2.day < d1.day) then

			years = years - 1

		end

		if d2.year > 0 and d1.year < 0 then

			years = years - 1 -- no year 0

		end

		return years

	end

	

	local old_min = age(dates1].max, dates2].min)

	local old_max = age(dates1].min, dates2].max)

	local old, old_expr

	if old_min == 0 and old_max == 0 then

		old = "< 1"

		old_max = 1 -- expression in singular

	elseif old_min == old_max then

		old = old_min

	else

		old = old_min .. "/" .. old_max

	end

	if args.formatting == 'unit' then

		local langs = findLang(args.lang)

		local yo, yo_sg, yo_pl, yo_pau

		if langs1 == wiki.langcode then

			yo_sg = i18n"years-old"].singular

			yo_pl = i18n"years-old"].plural

			yo_pau = i18n"years-old"].paucal

		end

		if not isSet(yo_pl) then

			yo_pl, _ = getLabelByLangs('Q24564698', langs)

			yo_sg = yo_pl

		end

		if not isSet(yo_pau) then

			yo_pau = yo_pl

		end

		yo = mw.language.new(langs1]):plural(old_max, {yo_sg, yo_pau, yo_pl})

		if mw.ustring.find(yo, '$1', 1, true) then

			old_expr = mw.ustring.gsub(yo, "$1", old)

		else

			old_expr = old .. '&nbsp;' .. yo

		end

	elseif args.formatting then

		old_expr = expandBraces(mw.ustring.gsub(args.formatting, '$1', old), args.formatting)

	else

		old_expr = old

	end

	

	return old_expr

end



-- Gets a label in a given language (content language by default) or its fallbacks, optionnally linked.

function p.getLabel(frame)

	local args = frame.args or frame -- via invoke or require

	local pargs = frame.args and frame:getParent().args or {}

	if not required and isSet(pargs.sandbox) then

		return require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).getLabel(frame)

	end

	local id = getEntityId(args, pargs, 1)

	if id == nil then return end

	local languages = findLang(args.lang)

	local labelicon = false

	if mw.wikibase.isValidEntityId(id) then

		_, labelicon = setIcons(args.editicon, pargs.editicon)

	end

	

	local label_icon = ''

	local label, lang

	if args.label then

		label = args.label

	else

		-- exceptions or labels fixed

		local exist, labels = pcall(require, wiki.module_title .. "/labels" .. (languages1 == wiki.langcode and '' or '/' .. languages1]))

		if exist and labels.infoboxLabelsFromId and next(labels.infoboxLabelsFromId) ~= nil then

			label = labels.infoboxLabelsFromIdid

		end

		

		if label == nil then

			label, lang = getLabelByLangs(id, languages)

			if label then

				if isSet(args.itemgender) and feminineGender(args.itemgender) then

					label = feminineForm(id, lang) or label

				end

				label = mw.language.new(lang):ucfirst(mw.text.nowiki(label)) -- sanitize

				if args.case then

					label = case(args.case, label, lang)

				end

			end

			label_icon = addLabelIcon(id, lang, languages1], labelicon)

		end

	end

	

	local linked = args.linked

	local ret2 = required and untranslated or ''

	if isSet(linked) and linked ~= "no" then

		local article = mw.wikibase.getSitelink(id) or ("d:Special:EntityPage/" .. id)

		return "[[" .. article .. "|" .. (label or id) .. "]]" .. label_icon, ret2

	else

		return (label or id) .. label_icon, ret2

	end

end



-- Utilities -----------------------------

-- See also module ../debug.



-- Copied from Module:Wikibase

function p.getSiteLink(frame)

	local args = frame.args or frame -- via invoke or require

	local pargs = frame.args and frame:getParent().args or {}

	local id = getEntityId(args, pargs, 1)

	if id == nil then return end

	return mw.wikibase.getSitelink(id, mw.text.trim(args2 or ''))

end



-- Helper function for the default language code used

function p.lang(frame)

	local lang = frame and frame.args1 -- nil via require

	return findLang(lang)[1

end



-- Number of statements

function p.numStatements(frame)

	local args = frame.args or frame -- via invoke or require

	local pargs = frame.args and frame:getParent().args or {}

	local id = getEntityId(args, pargs)

	if id == nil then return 0 end

	local prop = mw.text.trim(args1 or '')

	local num = {}

	if not isSet(prop) and frame.args then

		args = {}

		for k, v in pairs(pargs) do

			argsk = v

		end

		for k, v in pairs(frame.args) do

			argsk = v

		end

		args.query = 'num'

		_, num = p.claim(args)

		return num

	elseif args2 then -- qualifier

		local qual = mw.text.trim(args2])

		local values = p.claim{item=id, property=prop, qualifier=qual, formatting='raw', separator='/·/'}

		if values then

			num = mw.text.split(values, '/·/')

		end

	else

		num = mw.wikibase.getBestStatements(id, prop)

	end

	return #num

end



-- Returns true if property datavalue is found excluding novalue/somevalue

function p.validProperty(frame)

	local args = frame.args or frame -- via invoke or require

	local pargs = frame.args and frame:getParent().args or {}

	local item = getEntityId(args, pargs)

	if item == nil then return end

	local property = mw.text.trim(args1])

	local prop_data = getSnak(mw.wikibase.getBestStatements(item, property), {1, "mainsnak", "datavalue"})

	return prop_data and true or nil

end



function p.editAtWikidata(frame)

	local args = frame.args or frame -- via invoke or require

	local pargs = frame.args and frame:getParent().args or {}

	local value = isSet(args1])

	if value then return end

	local param = {}

	param.id = getEntityId(args, pargs)

	param.property = args.property

	param.lang = findLang(args.lang)

	param.editicon, _ = setIcons(args.editicon)

	return addEditIcon(param)

end



function p.formatNum(frame)

	local num = tonumber(mw.text.trim(frame.args1]))

	local lang = findLang(mw.text.trim(frame.args2]))

	return mw.language.new(lang1]):formatNum(num)

end



return p
From Wikipedia, the free encyclopedia

-- version 20210304 from master @cawiki



local p = {}



-- Initialization of variables --------------------



local i18n = {						-- internationalisation at [[Module:Wikidata/i18n]]

	"errors" = {

		"property-not-found" = "Property not found.",

		"qualifier-not-found" = "Qualifier not found.",

	},

	

	"datetime" = {

		-- $1 is a placeholder for the actual number

		"beforenow" = "$1 BCE",	-- how to format negative numbers for precisions 0 to 5

		"afternow" = "$1 CE",		-- how to format positive numbers for precisions 0 to 5

		"bc" = "$1 BCE",			-- how print negative years

		"ad" = "$1",				-- how print 1st century AD dates

		

		0 = "$1 billion years",	-- precision: billion years

		1 = "$100 million years",	-- precision: hundred million years

		2 = "$10 million years",	-- precision: ten million years

		3 = "$1 million years",	-- precision: million years

		4 = "$100000 years",		-- precision: hundred thousand years; thousand separators added afterwards

		5 = "$10000 years",		-- precision: ten thousand years; thousand separators added afterwards

		6 = "$1 millennium",		-- precision: millennium

		7 = "$1 century",			-- precision: century

		8 = "$1s",				-- precision: decade

		-- the following use the format of #time parser function

		9 = "Y",					-- precision: year, 

		10 = "F Y",				-- precision: month

		11 = "F j, Y",			-- precision: day

		

		"hms" = {["hours" = "h", "minutes" = "m", "seconds" = "s"},	-- duration: xh xm xs

	},

	

	"years-old" = {

		"singular" = "",			-- year old, as in {{PLURAL:$1|singular|plural}}

		"plural" = "",			-- years old

		"paucal" = "",			-- for languages with 3 plural forms as in {{PLURAL:$1|singular|paucal|plural}}

	},

	

	"cite" = {					-- cite parameters

		"title" = "title",

		"author" = "author",

		"date" = "date",

		"pages" = "pages",

		"language" = "language",

		-- cite web parameters

		"url" = "url",

		"website" = "website",

		"access-date" = "access-date",

		"archive-url" = "archive-url",

		"archive-date" = "archive-date",

		"publisher" = "publisher",

		"quote" = "quote",

		-- cite journal parameters

		"work" = "work",

		"issue" = "issue",

		"issn" = "issn",

		"doi" = "doi"

	},

	

	-- default local wiki settings

	"addpencil" = false, -- adds a pencil icon linked to Wikidata statement, planned to overwrite by Wikidata Bridge

	"categorylabels" = "", -- Category:Pages with Wikidata labels not translated (void for no local category)

	"categoryprop" = "", -- Category:Pages using Wikidata property $1 (void for no local category)

	"categoryref" = "", -- Category:Pages with references from Wikidata (void for no local category)

	"addfallback" = {} -- additional fallback language codes

}



local cases = {} -- functions for local grammatical cases defined at [[Module:Wikidata/i18n]]



local required = ... -- variadic arguments from require function

local wiki = 

{

	langcode = mw.language.getContentLanguage().code,

	module_title = required or mw.getCurrentFrame():getTitle()

}



local untranslated -- used in infobox modules: nil or true

local _ -- variable for unused returned values, avoiding globals



-- Module local functions --------------------------------------------



-- Credit to http://stackoverflow.com/a/1283608/2644759, cc-by-sa 3.0

local function tableMerge(t1, t2)

	for k, v in pairs(t2) do

		if type(v) == "table" then

			if type(t1k or false) == "table" then

				tableMerge(t1k or {}, t2k or {})

			else

				t1k = v

			end

		else

			t1k = v

		end

	end

	return t1

end



local function loadI18n(lang)

	local exist, res = pcall(require, wiki.module_title .. "/i18n")

	if exist and next(res) ~= nil then

		tableMerge(i18n, res.i18n)

		cases = res.cases

	end

	if lang ~= wiki.langcode then

		exist, res = pcall(require, wiki.module_title .. "/i18n/" .. lang)

		if exist and next(res) ~= nil then

			tableMerge(i18n, res.i18n)

			tableMerge(cases, res.cases)

		end

	end

end



-- Table of language codes: requested or default and its fallbacks

local function findLang(langcode)

	if mw.language.isKnownLanguageTag(langcode or '') == false then

		local cframe = mw.getCurrentFrame()

		local pframe = cframe:getParent()

		langcode = pframe and pframe.args.lang

		if mw.language.isKnownLanguageTag(langcode or '') == false then

			if not mw.title.getCurrentTitle().isContentPage then

				langcode = cframe:preprocess('{{int:lang}}')

			end

			if mw.language.isKnownLanguageTag(langcode or '') == false then

				langcode = wiki.langcode

			end

		end

	end

	

	loadI18n(langcode)

	

	local languages = mw.language.getFallbacksFor(langcode)

	table.insert(languages, 1, langcode)

	if langcode == wiki.langcode then

		for _, l in ipairs(i18n.addfallback) do

			table.insert(languages, l)

		end

	end

	

	return languages

end



-- Argument is 'set' when it exists (not nil) or when it is not an empty string.

local function isSet(var)

	return not (var == nil or (type(var) == 'string' and mw.text.trim(var) == ''))

end



-- Set local case to a label

local function case(localcase, label, ...)

	if not isSet(label) then return label end

	

	if type(localcase) == "function" then

		return localcase(label)

	elseif localcase == "smallcaps" then

		return '<span style="font-variant: small-caps;">' .. label .. '</span>'

	elseif caseslocalcase then

		return caseslocalcase](label, ...)

	end

	

	return label

end



-- get safely a serialized snak

local function getSnak(statement, snaks)

	local ret = statement

	for i, v in ipairs(snaks) do

		if not ret then return end

		ret = retv

	end

	return ret

end



-- mw.wikibase.getLabelWithLang or getLabelByLang with a table of languages

local function getLabelByLangs(id, languages)

	local label

	local lang

	for _, l in ipairs(languages) do

		if l == wiki.langcode then

			-- using getLabelWithLang when possible instead of getLabelByLang, do not solve redirects pending phab:T157868

			label, l = mw.wikibase.getLabelWithLang(id)

		else

			label = mw.wikibase.getLabelByLang(id, l)

		end

		if label then

			lang = l

			break

		end

	end

	return label, lang

end



-- getBestStatements if bestrank=true, else getAllStatements with no deprecated

local function getStatements(entityId, property, bestrank)

	local claims = {}

	if not (entityId and mw.ustring.match(property, "^P%d+$")) then return claims end

	if bestrank then

		claims = mw.wikibase.getBestStatements(entityId, property)

	else

		local allclaims = mw.wikibase.getAllStatements(entityId, property)

		for _, c in ipairs(allclaims) do

			if c.rank ~= "deprecated" then

				table.insert(claims, c)

			end

		end

	end

	return claims

end



-- Is gender femenine? true or false

local function feminineGender(id)

	local claims = mw.wikibase.getBestStatements(id or mw.wikibase.getEntityIdForCurrentPage(),'P21')

	local gender_id = getSnak(claims, {1, "mainsnak", "datavalue", "value", "id"})

	if gender_id == "Q6581072" or gender_id == "Q1052281" or gender_id == "Q43445" then -- female, transgender female, female organism

		return true

	end

	return false

end



-- Fetch female form of label

local function feminineForm(id, lang)

	local feminine_claims = getStatements(id, 'P2521')

	for _, feminine_claim in ipairs(feminine_claims) do

		if getSnak(feminine_claim, {'mainsnak', 'datavalue', 'value', 'language'}) == lang then

			return feminine_claim.mainsnak.datavalue.value.text

		end

	end

end



-- Add an icon for no label in requested language

local function addLabelIcon(label_id, lang, uselang, icon)

	local ret_lang, ret_icon = '', ''

	if icon then

		if lang and lang ~= uselang then

			ret_lang = " <sup>(" .. lang .. ")</sup>"

		end

		if label_id and (lang == nil or lang ~= uselang) then

			local namespace = ''

			if string.sub(label_id, 1, 1) == 'P' then

				namespace = 'Property:'

			end

			ret_icon = " [[File:Noun Project label icon 1116097 cc mirror.svg|10px|baseline|"

				.. mw.message.new('Translate-taction-translate'):inLanguage(uselang):plain()

				.. "|link=https://www.wikidata.org/wiki/" .. namespace .. label_id .. "?uselang=" .. uselang .. "]]"

			untranslated = true

		end

		if isSet(i18n.categorylabels) and lang ~= uselang and uselang == wiki.langcode then

			ret_icon = ret_icon .. '[[' .. i18n.categorylabels .. (lang and ']]' or '/Q]]')

		end

	end

	return ret_lang .. ret_icon

end



-- editicon values: true/false (no=false), right, void defaults to i18n.addpencil

-- labelicon only by parameter

local function setIcons(arg, parg)

	local val = arg == nil and parg or arg

	local edit_icon, label_icon

	if not isSet(val) then

		edit_icon, label_icon = i18n.addpencil, true

	elseif val == false or val == "false" or val == "no" then

		edit_icon, label_icon = false, false

	else

		edit_icon, label_icon = val, true

	end

	return edit_icon, label_icon

end



-- Add an icon for editing a statement with requirements for Wikidata Bridge

local function addEditIcon(parameters)

	local ret = ''

	if parameters.editicon and parameters.id and parameters.property then

		local icon_style = parameters.editicon == "right" and ' style="float: right;"' or ''

		ret = ' <span class="penicon" data-bridge-edit-flow="single-best-value"' .. icon_style .. '>'

			.. "[[File:Arbcom ru editing.svg|10px|baseline|"

			.. string.gsub(mw.message.new('Wikibase-client-data-bridge-bailout-suggestion-go-to-repo-button'):inLanguage(parameters.lang1]):plain(), '{{WBREPONAME}}', 'Wikidata')

			.. "|link=https://www.wikidata.org/wiki/" .. parameters.id .. "?uselang=" .. parameters.lang1 .. "#" .. parameters.property .. "]]"

			.. "</span>"

		if isSet(i18n.categoryprop) then

			ret = ret .. "[[" .. string.gsub(i18n.categoryprop, '$1', parameters.property) .. "]]"

		end

	end

	return ret

end

-- add edit icon to the last element of a table

local function addEditIconTable(thetable, parameters)

	if #thetable == 0 or parameters.editicon == false then

		return thetable

	end

	local last_element = thetable#thetable

	local the_icon = addEditIcon(parameters)

	-- add it before last html closing tags

	local tags = ''

	local rev_element = string.reverse(last_element)

	for tag in string.gmatch(rev_element, '(>%l+/<)') do

		if string.match(rev_element, '^' .. tags .. tag) then

			tags = tags .. tag

		else

			break

		end

	end

	local last_tags = string.reverse(tags)

	local offset = string.find(last_element, last_tags .. '$')

	if offset then

		thetable#thetable = string.sub(last_element, 1, offset - 1) .. the_icon .. last_tags

	else

		thetable#thetable = last_element .. the_icon

	end

	return thetable

end



-- Escape Lua captures

local function captureEscapes(text)

	return mw.ustring.gsub(text, "(%%%d)", "%%%1")

end



-- expandTemplate or callParserFunction

local function expandBraces(text, formatting)

	if text == nil or formatting == nil then return text end

	-- only expand braces if provided in argument, not included in value as in Q1164668

	if mw.ustring.find(formatting, '{{', 1, true) == nil then return text end

	if type(text) ~= "string" then

		text = tostring(text)

	end

	

	for braces in mw.ustring.gmatch(text, "{{(.-)}}") do

		local parts = mw.text.split(braces, "|")

		local title_part = parts1

		local parameters = {}

		for i = 2, #parts do

			local subparts = mw.ustring.find(partsi], "=")

			if subparts then

				local param_name = mw.ustring.sub(partsi], 1, subparts - 1)

				local param_value = mw.ustring.sub(partsi], subparts + 1, -1)

				-- reconstruct broken links by parts

				if i < #parts and mw.ustring.find(param_value, "[[", 1, true) and not mw.ustring.find(param_value, "]]", 1, true) then

					parametersparam_name = param_value

					local part_next = i + 1

					while partspart_next and mw.ustring.find(partspart_next], "]]", 1, true) do

						parametersparam_name = parametersparam_name .. "|" .. partspart_next

						part_next = part_next + 1

					end

				else

					parametersparam_name = param_value

				end

			elseif not mw.ustring.find(partsi], "]]", 1, true) then

				table.insert(parameters, partsi])

			end

		end

		

		local braces_expanded

		if mw.ustring.find(title_part, ":")

			and mw.text.split(title_part, ":")[1 ~= mw.site.namespaces10].name -- not a prefix Template:

			then

			braces_expanded = mw.getCurrentFrame():callParserFunction{name=title_part, args=parameters}

		else

			braces_expanded = mw.getCurrentFrame():expandTemplate{title=title_part, args=parameters}

		end

		braces = mw.ustring.gsub(braces, "([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1") -- escape magic characters

		braces_expanded = captureEscapes(braces_expanded)

		text = mw.ustring.gsub(text, "{{" .. braces .. "}}", braces_expanded)

	end

	

	return text

end



-- Resolve Wikidata redirects, pending phab:T157868

local function resolveEntityId(id)

	if not id or not mw.wikibase.isValidEntityId(id) then return id end

	-- if no label in English, maybe it is a redirect

	-- not using mw.title.new(id).isRedirect as it is expensive

	-- currently getLabelByLang does not follows redirects

	if mw.wikibase.getLabelByLang(id, 'en') == nil then

		local entity = mw.wikibase.getEntity(id) -- expensive function

		if not entity then return nil end

		if id ~= entity.id then

			-- Qid redirected to be fixed

			-- see [[Special:WhatLinksHere/Template:Track/wikidata/redirect]]

			require(wiki.module_title .. '/debug').track('redirect')

			require(wiki.module_title .. '/debug').track('redirect/' .. id)

		else

			-- no redirect and no English label, fix it to avoid expensive functions

			require(wiki.module_title .. '/debug').track('label')

			require(wiki.module_title .. '/debug').track('label/' .. id)

		end

		return entity.id

	end

	return id

end



-- format data type math

local function printDatatypeMath(data)

	return mw.getCurrentFrame():callParserFunction('#tag:math', data)

end



-- format data type musical-notation

local function printDatatypeMusical(data, formatting)

	local attr = {}

	if formatting == 'sound' then

		attr.sound = 1

	end

	return mw.getCurrentFrame():extensionTag('score', data, attr)

end



-- format data type string

local function printDatatypeString(data, parameters)

	if mw.ustring.find((parameters.formatting or ''), '$1', 1, true) then -- formatting = a pattern

		return expandBraces(mw.ustring.gsub(parameters.formatting, '$1', {['$1' = data}), parameters.formatting)

	elseif parameters.case then

		return case(parameters.case, data, parameters.lang1], feminineGender(parameters.id))

	end

	local data_number = string.match(data, "^%d+")

	if data_number then -- sort key by initial number and remaining string

		local sortkey = string.format("%019d", data_number * 1000)

		return data, sortkey .. string.sub(data, #data_number + 1)

	end

	return data

end



-- format data type url

local function printDatatypeUrl(data, parameters)

	if parameters.formatting == 'weblink' then

		local label_parts = mw.text.split(string.gsub(data, '/$', ''), '/')

		local label = string.gsub(label_parts3], '^www%.', '')

		if #label_parts > 3 then

			label = label .. '…'

		end

		return '[' .. data .. ' ' .. label .. ']'

	end

	return printDatatypeString(data, parameters)

end



-- format data type external-id

local function printDatatypeExternal(data, parameters)

	if parameters.formatting == 'externalid' then

		local p_stat = mw.wikibase.getBestStatements(parameters.property, 'P1630') -- formatter URL

		local p_link_pattern = getSnak(p_stat, {1, "mainsnak", "datavalue", "value"})

		if p_link_pattern then

			local p_link = mw.ustring.gsub(p_link_pattern, '$1', {['$1' = data})

			return '[' .. p_link .. ' ' .. data .. ']'

		end

	end

	return printDatatypeString(data, parameters)

end



-- format data type commonsMedia and geo-shape

local function printDatatypeMedia(data, parameters)

	local icon

	if not string.find((parameters.formatting or ''), '$1', 1, true) then

		icon = "no-icon"

		if not string.find(data, '^Data:') then

			data = mw.uri.encode(data, 'PATH') -- encode special characters in filename

		end

	end

	return printDatatypeString(data, parameters), icon

end



-- format data type globe-coordinate

local function printDatatypeCoordinate(data, formatting)

	local function globes(globe_id)

		local globes = {['Q3134'='callisto',['Q596'='ceres',['Q15040'='dione',['Q2'='earth',['Q3303'='enceladus',

			'Q3143'='europa',['Q17975'='phoebe',['Q3169'='ganymede',['Q3123'='io',['Q17958'='iapetus',

			'Q308'='mercury',['Q15034'='mimas',['Q405'='moon',['Q15050'='rhea',['Q15047'='tethys',

			'Q111'='mars',['Q2565'='titan',['Q3359'='triton',['Q313'='venus',['Q3030'='vesta'}

		return globesglobe_id

	end

	

	local function roundPrecision(num, prec)

		if prec == nil or prec <= 0 then return num end

		local sig = 10^math.floor(math.log10(prec)+.5) -- significant figure from sexagesimal precision: 0.00123 -> 0.001

		return math.floor(num / sig + 0.5) * sig

	end

	

	local precision = data.precision

	local latitude = roundPrecision(data.latitude, precision)

	local longitude = roundPrecision(data.longitude, precision)

	if formatting and string.find(formatting, '$lat', 1, true) and string.find(formatting, '$lon', 1, true) then

		local ret = mw.ustring.gsub(formatting, '$l[ao][tn]', {['$lat' = latitude, '$lon' = longitude})

		if string.find(formatting, '$globe', 1, true) then

			local myglobe = 'earth'

			if isSet(data.globe) then

				local globenum = mw.text.split(data.globe, 'entity/')[2 -- http://www.wikidata.org/wiki/Q2

				myglobe = globes(globenum) or 'earth'

			end

			ret = mw.ustring.gsub(ret, '$globe', myglobe)

		end

		return expandBraces(ret, formatting)

	elseif formatting == 'latitude' then

		return latitude, "no-icon"

	elseif formatting == 'longitude' then

		return longitude, "no-icon"

	elseif formatting == 'dimension' then

		return data.dimension, "no-icon"

	else --default formatting='globe'

		if isSet(data.globe) == false or data.globe == 'http://www.wikidata.org/entity/Q2' then

			return 'earth', "no-icon"

		else

			local globenum = mw.text.split(data.globe, 'entity/')[2

			return globes(globenum) or globenum, "no-icon"

		end

	end

end



-- Local functions for data value quantity

local function unitSymbol(id, lang) -- get unit symbol or code

	local unit_symbol = ''

	if lang == wiki.langcode and pcall(require, wiki.module_title .. "/Units") then

		unit_symbol = require(wiki.module_title .. "/Units").getUnit(0, '', id, true)

	end

	if unit_symbol == '' then

		-- fetch it

		local claims = mw.wikibase.getBestStatements(id, 'P5061')

		if #claims > 0 then

			local langclaims = {}

			table.insert(lang, 'mul') -- multilingual as last try

			for _, snak in ipairs(claims) do

				local snak_language = getSnak(snak, {"mainsnak", "datavalue", "value", "language"})

				if snak_language and not langclaimssnak_language then -- just the first one by language

					langclaimssnak_language = snak.mainsnak.datavalue.value.text

				end

			end

			for _, l in ipairs(lang) do

				if langclaimsl then

					return langclaimsl

				end

			end

		end

	end

	return unit_symbol

end



local function getUnit(amount, id, parameters) -- get unit symbol or name

	local suffix = ''

	if parameters.formatting == "unitcode" then

		-- get unit symbol

		local unit_symbol = unitSymbol(id, parameters.lang)

		if isSet(unit_symbol) then

			suffix = unit_symbol

		end

	end

	if suffix == '' then -- formatting=unit, or formatting=unitcode not found

		-- get unit name

		local unit_label, lang = getLabelByLangs(id, parameters.lang)

		if lang == wiki.langcode and pcall(require, wiki.module_title .. "/Units") then

			suffix = require(wiki.module_title .. "/Units").getUnit(amount, unit_label, id, false)

		else

			suffix = (unit_label or id) .. addLabelIcon(id, lang, parameters.lang1], parameters.labelicon)

		end

	end

	if suffix ~= '' then

		suffix = ' ' .. suffix

	end

	return suffix

end



local function roundDefPrecision(in_num, factor)

	-- rounds out_num with significant figures of in_num (default precision)

	local out_num = in_num * factor

	if factor/60 == math.floor(factor/60) or out_num == 0 then -- sexagesimal integer or avoiding NaN

		return out_num

	end

	-- first, count digits after decimal mark, handling cases like '12.345e6'

	local exponent, prec

	local integer, dot, decimals, expstr = in_num:match('^(%d*)(%.?)(%d*)(.*)')

	local e = expstr:sub(1, 1)

	if e == 'e' or e == 'E' then

		exponent = tonumber(expstr:sub(2))

	end

	if dot == '' then

		prec = -integer:match('0*$'):len()

	else

		prec = #decimals

	end

	if exponent then

		-- So '1230' and '1.23e3' both give prec = -1, and '0.00123' and '1.23e-3' give 5.

		prec = prec - exponent

	end

	-- significant figures

	local in_bracket = 10^-prec -- -1 -> 10, 5 -> 0.00001

	local out_bracket = in_bracket * out_num / in_num

	out_bracket = 10^math.floor(math.log10(out_bracket)+.5) -- 1230 -> 1000, 0.00123 -> 0.001

	-- round it (credit to Luc Bloom from http://lua-users.org/wiki/SimpleRound)

	return math.floor(out_num/out_bracket + (out_num >=0 and 1 or -1) * 0.5) * out_bracket

end



-- format data type quantity

local function printDatatypeQuantity(data, parameters)

	local amount = data.amount

	amount = mw.ustring.gsub(amount, "%+", "")

	local suffix = ""

	local conv_amount, conv_suffix

	if string.sub(parameters.formatting or '', 1, 4) == "unit" or string.sub(parameters.formatting or '', 1, 8) == "duration" or parameters.convert then

		local unit_id = data.unit

		unit_id = mw.ustring.sub(unit_id, mw.ustring.find(unit_id, "Q"), -1)

		if string.sub(unit_id, 1, 1) == "Q" then

			suffix = getUnit(amount, unit_id, parameters)

			local convert_to

			if parameters.convert == "default" or parameters.convert == "default2" then

				local exist, units = pcall(require, wiki.module_title .. "/Units")

				if exist and units.convert_default and next(units.convert_default) ~= nil then

					convert_to = units.convert_defaultunit_id

				end

			elseif string.sub(parameters.convert or '', 1, 1) == "Q" then

				convert_to = resolveEntityId(parameters.convert)

			elseif string.sub(parameters.formatting or '', 1, 8) == "duration" then

				convert_to = 'Q11574' -- seconds

			end

			if convert_to and convert_to ~= unit_id then

				-- convert units

				local conv_temp = { -- formulae for temperatures ºC, ºF, ªK: [from] = {[to] = 'formula'}

					'Q25267' = {['Q42289' = '$1*1.8+32', 'Q11597' = '$1+273.15'},

					'Q42289' = {['Q25267' = '($1-32)/1.8', 'Q11597' = '($1+459.67)*5/9'},

					'Q11597' = {['Q25267' = '$1-273.15', 'Q42289' = '($1-273.15)*1.8000+32.00'}

				}

				if conv_tempunit_id and conv_tempunit_id][convert_to then

					local amount_f = mw.getCurrentFrame():callParserFunction('#expr', mw.ustring.gsub(conv_tempunit_id][convert_to], "$1", amount))

					conv_amount = math.floor(tonumber(amount_f) + 0.5)

				else

					local conversions = getStatements(unit_id, 'P2442') -- conversion to standard unit

					table.insert(conversions, mw.wikibase.getBestStatements(unit_id, 'P2370')[1]) -- conversion to SI unit

					for _, conv in ipairs(conversions) do

						if conv.mainsnak.snaktype == 'value' then -- no somevalue nor novalue

							if conv.mainsnak.datavalue.value.unit == "http://www.wikidata.org/entity/" .. convert_to then

								conv_amount = roundDefPrecision(amount, tonumber(conv.mainsnak.datavalue.value.amount))

								break

							end

						end

					end

				end

				if conv_amount then

					conv_suffix = getUnit(conv_amount, convert_to, parameters)

				end

			elseif parameters.convert == 'M' and tonumber(amount) > 10^8 then

				conv_amount = math.floor(amount/10^6 + 0.5)

				conv_suffix = ' M' .. string.sub(suffix, 2)

			end

		end

	end

	local lang_obj = mw.language.new(parameters.lang1])

	local sortkey = string.format("%019d", tonumber(amount) * 1000)

	if string.sub(parameters.formatting or '', 1, 8) == "duration" then

		local sec = tonumber(conv_amount or amount)

		if parameters.formatting == 'durationhms' or parameters.formatting == 'durationh:m:s' then

			local intervals = {"hours", "minutes", "seconds"}

			local sec2table = lang_obj:getDurationIntervals(sec, intervals)

			sec2table"seconds" = (sec2table"seconds" or 0) + tonumber("." .. (tostring(sec):match("%.(%d+)") or "0")) -- add decimals

			local duration = ''

			for i, v in ipairs(intervals) do

				if parameters.formatting == 'durationh:m:s' then

					if i == 1 and sec2tablev then

						duration = duration .. sec2tablev .. ":"

					elseif i == 2 then

						duration = duration .. string.format("%02d", sec2tablev or 0) .. ":"

					elseif i == 3 then

						local sec_str = tostring(lang_obj:formatNum(sec2tablev or 0))

						duration = duration .. (sec2tablev < 10 and "0" or "") .. sec_str

					end

				elseif sec2tablev then

					duration = duration .. lang_obj:formatNum(sec2tablev]) .. i18n.datetime.hmsv .. (i < 3 and " " or "")

				end

			end

			return duration

		else

			return lang_obj:formatDuration(sec)

		end

	end

	if parameters.case then

		amount = case(parameters.case, amount, parameters.lang1])

	elseif parameters.formatting ~= 'raw' then

		amount = lang_obj:formatNum(tonumber(amount))

	end

	if conv_amount then

		local conv_sortkey = string.format("%019d", conv_amount * 1000)

		conv_amount = lang_obj:formatNum(conv_amount)

		if parameters.convert == 'default2' then

			return conv_amount .. conv_suffix .. ' (' .. amount .. suffix .. ')', conv_sortkey

		else

			return conv_amount .. conv_suffix, conv_sortkey

		end

	elseif mw.ustring.find((parameters.formatting or ''), '$1', 1, true) then -- formatting with pattern

		amount = mw.ustring.gsub(parameters.formatting, '$1', {['$1' = amount})

	end

	return amount .. suffix, sortkey

end



-- format data type time

local function printDatatypeTime(data, parameters)

	-- Dates and times are stored in ISO 8601 format

	local timestamp = data.time

	local post_format

	local calendar_add = ""

	local precision = data.precision or 11

	

	if string.sub(timestamp, 1, 1) == '-' then

		post_format = i18n.datetime"bc"

	elseif string.sub(timestamp, 2, 3) == '00' then

		post_format = i18n.datetime"ad"

	elseif precision > 8 then

		-- calendar model

		local calendar_model = {["Q12138" = "gregorian", "Q1985727" = "gregorian", "Q11184" = "julian", "Q1985786" = "julian"}

		local calendar_id = mw.text.split(data.calendarmodel, 'entity/')[2

		if (timestamp < "+1582-10-15T00:00:00Z" and calendar_modelcalendar_id == "gregorian")

			or (timestamp > "+1582-10-04T00:00:00Z" and calendar_modelcalendar_id == "julian")

			then

			calendar_add = " <sup>(" .. mw.message.new('Wikibase-time-calendar-' .. calendar_modelcalendar_id]):inLanguage(parameters.lang1]):plain() .. ")</sup>"

		end

	end

	

	local function formatTime(form, stamp)

		local pattern

		if type(form) == "function" then

			pattern = form(stamp)

		else

			pattern = form

		end

		stamp = tostring(stamp)

		if mw.ustring.find(pattern, "$1") then

			return mw.ustring.gsub(pattern, "$1", stamp)

		elseif string.sub(stamp, 1, 1) == '-' then -- formatDate() only supports years from 0

			stamp = '+' .. string.sub(stamp, 2)

		elseif string.sub(stamp, 1, 1) ~= '+' then -- not a valid timestamp, it is a number

			stamp = string.format("%04d", stamp)

		end

		local ret = mw.language.new(parameters.lang1]):formatDate(pattern, stamp)

		ret = string.gsub(ret, "^(%[?%[?)0+", "%1") -- supress leading zeros

		ret = string.gsub(ret, "( %[?%[?)0+", "%1")

		return ret

	end

	

	local function postFormat(t)

		if post_format and mw.ustring.find(post_format, "$1") then

			return mw.ustring.gsub(post_format, "$1", t)

		end

		return t

	end

	

	local intyear = tonumber(string.match(timestamp, "[+-](%d+)"))

	local ret = ""

	

	if precision <= 5 then -- precision is 10000 years or more

		local factor = 10 ^ ((5 - precision) + 4)

		local y2 = math.ceil(math.abs(intyear) / factor)

		local relative = formatTime(i18n.datetimeprecision], y2)

		if post_format == i18n.datetime"bc" then

			ret = mw.ustring.gsub(i18n.datetime.beforenow, "$1", relative)

		else

			ret = mw.ustring.gsub(i18n.datetime.afternow, "$1", relative)

		end

		local ret_number = string.match(ret, "%d+")

		if ret_number ~= nil then

			ret = mw.ustring.gsub(ret, ret_number, mw.language.new(parameters.lang1]):formatNum(tonumber(ret_number)))

		end

	elseif precision == 6 or precision == 7 then -- millennia or centuries

		local card = math.floor((intyear - 1) / 10^(9 - precision)) + 1

		ret = formatTime(i18n.datetimeprecision], card)

		ret = postFormat(ret)

	elseif precision == 8 then -- decades

		local card = math.floor(math.abs(intyear) / 10) * 10

		ret = formatTime(i18n.datetime8], card)

		ret = postFormat(ret)

	elseif intyear > 9999 then -- not a valid timestamp

		return

	elseif precision == 9 or parameters.formatting == 'Y' then -- precision is year

		ret = formatTime(i18n.datetime9], intyear)

		ret = postFormat(ret) .. calendar_add

	elseif precision == 10 then -- month

		ret = formatTime(i18n.datetime10], timestamp .. " + 1 day") -- formatDate yyyy-mm-00 returns the previous month

		ret = postFormat(ret) .. calendar_add

	else -- precision 11, day

		ret = formatTime(parameters.formatting or i18n.datetime11], timestamp)

		ret = postFormat(ret) .. calendar_add

	end

	return ret, timestamp

end



-- format data value wikibase-entityid: types wikibase-item, wikibase-property

local function printDatatypeEntity(data, parameters)

	local entity_id = data'id'

	if parameters.formatting == 'raw' then

		return entity_id, entity_id

	end

	local entity_page = 'Special:EntityPage/' .. entity_id

	local label, lang = getLabelByLangs(entity_id, parameters.lang)

	local sitelink = mw.wikibase.getSitelink(entity_id)

	local parameter = parameters.formatting

	local labelcase = label or sitelink

	if parameters.gender == 'feminineform' then

		labelcase = feminineForm(entity_id, lang) or labelcase

	end

	if parameters.case ~= 'gender' then

		labelcase = case(parameters.case, labelcase, lang, parameters.lang1], entity_id, parameters.id)

	end

	local ret1, ret2

	if parameter == 'label' then

		ret1 = labelcase or entity_id

		ret2 = labelcase or entity_id

	elseif parameter == 'sitelink' then

		ret1 = (sitelink or 'd:' .. entity_page)

		ret2 = sitelink or entity_id

	elseif mw.ustring.find((parameter or ''), '$1', 1, true) then -- formatting = a pattern

		ret1 = mw.ustring.gsub(parameter, '$1', labelcase or entity_id)

		ret1 = expandBraces(ret1, parameter)

		ret2 = labelcase or entity_id

	else

		if parameter == "ucfirst" or parameter == "ucinternallink" then

			if labelcase and lang then

				labelcase = mw.language.new(lang):ucfirst(labelcase)

			end

			-- only first of a list, reset formatting for next ones

			if parameter == "ucinterlanllink" then

				parameters.formatting = 'internallink'

			else

				parameters.formatting = nil -- default format

			end

		end

		

		if sitelink then

			ret1 = '[[' .. sitelink .. '|' .. labelcase .. ']]'

			ret2 = labelcase

		elseif label and string.match(parameter or '', 'internallink$') and not mw.wikibase.getEntityIdForTitle(label) then

			ret1 = '[[' .. label .. '|' .. labelcase .. ']]'

			ret2 = labelcase

		else

			ret1 = '[[d:' .. entity_page .. '|<span style="color:#5f9cbb;">' .. (labelcase or entity_id) .. '</span>]]'

			ret2 = labelcase or entity_id

		end

	end

	

	return ret1 .. addLabelIcon(entity_id, lang, parameters.lang1], parameters.labelicon), ret2

end



-- format data type monolingualtext

local function printDatatypeMonolingual(data, parameters)

	-- data fields: language [string], text [string]

	

	if parameters.list == "lang" and data"language" ~= parameters.lang1 then

		return

	elseif parameters.list == "notlang" and data"language" == parameters.lang1 then

		return

	elseif parameters.formatting == "language" or parameters.formatting == "text" then

		return dataparameters.formatting

	end

	local result = data"text"

	if data"language" ~= wiki.langcode then

		result = mw.ustring.gsub('<span lang="$1">$2</span>', '$[12]', {["$1"=data"language"], "$2"=data"text"]})

	end

	if mw.ustring.find((parameters.formatting or ''), '$', 1, true) then

		-- output format defined with $text, $language

		result = mw.ustring.gsub(parameters.formatting, '$text', result)

		result = mw.ustring.gsub(result, '$language', data"language"])

	end

	return result

end



local function getSnakValue(snak, parameters)

	if snak.snaktype == 'value' then

		-- see Special:ListDatatypes

		if snak.datatype == "string" then

			return printDatatypeString(snak.datavalue.value, parameters)

		-- other data value string, tabular-data not implemented

		elseif snak.datatype == "commonsMedia" or snak.datatype == "geo-shape" then

			return printDatatypeMedia(snak.datavalue.value, parameters)

		elseif snak.datatype == "url" then

			return printDatatypeUrl(snak.datavalue.value, parameters)

		elseif snak.datatype == "external-id" then

			return printDatatypeExternal(snak.datavalue.value, parameters)

		elseif snak.datatype == 'math' then

			return printDatatypeMath(snak.datavalue.value)

		elseif snak.datatype == 'musical-notation' then

			return printDatatypeMusical(snak.datavalue.value, parameters.formatting)

		-- other data types

		elseif snak.datatype == 'wikibase-item' or snak.datatype == 'wikibase-property' then

			return printDatatypeEntity(snak.datavalue.value, parameters)

		elseif snak.datatype == 'monolingualtext' then

			return printDatatypeMonolingual(snak.datavalue.value, parameters)

		elseif snak.datatype == "globe-coordinate" then

			return printDatatypeCoordinate(snak.datavalue.value, parameters.formatting)

		elseif snak.datatype == "quantity" then

			return printDatatypeQuantity(snak.datavalue.value, parameters)

		elseif snak.datatype == "time" then

			return printDatatypeTime(snak.datavalue.value, parameters)

		end

	elseif snak.snaktype == 'novalue' then

		if parameters.formatting == 'raw' or parameters.shownovalue == false then return end

		return mw.message.new('Wikibase-snakview-snaktypeselector-novalue'):inLanguage(parameters.lang1]):plain()

	elseif snak.snaktype == 'somevalue' then

		if parameters.formatting == 'raw' then return end

		return mw.message.new('Wikibase-snakview-snaktypeselector-somevalue'):inLanguage(parameters.lang1]):plain()

	end

	return mw.wikibase.renderSnak(snak)

end



local function printError(key)

	return '<span class="error">' .. i18n.errorskey .. '</span>'

end



local function getQualifierSnak(claim, qualifierId, parameters)

	-- a "snak" is Wikidata terminology for a typed key/value pair

	-- a claim consists of a main snak holding the main information of this claim,

	-- as well as a list of attribute snaks and a list of references snaks

	if qualifierId then

		-- search the attribute snak with the given qualifier as key

		if claim.qualifiers then

			local qualifier = claim.qualifiersqualifierId

			if qualifier then

				if qualifier1].datatype == "monolingualtext" then

					-- iterate over monolingualtext qualifiers to get local language

					for idx in pairs(qualifier) do

						if getSnak(qualifieridx], {"datavalue", "value", "language"}) == parameters.lang1 then

							return qualifieridx

						end

					end

				elseif parameters.list then

					return qualifier

				else

					return qualifier1

				end

			end

		end

		return nil, printError("qualifier-not-found")

	else

		-- otherwise return the main snak

		return claim.mainsnak

	end

end



local function getValueOfClaim(claim, qualifierId, parameters)

	local snak, error = getQualifierSnak(claim, qualifierId, parameters)

	if not snak then

		return nil, nil, error

	elseif snak1 then -- a multi qualifier

		local result, sortkey = {}, {}

		local maxvals = tonumber(parameters.list)

		for idx in pairs(snak) do

			result#result + 1], sortkey#sortkey + 1 = getSnakValue(snakidx], parameters)

			if maxvals and maxvals == #result then break end

		end

		return mw.text.listToText(result, parameters.qseparator, parameters.qconjunction), sortkey1

	else -- a property or a qualifier

		return getSnakValue(snak, parameters)

	end

end



local function getValueOfParentClaim(claim, qualifierId, parameters)

	local qids = mw.text.split(qualifierId, '/', true)

	local value, sortkey, valueraw = {}, {}, {}

	local parent_raw, value_text

	if qids1 == parameters.property then

		parent_raw, _, _ = getValueOfClaim(claim, nil, {["formatting"="raw", "lang"=parameters.lang})

	else

		parent_raw, _, _ = getValueOfClaim(claim, qids1], {["formatting"="raw", "lang"=parameters.lang, "list"=true, "qseparator"='/', "qconjunction"='/'})

	end

	if string.sub(parent_raw or '', 1, 1) == "Q" then -- protection for 'no value'

		local parent_qids = mw.text.split(parent_raw, '/', true)

		for idx, p_qid in ipairs(parent_qids) do

			local parent_claims = mw.wikibase.getBestStatements(p_qid, qids2])

			if parent_claims1 then

				valueidx], sortkeyidx], _ = getValueOfClaim(parent_claims1], nil, parameters)

				-- raw parent value needed for while/black lists, lang for avoiding an error on types other than entity

				valuerawidx], _, _ = getValueOfClaim(parent_claims1], nil, {["formatting"="raw", "lang"=parameters.lang})

			end

		end

	end

	if value1 then

		value_text = mw.text.listToText(value, parameters.qseparator, parameters.qconjunction)

	end

	return value_text, sortkey1], valueraw1

end



-- see d:Help:Sources

local function getReferences(claim, lang)

	local notproperref = {

		"P143" = true, -- imported from

		"P3452" = true, -- inferred from

		"P887" = true, -- based on heuristic

		"P4656" = true -- Wikimedia import URL

	}

	local result = ""

	-- traverse through all references

	for ref in pairs(claim.references or {}) do

		local refparts

		local refs = {}

		local validref = true

		local ref_name

		-- traverse through all parts of the current reference

		for snakkey, snakval in pairs(claim.referencesref].snaks or {}) do

			for partkey, _ in pairs(claim.referencesref].snakssnakkey or {}) do

				if notproperrefsnakkey then -- not a proper reference

					validref = false

					break

				end

			end

			if validref then

				for snakidx = 1, #snakval do

					if snakidx > 1 then refparts = refparts .. ", " end

					refparts = refparts or '' .. (getSnakValue(snakvalsnakidx], {lang=lang}) or '')

				end

				refssnakkey = refparts

				refparts = nil

				if snakkey == "P248" then -- stated in

					ref_name = getSnak(snakval, {1, "datavalue", "value", "id"})

				end

			end

		end

		

		-- fill missing values with parent item

		if ref_name then

			local function refParent(qid, pid, formatting)

				local snak = getSnak(mw.wikibase.getBestStatements(qid, pid), {1, "mainsnak"})

				return snak and getSnakValue(snak, {formatting=formatting, lang=lang})

			end

			

			refs'P50' = refs'P50' or refParent(ref_name, 'P50', 'label') -- author

			refs'P407' = refs'P407' or refParent(ref_name, 'P407', 'label') -- language of work

			refs'P123' = refs'P123' or refParent(ref_name, 'P123', 'label') -- publisher

			refs'P577' = refs'P577' or refParent(ref_name, 'P577') -- date

			refs'P1433' = refs'P1433' or refParent(ref_name, 'P1433', 'label') -- published in

			refs'P304' = refs'P304' or refParent(ref_name, 'P304') -- page(s)

			refs'P433' = refs'P433' or refParent(ref_name, 'P433') -- issue

			refs'P236' = refs'P236' or refParent(ref_name, 'P236') -- ISSN

			refs'P356' = refs'P356' or refParent(ref_name, 'P356') -- DOI

			

			ref_name = ref_name .. claim.referencesref].hash

		end

		

		-- get title of local templates for citing references

		local template_web = mw.wikibase.getSitelink('Q5637226') or ""

		template_web = mw.text.split(template_web, ":")[2 -- split off namespace from front

		local template_journal = mw.wikibase.getSitelink('Q5624899') or ""

		template_journal = mw.text.split(template_journal, ":")[2

		

		local citeParams = {}

		if refs'P854' and (refs'P1476' or refs'P248']) and template_web then

			-- if both "reference URL" and "title" (or "stated in") are present, then use cite web template

			citeParamsi18n'cite']['url']] = refs'P854'

			if refs'P248' and refs'P1476' == nil then

				citeParamsi18n'cite']['title']] = refs'P248']:match("^%[%[.-|(.-)%]%]")

			else

				citeParamsi18n'cite']['title']] = refs'P1476'

				citeParamsi18n'cite']['website']] = refs'P248'

			end

			citeParamsi18n'cite']['author']] = refs'P50'

			citeParamsi18n'cite']['language']] = refs'P407'

			citeParamsi18n'cite']['publisher']] = refs'P123'

			citeParamsi18n'cite']['date']] = refs'P577'

			citeParamsi18n'cite']['pages']] = refs'P304'

			citeParamsi18n'cite']['access-date']] = refs'P813'

			citeParamsi18n'cite']['archive-url']] = refs'P1065'

			citeParamsi18n'cite']['archive-date']] = refs'P2960'

			citeParamsi18n'cite']['quote']] = refs'P1683'

			refparts = mw.getCurrentFrame():expandTemplate{title=template_web, args=citeParams}

		elseif refs'P1433' and (refs'P1476' or refs'P248']) and template_journal then

			-- if both "published in" and "title" (or "stated in") are present, then use cite journal template

			citeParamsi18n'cite']['work']] = refs'P1433'

			citeParamsi18n'cite']['title']] = refs'P1476' or refs'P248'

			citeParamsi18n'cite']['author']] = refs'P50'

			citeParamsi18n'cite']['date']] = refs'P577'

			citeParamsi18n'cite']['issue']] = refs'P433'

			citeParamsi18n'cite']['pages']] = refs'P304'

			citeParamsi18n'cite']['language']] = refs'P407'

			citeParamsi18n'cite']['issn']] = refs'P236'

			citeParamsi18n'cite']['doi']] = refs'P356'

			refparts = mw.getCurrentFrame():expandTemplate{title=template_journal, args=citeParams}

		elseif validref then

			-- raw ouput

			local snaksorder = claim.referencesref]["snaks-order"

			local function indexed(a)

				for _, b in ipairs(snaksorder) do

					if b == a then return true end

				end

				return false

			end

			for k, _ in pairs(refs or {}) do

				if not indexed(k) then

					table.insert(snaksorder, k)

				end

			end

			local italics = "''"

			for _, k in ipairs(snaksorder) do

				if refsk then

					refparts = refparts and refparts .. " " or ""

					refparts = refparts .. mw.ustring.gsub(getLabelByLangs(k, lang), "^%l", mw.ustring.upper) .. ": "

					refparts = refparts .. italics .. refsk .. italics .. "."

					italics = ""

				end

			end

		end

		if refparts then result = mw.getCurrentFrame():extensionTag("ref", refparts, {name=ref_name}) end

	end

	if type(result) == 'string' and result ~= "" and isSet(i18n.categoryref) then

		result = result .. "[[" ..i18n.categoryref .. "]]"

	end

	return result

end



-- Set whitelist or blacklist values

local function setWhiteOrBlackList(num_qual, args)

	local lists = {['whitelist'={}, 'blacklist'={}, 'ignorevalue'={}, 'selectvalue'={}}

	for i = 0, num_qual do

		for k, _ in pairs(lists) do

			if isSet(argsk .. i]) then

				listsk][tostring(i)] = {}

				local pattern = 'Q%d+'

				if string.sub(argsk .. i], 1, 1) ~= 'Q' then

					pattern = '[^%p%s]+'

				end

				for q in string.gmatch(argsk .. i], pattern) do

					listsk][tostring(i)][resolveEntityId(q)] = true

				end

			end

		end

	end

	return lists'whitelist'], lists'blacklist'], lists'ignorevalue'], lists'selectvalue'

end



local function tableParameters(args, parameters, column)

	local column_params = mw.clone(parameters)

	column_params.formatting = args"colformat"..column]; if column_params.formatting == "" then column_params.formatting = nil end

	column_params.convert = args"convert" .. column

	if args"case" .. column then

		column_params.case = args"case" .. column

	end

	return column_params

end



local function getEntityId(args, pargs, unnamed)

	pargs = pargs or {}

	local id = args.item or args.from or (unnamed and mw.text.trim(args1 or '') or nil)

	if not isSet(id) then

		id = pargs.item or pargs.from or (unnamed and mw.text.trim(pargs1 or '') or nil)

	end

	if isSet(id) then

		if string.find(id, ":") then -- remove prefix as Property:Pid

			id = mw.text.split(id, ":")[2

		end

	else

		id = mw.wikibase.getEntityIdForCurrentPage()

	end

	return id

end



local function getArg(value, default, aliases)

	if type(value) == 'boolean' then return value

	elseif value == "false" or value == "no" then return false

	elseif value == "true" or value == "yes" then return true

	elseif value and aliases and aliasesvalue then return aliasesvalue

	elseif isSet(value) then return value

	elseif default then return default

	else return nil

	end

end



-- Main function claim ---------------------------------------------

-- on debug console use: =p.claim{item="Q...", property="P...", ...}

function p.claim(frame)

	local args = frame.args or frame -- via invoke or require

	local pargs = frame.args and frame:getParent().args or {}

	local is_sandbox = isSet(pargs.sandbox)

	if not required and is_sandbox then

		return require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).claim(frame)

	end

	--If a value is already set, use it

	if isSet(args.value) then

		if args.value == 'NONE' then

			return

		else

			return args.value

		end

	end

	

	-- arguments

	local parameters = {}

	parameters.id = getEntityId(args, pargs)

	if parameters.id == nil then return end

	parameters.property = string.upper(args.property or "")

	local qualifierId = {}

	qualifierId1 = getArg(string.upper(args.qualifier or ""))

	local i = 2

	while isSet(args"qualifier" .. i]) do

		qualifierIdi = string.upper(args"qualifier" .. i])

		i = i + 1

	end

	parameters.formatting = getArg(args.formatting)

	parameters.convert = getArg(args.convert)

	parameters.case = args.case

	parameters.list = getArg(args.list, true, {firstrank='bestrank'})

	parameters.shownovalue = getArg(args.shownovalue, true)

	parameters.separator = getArg(args.separator)

	parameters.conjunction = getArg(args.conjunction, parameters.separator)

	parameters.qseparator = parameters.separator

	parameters.qconjunction = parameters.conjunction

	local sorting_col = args.tablesort

	local sorting_up = (args.sorting or "") ~= "-1"

	local rowformat = args.rowformat

	local references = args.references

	local showerrors = args.showerrors

	local default = args.default

	if default then showerrors = nil end

	parameters.lang = findLang(args.lang)

	if parameters.formatting == "raw" then

		parameters.editicon, parameters.labelicon = false, false

	else

		parameters.editicon, parameters.labelicon = setIcons(args.editicon, pargs.editicon) -- needs loadI18n by findLand

	end

	

	-- fetch property

	local claims = {}

	local bestrank = (parameters.list == false or parameters.list == 'bestrank') and parameters.list ~= 'lang'

	for p in string.gmatch(parameters.property, 'P%d+') do

		claims = getStatements(parameters.id, p, bestrank)

		if #claims > 0 then

			parameters.property = p

			break

		end

	end

	if #claims == 0 then

		if showerrors then return printError("property-not-found") else return default end

	end

	

	-- defaults for table

	local preformat, postformat = "", ""

	local whitelisted = false

	local whitelist, blacklist, ignorevalue, selectvalue = {}, {}, {}, {}

	if parameters.formatting == "table" then

		parameters.separator = parameters.separator or "<br />"

		parameters.conjunction = parameters.conjunction or "<br />"

		parameters.qseparator = ", "

		parameters.qconjunction = ", "

		if not rowformat then

			rowformat = "$0 ($1"

			i = 2

			while qualifierIdi do

				rowformat = rowformat .. ", $" .. i

				i = i + 1

			end

			rowformat = rowformat .. ")"

		elseif mw.ustring.find(rowformat, "^[*#]") then

			parameters.separator = "</li><li>"

			parameters.conjunction = "</li><li>"

			if mw.ustring.match(rowformat, "^[*#]") == "*" then

				preformat = "<ul><li>"

				postformat = "</li></ul>"

			else

				preformat = "<ol><li>"

				postformat = "</li></ol>"

			end

			rowformat = mw.ustring.gsub(rowformat, "^[*#] ?", "")

		end

		

		-- set whitelist and blacklist values

		whitelist, blacklist, ignorevalue, selectvalue = setWhiteOrBlackList(#qualifierId, args)

		local next = next

		if next(whitelist) ~= nil then whitelisted = true end

	end

	

	-- set feminine case if gender is requested

	local itemgender = args.itemgender

	local idgender

	if itemgender then

		if string.match(itemgender, "^P%d+$") then

			local snak_id = getSnak(mw.wikibase.getBestStatements(parameters.id, itemgender), {1, "mainsnak", "datavalue", "value", "id"})

			if snak_id then

				idgender = snak_id

			end

		elseif string.match(itemgender, "^Q%d+$") then

			idgender = itemgender

		end

	end

	local gender_requested = false

	if parameters.case == "gender" or idgender then

		gender_requested = true

	elseif parameters.formatting == "table" then

		for i=0, #qualifierId do

			if args"case" .. i and args"case" .. i == "gender" then

				gender_requested = true

				break

			end

		end

	end

	if gender_requested then

		if feminineGender(idgender or parameters.id) then

			parameters.gender = "feminineform"

		end

	end

	

	-- get initial sort indices

	local sortindices = {}

	for idx in pairs(claims) do

		sortindices#sortindices + 1 = idx

	end

	-- sort by claim rank

	local comparator = function(a, b)

		local rankmap = { deprecated = 2, normal = 1, preferred = 0 }

		local ranka = rankmapclaimsa].rank or "normal" .. string.format("%08d", a)

		local rankb = rankmapclaimsb].rank or "normal" .. string.format("%08d", b)

		return ranka < rankb

	end

	table.sort(sortindices, comparator)

	

	local result, result2, result_query

	local error

	if parameters.list or parameters.formatting == "table" then

		-- convert LF to line feed, <br /> may not work on some cases

		parameters.separator = parameters.separator == "LF" and "\010" or parameters.separator

		parameters.conjunction = parameters.conjunction == "LF" and "\010" or parameters.conjunction

		-- i18n separators

		parameters.separator = parameters.separator or mw.message.new('Comma-separator'):inLanguage(parameters.lang1]):plain()

		parameters.conjunction = parameters.conjunction or (mw.message.new('And'):inLanguage(parameters.lang1]):plain() .. mw.message.new('Word-separator'):inLanguage(parameters.lang1]):plain())

		-- iterate over all elements and return their value (if existing)

		local value, valueq

		local sortkey, sortkeyq

		local values = {}

		local sortkeys = {}

		local refs = {}

		local rowlist = {} -- rows to list with whitelist or blacklist

		for idx in pairs(claims) do

			local claim = claimssortindicesidx]]

			local reference = {}

			if not whitelisted then rowlistidx = true end

			if parameters.formatting == "table" then

				local params = tableParameters(args, parameters, "0")

				value, sortkey, error = getValueOfClaim(claim, nil, params)

				if value then

					values#values + 1 = {}

					sortkeys#sortkeys + 1 = {}

					refs#refs + 1 = {}

					if whitelist"0" or blacklist"0" then

						local valueraw, _, _ = getValueOfClaim(claim, nil, {["formatting"="raw", "lang"=params.lang})

						if whitelist"0" and whitelist"0"][valueraw or "" then

							rowlist#values = true

						elseif blacklist"0" and blacklist"0"][valueraw or "" then

							rowlist#values = false

						end

					end

					for i, qual in ipairs(qualifierId) do

						local j = tostring(i)

						params = tableParameters(args, parameters, j)

						local valueq, sortkeyq, valueraw

						if qual == parameters.property then -- hack for getting the property with another formatting, i.e. colformat1=raw

							valueq, sortkeyq, _ = getValueOfClaim(claim, nil, params)

						else

							for q in mw.text.gsplit(qual, '%s*OR%s*') do

								if string.find(q, ".+/.+") then

									valueq, sortkeyq, valueraw = getValueOfParentClaim(claim, q, params)

								elseif string.find(q, "^/.+") then

									local claim2 = getStatements(parameters.id, string.sub(q, 2), bestrank)

									if #claim2 > 0 then

										valueq, sortkeyq, _ = getValueOfClaim(claim21], nil, params)

									end

								else

									valueq, sortkeyq, _ = getValueOfClaim(claim, q, params)

								end

								if valueq then

									qual = q

									break

								end

							end

						end

						values#values]["col" .. j = valueq

						sortkeys#sortkeys]["col" .. j = sortkeyq or valueq

						if whitelistj or blacklistj or ignorevaluej or selectvaluej then

							valueq = valueraw or getValueOfClaim(claim, qual, {["formatting"="raw", "lang"=params.lang})

							if whitelistj and whitelistj][valueq or "" then

								rowlist#values = true

							elseif blacklistj and blacklistj][valueq or "" then

								rowlist#values = false

							elseif ignorevaluej and ignorevaluej][valueq or "" then

								values#values]["col" .. j = nil

							elseif selectvaluej and not selectvaluej][valueq or "" then

								values#values]["col" .. j = nil

							end

						end

					end

				end

			else

				value, sortkey, error = getValueOfClaim(claim, qualifierId1], parameters)

				values#values + 1 = {}

				sortkeys#sortkeys + 1 = {}

				refs#refs + 1 = {}

			end

			if not value and showerrors then value = error end

			if value then

				if references and claim.references then reference = claim.references end

				refs#refs]["col0" = reference

				values#values]["col0" = value

				sortkeys#sortkeys]["col0" = sortkey or value

			end

		end

		-- sort and format results

		sortindices = {}

		for idx in pairs(values) do

			sortindices#sortindices + 1 = idx

		end

		if sorting_col then

			local sorting_table = mw.text.split(sorting_col, '%D+')

			local comparator = function(a, b)

				local valuea, valueb

				local i = 1

				while valuea == valueb and i <= #sorting_table do

					valuea = sortkeysa]["col" .. sorting_tablei]] or ''

					valueb = sortkeysb]["col" .. sorting_tablei]] or ''

					i = i + 1

				end

				

				if sorting_up then

					return valueb > valuea

				end

				return valueb < valuea

			end

			table.sort(sortindices, comparator)

		end

		local maxvals = tonumber(parameters.list)

		result = {}

		for idx in pairs(values) do

			local valuerow = valuessortindicesidx]]

			local reference = getReferences({["references" = refssortindicesidx]]["col0"]}, parameters.lang)

			

			value = valuerow"col0"

			if parameters.formatting == "table" then

				if not rowlistsortindicesidx]] then

					value = nil

				else

					local rowformatting = rowformat .. "$" -- fake end character added for easy gsub

					value = mw.ustring.gsub(rowformatting, "$0", {["$0" = value})

					value = mw.ustring.gsub(value, "$R0", reference) -- add reference

					for i, _ in ipairs(qualifierId) do

						local valueq = valuerow"col" .. i

						if args"rowsubformat" .. i and isSet(valueq) then

							-- add fake end character $

							-- gsub $i not followed by a number so $1 doesn't match $10, $11...

							-- remove fake end character

							valueq = captureEscapes(valueq)

							valueq = mw.ustring.gsub(args"rowsubformat" .. i .. "$", "$" .. i .. "(%D)", valueq .. "%1")

							valueq = string.sub(valueq, 1, -2)

							rowformatting = mw.ustring.gsub(rowformatting, "$" .. i .. "(%D)", args"rowsubformat" .. i .. "%1")

						end

						valueq = valueq and captureEscapes(valueq) or ''

						value = mw.ustring.gsub(value, "$" .. i .. "(%D)", valueq .. "%1")

					end

					value = string.sub(value, 1, -2) -- remove fake end character

					value = expandBraces(value, rowformatting)

				end

			elseif value then

				value = expandBraces(value, parameters.formatting)

				value = value .. reference

			end

			if isSet(value) then

				result#result + 1 = value

				if not parameters.list or (maxvals and maxvals == #result) then

					break

				end

			end

		end

		

		if args.query == 'num' then

			result_query = 0

			for _, v in pairs(rowlist) do

				result_query = result_query + (v and 1 or 0)

			end

		end

		if #result > 0 then

			if parameters.formatting == 'table' then

				result = addEditIconTable(result, parameters) -- in a table, add edit icon on last element

			end

			result = preformat .. mw.text.listToText(result, parameters.separator, parameters.conjunction) .. postformat

		else

			result = ''

		end

	else

		-- return first element

		local claim = claimssortindices1]]

		result, result2, error = getValueOfClaim(claim, qualifierId1], parameters)

		if result and references then result = result .. getReferences(claim, parameters.lang) end

		if args.query == 'num' then result_query = 1 end

	end

	

	if isSet(result) then

		if not (parameters.formatting == 'table' or (result2 and result2 == 'no-icon')) then

			-- add edit icon, except table added previously and except explicit no-icon internal flag

			result = result .. addEditIcon(parameters)

		end

	else

		if showerrors then result = error else result = default end

	end

	if args.query == 'untranslated' and required and not is_sandbox then

		result_query = untranslated

	end

	return result, result_query or ''

end



-- Local functions for getParentValues -----------------------



local function uc_first(word)

	if word == nil then return end

	return mw.ustring.upper(mw.ustring.sub(word, 1, 1)) .. mw.ustring.sub(word, 2)

end



local function getPropertyValue(id, property, parameter, langs, labelicon, case)

	local snaks = mw.wikibase.getBestStatements(id, property)

	local mysnak = getSnak(snaks, {1, "mainsnak"})

	if mysnak == nil then

		return

	end

	

	local entity_id

	local result = '-' -- default for 'no value'

	if mysnak.datavalue then

		entity_id = "Q" .. tostring(mysnak.datavalue.value'numeric-id'])

		result, _ = getSnakValue(mysnak, {formatting=parameter, lang=langs, labelicon=labelicon, case=case})

	end

	

	return entity_id, result

end



local function getParentObjects(id,

	prop_format,

	label_format,

	languages, 

	propertySupString, 

	propertyLabel,

	propertyLink,

	label_show,

	labelicon0,

	labelicon1,

	upto_number,

	upto_label,

	upto_value,

	last_only,

	grammatical_case,

	include_self)

	

	local propertySups = mw.text.split(propertySupString, '[^P%d]')

	

	local maxloop = 10

	if upto_number then

		maxloop = tonumber(upto_number)

	elseif next(upto_label) or next(upto_value) then

		maxloop = 50

	end

	

	local labels_filter = next(label_show)

	

	local result = {}

	local id_value = id

	for iter = 1, maxloop do

		local link, label, labelwicon, linktext, id_label

		for _, propertySup in pairs(propertySups) do 	

			local _id_value, _link = getPropertyValue(id_value, propertySup, prop_format, languages, labelicon1, grammatical_case)

			if _id_value and _link then id_value = _id_value; link = _link break end

		end

		

		if not id_value or not link then break end

		

		if propertyLink then

			_, linktext = getPropertyValue(id_value, propertyLink, "label", languages)

			if linktext then

				link = mw.ustring.gsub(link, "%[%[(.*)%|.+%]%]", "[[%1|" .. linktext .. "]]")

			end

		end

		

		id_label, label = getPropertyValue(id_value, propertyLabel, label_format, languages, false, "infoboxlabel")

		if labelicon0 then

			_, labelwicon = getPropertyValue(id_value, propertyLabel, label_format, languages, labelicon0, "infoboxlabel")

		else

			labelwicon = label

		end

		

		if labels_filter == nil or (label_showid_label or label_showlabel]) then

			result#result + 1 = {labelwicon, link}

			label_showid_label or 'none'], label_showlabel or 'none' = nil, nil -- only first label found

		end

		

		if upto_labelid_label or upto_labellabel or upto_valueid_value then

			break

		end

	end

	

	if last_only then

		result = {result#result]}

	end

	

	if include_self then

		local label_self, link_self

		_, label_self = getPropertyValue(id, propertyLabel, label_format, languages, labelicon0, "infoboxlabel")

		link_self, _ = getLabelByLangs(id, languages)

		table.insert(result, 1, {label_self, link_self})

	end

	

	return result

end



local function parentObjectsToString(result,

	rowformat,

	cascade,

	sorting)

	

	local ret = {}

	local first = 1

	local last = #result

	local iter = 1

	if sorting == "-1" then first = #result; last = 1; iter = -1 end

	for i = first, last, iter do

		local rowtext = mw.ustring.gsub(rowformat, "$[01]", {["$0" = resulti][1], "$1" = resulti][2]})

		ret#ret + 1 = expandBraces(rowtext, rowformat)

	end

	

	if cascade then

		local direction = mw.language.new(wiki.langcode):isRTL() and "right" or "left"

		local suffix = ""

		for i = 1, #ret do

			reti = '<ul style="line-height:100%; margin-' .. direction .. ':0.45em; padding-' .. direction .. ':0;"><li>' .. reti

			suffix = suffix .. '</li></ul>'

		end

		ret#ret = ret#ret .. suffix

	end

	

	return ret

end



-- Returns pairs of parent label and property value fetching a recursive tree

function p.getParentValues(frame)

	local args = frame.args or frame -- via invoke or require

	local pargs = frame.args and frame:getParent().args or {}

	if not required and isSet(pargs.sandbox) then

		return require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).getParentValues(frame)

	end

	local id = getEntityId(args, pargs)

	if id == nil then return end

	local languages = findLang(args.lang)

	local propertySup = getArg(args.property, "P131") --administrative entity

	local propertyLabel = getArg(args.label, "P31") --instance

	local propertyLink = getArg(args.valuetext)

	local property_format = getArg(args.formatting)

	local label_format = getArg(args.labelformat, "label")

	local upto_number = getArg(args.upto)

	local last_only = getArg(args.last_only, false)

	local editicon, labelicon = setIcons(args.editicon, pargs.editicon)

	local include_self = getArg(args.include_self, false)

	local case = getArg(args.case)

	

	local upto_label = {}

	for q in string.gmatch(args.uptolabelid or '', 'Q%d+') do

		local checked_q = resolveEntityId(q)

		if checked_q then

			upto_labelchecked_q = true

		end

	end

	if type(upto_number) == 'string' then

		upto_labeluc_first(upto_number)] = true

		upto_number = nil

		require(wiki.module_title .. '/debug').track('upto') -- replace upto by uptolabelid

	end

	

	local upto_value = {}

	for q in string.gmatch(args.uptovalueid or args.uptolinkid or '', 'Q%d+') do

		local checked_q = resolveEntityId(q)

		if checked_q then

			upto_valuechecked_q = true

		end

	end

	

	local label_show = {}

	for q in string.gmatch(args.showlabelid or '', 'Q%d+') do

		local checked_q = resolveEntityId(q)

		if checked_q then

			label_showchecked_q = true

		end

	end

	for _, v in ipairs(mw.text.split(args.labelshow or '', "/")) do

		if v ~= '' then

			label_showuc_first(v)] = true

			require(wiki.module_title .. '/debug').track('labelshow') -- replace labelshow by showlabelid

		end

	end

	

	local rowformat = args.rowformat; if not isSet(rowformat) then rowformat = "$0 = $1" end

	local labelicon0, labelicon1 = labelicon, labelicon

	if string.find(label_format, '{{.*$0.*}}') or (string.find(rowformat, '{{.*$0.*}}') and label_format ~= 'raw') then

		labelicon0 = false

	end

	

	local result = getParentObjects(id,

		property_format,

		label_format,

		languages, 

		propertySup, 

		propertyLabel,

		propertyLink,

		label_show,

		labelicon0,

		labelicon1,

		upto_number,

		upto_label,

		upto_value,

		last_only,

		case,

		include_self)

	if #result == 0 then return end

	

	local separator = args.separator; if not isSet(separator) then separator = "<br />" end

	local sorting = args.sorting; if sorting == "" then sorting = nil end

	local cascade = (args.cascade == "true" or args.cascade == "yes")

	

	local ret = parentObjectsToString(result,

		rowformat,

		cascade,

		sorting)

	ret = addEditIconTable(ret, {property=propertySup, editicon=editicon, id=id, lang=languages})

	return mw.text.listToText(ret, separator, separator)

end



-- Link with a parent label --------------------

function p.linkWithParentLabel(frame)

	local pargs = frame.args and frame:getParent().args or {}

	if not required and isSet(pargs.sandbox) then

		return require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).linkWithParentLabel(frame)

	end

	local args = {}

	if frame.args then

		for k, v in pairs(frame.args) do -- metatable

			argsk = v

		end

	else

		args = frame -- via require

	end

	if isSet(args.value) then

		return args.value

	end

	

	-- get id value of property/qualifier

	local largs = mw.clone(args)

	largs.list = tonumber(args.list) and args.list or true

	largs.formatting = "raw"

	largs.separator = "/·/"

	largs.editicon = false

	local items_list, _ = p.claim(largs)

	if not isSet(items_list) then return end

	local items_table = mw.text.split(items_list, "/·/", true)

	

	-- get internal link of property/qualifier

	largs.formatting = "internallink"

	local link_list, _ = p.claim(largs)

	local link_table = mw.text.split(link_list, "/·/", true)

	

	-- get label of parent property

	local parent_claim = getSnak(getStatements(items_table1], args.parent, true), {1, "mainsnak", "datatype"})

	if parent_claim == 'monolingualtext' then

		largs.formatting = nil

		largs.list = 'lang'

	else

		largs.formatting = "label"

		largs.list = false

	end

	largs.property = args.parent

	largs.qualifier = nil

	for i, v in ipairs(items_table) do

		largs.item = v

		local link_label, _ = p.claim(largs)

		if isSet(link_label) then

			link_tablei = mw.ustring.gsub(link_tablei or '', "%[%[(.*)%|.+%]%]", "[[%1|" .. link_label .. "]]")

		end

	end

	args.editicon, _ = setIcons(args.editicon, pargs.editicon)

	args.id = getEntityId(args, pargs)

	args.lang = findLang(args.lang)

	return mw.text.listToText(link_table) .. addEditIcon(args)

end



-- Calculate number of years old ----------------------------

function p.yearsOld(frame)

	if not required and frame.args and isSet(frame:getParent().args.sandbox) then

		return require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).yearsOld(frame)

	end

	local args = frame.args or frame -- via invoke or require

	local pargs = frame.args and frame:getParent().args or {}

	local id = getEntityId(args, pargs)

	if id == nil then return end

	local lang = mw.language.new('en')

	

	local function getBestValue(id, prop)

		return getSnak(mw.wikibase.getBestStatements(id, prop), {1, "mainsnak", "datavalue", "value"})

	end

	

	local birth = getBestValue(id, 'P569')

	if type(birth) ~= 'table' or birth.time == nil or birth.precision == nil or birth.precision < 8 then

		return

	end

	local death = getBestValue(id, 'P570')

	if type(death) ~= 'table' or death.time == nil or death.precision == nil then

		death = {['time' = lang:formatDate('c'), 'precision' = 11} -- current date

	elseif death.precision < 8 then

		return

	end

	

	local dates = {}

	dates1 = {['min' = {}, 'max' = {}, 'precision' = birth.precision}

	dates1].min.year = tonumber(mw.ustring.match(birth.time, "^[+-]?%d+"))

	dates1].min.month = tonumber(mw.ustring.match(birth.time, "\-(%d%d)\-"))

	dates1].min.day = tonumber(mw.ustring.match(birth.time, "\-(%d%d)T"))

	dates1].max = mw.clone(dates1].min)

	dates2 = {['min' = {}, 'max' = {}, 'precision' = death.precision}

	dates2].min.year = tonumber(mw.ustring.match(death.time, "^[+-]?%d+"))

	dates2].min.month = tonumber(mw.ustring.match(death.time, "\-(%d%d)\-"))

	dates2].min.day = tonumber(mw.ustring.match(death.time, "\-(%d%d)T"))

	dates2].max = mw.clone(dates2].min)

	

	for i, d in ipairs(dates) do

		if d.precision == 10 then -- month

			d.min.day = 1

			local timestamp = string.format("%04d", tostring(math.abs(d.max.year)))

				.. string.format("%02d", tostring(d.max.month))

				.. "01"

			d.max.day = tonumber(lang:formatDate("j", timestamp .. " + 1 month - 1 day"))

		elseif d.precision < 10 then -- year or decade

			d.min.day = 1

			d.min.month = 1

			d.max.day = 31

			d.max.month = 12

			if d.precision == 8 then -- decade

				d.max.year = d.max.year + 9

			end

		end

	end

	

	local function age(d1, d2)

		local years = d2.year - d1.year

		if d2.month < d1.month or (d2.month == d1.month and d2.day < d1.day) then

			years = years - 1

		end

		if d2.year > 0 and d1.year < 0 then

			years = years - 1 -- no year 0

		end

		return years

	end

	

	local old_min = age(dates1].max, dates2].min)

	local old_max = age(dates1].min, dates2].max)

	local old, old_expr

	if old_min == 0 and old_max == 0 then

		old = "< 1"

		old_max = 1 -- expression in singular

	elseif old_min == old_max then

		old = old_min

	else

		old = old_min .. "/" .. old_max

	end

	if args.formatting == 'unit' then

		local langs = findLang(args.lang)

		local yo, yo_sg, yo_pl, yo_pau

		if langs1 == wiki.langcode then

			yo_sg = i18n"years-old"].singular

			yo_pl = i18n"years-old"].plural

			yo_pau = i18n"years-old"].paucal

		end

		if not isSet(yo_pl) then

			yo_pl, _ = getLabelByLangs('Q24564698', langs)

			yo_sg = yo_pl

		end

		if not isSet(yo_pau) then

			yo_pau = yo_pl

		end

		yo = mw.language.new(langs1]):plural(old_max, {yo_sg, yo_pau, yo_pl})

		if mw.ustring.find(yo, '$1', 1, true) then

			old_expr = mw.ustring.gsub(yo, "$1", old)

		else

			old_expr = old .. '&nbsp;' .. yo

		end

	elseif args.formatting then

		old_expr = expandBraces(mw.ustring.gsub(args.formatting, '$1', old), args.formatting)

	else

		old_expr = old

	end

	

	return old_expr

end



-- Gets a label in a given language (content language by default) or its fallbacks, optionnally linked.

function p.getLabel(frame)

	local args = frame.args or frame -- via invoke or require

	local pargs = frame.args and frame:getParent().args or {}

	if not required and isSet(pargs.sandbox) then

		return require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).getLabel(frame)

	end

	local id = getEntityId(args, pargs, 1)

	if id == nil then return end

	local languages = findLang(args.lang)

	local labelicon = false

	if mw.wikibase.isValidEntityId(id) then

		_, labelicon = setIcons(args.editicon, pargs.editicon)

	end

	

	local label_icon = ''

	local label, lang

	if args.label then

		label = args.label

	else

		-- exceptions or labels fixed

		local exist, labels = pcall(require, wiki.module_title .. "/labels" .. (languages1 == wiki.langcode and '' or '/' .. languages1]))

		if exist and labels.infoboxLabelsFromId and next(labels.infoboxLabelsFromId) ~= nil then

			label = labels.infoboxLabelsFromIdid

		end

		

		if label == nil then

			label, lang = getLabelByLangs(id, languages)

			if label then

				if isSet(args.itemgender) and feminineGender(args.itemgender) then

					label = feminineForm(id, lang) or label

				end

				label = mw.language.new(lang):ucfirst(mw.text.nowiki(label)) -- sanitize

				if args.case then

					label = case(args.case, label, lang)

				end

			end

			label_icon = addLabelIcon(id, lang, languages1], labelicon)

		end

	end

	

	local linked = args.linked

	local ret2 = required and untranslated or ''

	if isSet(linked) and linked ~= "no" then

		local article = mw.wikibase.getSitelink(id) or ("d:Special:EntityPage/" .. id)

		return "[[" .. article .. "|" .. (label or id) .. "]]" .. label_icon, ret2

	else

		return (label or id) .. label_icon, ret2

	end

end



-- Utilities -----------------------------

-- See also module ../debug.



-- Copied from Module:Wikibase

function p.getSiteLink(frame)

	local args = frame.args or frame -- via invoke or require

	local pargs = frame.args and frame:getParent().args or {}

	local id = getEntityId(args, pargs, 1)

	if id == nil then return end

	return mw.wikibase.getSitelink(id, mw.text.trim(args2 or ''))

end



-- Helper function for the default language code used

function p.lang(frame)

	local lang = frame and frame.args1 -- nil via require

	return findLang(lang)[1

end



-- Number of statements

function p.numStatements(frame)

	local args = frame.args or frame -- via invoke or require

	local pargs = frame.args and frame:getParent().args or {}

	local id = getEntityId(args, pargs)

	if id == nil then return 0 end

	local prop = mw.text.trim(args1 or '')

	local num = {}

	if not isSet(prop) and frame.args then

		args = {}

		for k, v in pairs(pargs) do

			argsk = v

		end

		for k, v in pairs(frame.args) do

			argsk = v

		end

		args.query = 'num'

		_, num = p.claim(args)

		return num

	elseif args2 then -- qualifier

		local qual = mw.text.trim(args2])

		local values = p.claim{item=id, property=prop, qualifier=qual, formatting='raw', separator='/·/'}

		if values then

			num = mw.text.split(values, '/·/')

		end

	else

		num = mw.wikibase.getBestStatements(id, prop)

	end

	return #num

end



-- Returns true if property datavalue is found excluding novalue/somevalue

function p.validProperty(frame)

	local args = frame.args or frame -- via invoke or require

	local pargs = frame.args and frame:getParent().args or {}

	local item = getEntityId(args, pargs)

	if item == nil then return end

	local property = mw.text.trim(args1])

	local prop_data = getSnak(mw.wikibase.getBestStatements(item, property), {1, "mainsnak", "datavalue"})

	return prop_data and true or nil

end



function p.editAtWikidata(frame)

	local args = frame.args or frame -- via invoke or require

	local pargs = frame.args and frame:getParent().args or {}

	local value = isSet(args1])

	if value then return end

	local param = {}

	param.id = getEntityId(args, pargs)

	param.property = args.property

	param.lang = findLang(args.lang)

	param.editicon, _ = setIcons(args.editicon)

	return addEditIcon(param)

end



function p.formatNum(frame)

	local num = tonumber(mw.text.trim(frame.args1]))

	local lang = findLang(mw.text.trim(frame.args2]))

	return mw.language.new(lang1]):formatNum(num)

end



return p

Videos

Youtube | Vimeo | Bing

Websites

Google | Yahoo | Bing

Encyclopedia

Google | Yahoo | Bing

Facebook