Modul:Wikidata

De la Wikipedia, enciclopedia liberă
Salt la: Navigare, căutare

Acest modul folosește pentru accesarea datelor din structurile de la Wikidata. Desigur, există {{#property:}} cu care se poate accesa o proprietate a itemului curent, dar de cele mai multe ori este nevoie de acțiuni mai complexe.

Convenții[modificare sursă]

Funcțiile al căror nume începe cu get sunt dedicate formatelor și paginilor, și primesc ca argument un frame (care se transmite automat la apelul din pagini sau formate). Cele al căror nume începe cu find sunt dedicate celorlalte module, și primesc ca argumente direct valorile necesare. De regulă, cele din urmă doar extrag argumentele, apoi le apelează pe cele dintâi cu argumentele extrase.

Funcții exportate[modificare sursă]

Funcție Argumente Comportament
descriptionIn

frame cuprinzând ca argumente:

  1. codul limbii
  2. id-ul itemului de Wikidata
Extrage descrierea unui item într-o limbă. Limba este specificată de primul argument și poate lipsi, caz în care se folosește limba wikiului; id-ul itemului poate lipsi, caz în care se folosește itemul asociat paginii curente.
labelIn

frame cuprinzând ca argumente:

  1. codul limbii
  2. id-ul itemului de Wikidata
Extrage eticheta unui item într-o limbă. Limba este specificată de primul argument și poate lipsi, caz în care se folosește limba wikiului; id-ul itemului poate lipsi, caz în care se folosește itemul asociat paginii curente.
getEntityId Extrage id-ul entității curente.
findLinkToItem
  • entityId - id-ul entității
  • capitalize - flag care cere scrierea cu inițială majusculă
  • feminine - flag care cere căutarea formei feminine
  • shortestAlias - flag care cere căutarea unei abrevieri
Creează un link către articolul despre o altă entitate decât cea în pagina în care ne aflăm. Se poate cere scrierea etichetei linkului cu inițială majusculă (dacă regulile gramaticale o impun — cazul în care linkul se pune la începutul unui titlu sau al unei fraze); în forma de feminin (de exemplu, pentru meserii, dacă ele sunt referite ca practicate de o femeie); sau cu cea mai scurtă variantă posibilă (dacă se dorește o abreviere). Oricare din ultimele trei flaguri poate lipsi, caz în care ele sunt considerate a avea valoarea false.
findLinkToItemWithLabelFromClaim
  • entityId - id-ul entității
  • capitalize - flag care cere scrierea cu inițială majusculă
  • propertyId - identifică proprietatea folosită pentru extragerea etichetei linkului
Ca și findLinkToItem, doar că generalizează modul de obținere a etichetei: se poate preciza o proprietate a entității de la care se va obține eticheta
findLinkToItemWithLabelFromAnyClaim
  • entityId - id-ul entității
  • capitalize - flag care cere scrierea cu inițială majusculă
  • propertyIdsTable - listă de proprietăți folosite pentru extragerea etichetei linkului
Ca și findLinkToItemWithLabelFromClaim, doar că generalizează și mai mult modul de obținere a etichetei: se poate preciza o listă de proprietăți ale entității care sunt verificate pe rând până se găsește una care are o valoare
printSnak
  • snak - elementul din structura Wikidata
Afișează un „snak” (element polimorf din structura de date de la Wikidata). Este utilă atunci când într-un modul se procesează date preluate în mod direct din structurile de date de la Wikidata. Acest snak poate fi o dată calendaristică, id-ul unui alt item Wikidata, un șir de caractere etc. Funcția ia decizia a ce afișează în funcție de tipul snakului.
outputReferences Creează note de subsol conținând referințele bibliografice asociate unei afirmații. Notele de subsol sunt evitate dacă referința este către un alt proiect Wikipedia. Numele refului se calculează automat pentru a putea fi reutilizat de la o instanță la alta.
getValueList
  • entityId - id-ul entității; dacă este nil, e vorba de entitatea curentă
  • propertyId - id-ul proprietății
Întoarce un table format din toate valorile cu rang de la normal în sus pentru proprietatea și entitatea specificată.
printTimestampForClaim Întoarce, între paranteze, datele temporale asociate afirmației:
  • simpla specificare a datei dacă e dată prin proprietatea P585 (point in time)
  • „din” urmat de specificarea datei dacă este definită doar proprietatea P580 (start time)
  • „până la” urmat de specificarea datei dacă este definită doar proprietatea P582 (end time)
  • specificarea datelor date de proprietățile P580 și P582 separate de en-dash (–) dacă sunt definite ambele
getTimestampedValueList
  • entityId - id-ul entității; dacă este nil, e vorba de entitatea curentă
  • propertyId - id-ul proprietății
Întoarce un table format din valorile pe care le-ar returna funcția getValueList, fiecare urmată de valoarea pe care ar returna-o, pentru fiecare, funcția printTimestampForClaim apelată cu claimul asociat fiecăreia.
getValueListWithSeparator Un frame, având pe prima poziție separatorul, pe a doua id-ul de proprietate și pe a treia id-ul de entitate Returnează o listă ale cărei elemente sunt separate prin separatorul specificat, elementele fiind valorile pe care le-ar returna funcția getValueList apelată cu id-urile de proprietate și entitate specificate.
_getValueListWithSeparator Ca și getValueListWithSeparator, doar că primește direct table-ul de argumente, nu frame-ul Ca și getValueListWithSeparator.
getTimestampedValueListWithSeparator Un frame, având pe prima poziție separatorul, pe a doua id-ul de proprietate și pe a treia id-ul de entitate Returnează o listă ale cărei elemente sunt separate prin separatorul specificat, elementele fiind valorile pe care le-ar returna funcția getTimestampedValueList apelată cu id-urile de proprietate și entitate specificate.
_getTimestampedValueListWithSeparator Ca și getTimestampedValueListWithSeparator, doar că primește direct table-ul de argumente, nu frame-ul Ca și getTimestampedValueListWithSeparator.
getEntityIdsList
  • entityId - id-ul entității; dacă este nil, e vorba de entitatea curentă
  • propertyId - id-ul proprietății
Întoarce un table conținând id-urile de entitate, cu rank cel puțin normal, către care trimite proprietatea specificată a entității specificate.
getBestEntityIdsList
  • entityId - id-ul entității; dacă este nil, e vorba de entitatea curentă
  • propertyId - id-ul proprietății
Întoarce un table conținând id-urile de entitate, cu rank cel mai mare, către care trimite proprietatea specificată a entității specificate.
findClaimsForProperty
  • entityId - id-ul entității; dacă este nil, e vorba de entitatea curentă
  • propertyId - id-ul proprietății
Întoarce un table conținând claimurile pure ce reprezintă afirmațiile asociate proprietății specificate a entității specificate.
findBestClaimsForProperty
  • entityId - id-ul entității; dacă este nil, e vorba de entitatea curentă
  • propertyId - id-ul proprietății
Întoarce un table conținând claimurile pure ce reprezintă afirmațiile cu cel mai bun rang, asociate proprietății specificate a entității specificate.
findSortedClaimsForProperty
  • entityId - id-ul entității; dacă este nil, e vorba de entitatea curentă
  • propertyId - id-ul proprietății
Întoarce un table conținând claimurile pure ce reprezintă afirmațiile asociate proprietății specificate a entității specificate, sortate în funcție de calificatorul end time (P580) asociat lor.
findQualifierValueListForClaim Întoarce un table conținând reprezentarea valorilor asociate calificatorului specificat pentru claimul specificat.
getQualifierValue Un frame conținând în tabelul args, în ordine, id-ul proprietății și id-ul calificatorului Întoarce reprezentarea tuturor calificatorilor cu id-ul specificat pentru proprietatea cu id-ul specificat a entității curente. Calificatoarele sunt separate prin virgulă și spațiu.
getRawValue Un frame având pe prima poziție a tabelului args valoare id-ului proprietății. Întoarce reprezentarea dată de funcția formatPropertyValues a entitătii curente, apelată cu id-ul de proprietate specificat.
getRawQualifierValue Un frame având pe prima poziție a tabelului args valoare id-ului proprietății și pe a doua id-ul unui calificator. Întoarce reprezentarea simplă a valorii (dacă valoarea este id-ul unui alt element, aceasta este labelul acelui element) tuturor calificatoarelor cu id-ul specificat ale id-ului proprietății cu id-ul specificat a entității curente. Reprezentările sunt separate prin virgulă.
findDateValues
  • propertyId - id-ul proprietății
  • entityId - id-ul entității; dacă este nil, e vorba de entitatea curentă
Întoarce un table ale cărui elemente sunt la rândul lor table-uri reprezentând datele cu rangul cel mai bun asociate proprietății cu id-ul specificat al entității cu id-ul specificat. Proprietățile fiecărui element din table-ul ce reprezintă data sunt:
  • day - ziua din lună
  • month - luna din an, întreg între 1 și 12
  • year - anul, poate fi valoare negativă pentru datele dinaintea erei noastre
  • claim - claimul brut asociat datei, pentru eventuale procesări ulterioare
  • precision - precizia, în codificarea Wikidata
  • calendarmodel - modelul calendarului, ca URL de entitate
getDateValue Un frame conținând în tabelul args pe prima poziție id-ul de proprietate, pe a doua id-ul de entitate (nil înseamnă entitatea curentă), pe a treia un format de dată (implicit dmy) și pe a patra un sufix pentru datele dinaintea erei noastre Întoarce o listă a datelor cu rang cel puțin normal asociate id-ului de proprietate și id-ului de entitate specificate, formatate după cum specifică formatul de dată și sufixul, separate prin virgulă și spațiu.
pageId Întoarce id-ul din Wikidata al elementului asociat paginii curente
getPreferredValue Un frame conținând în tabelul args pe prima poziție id-ul de proprietate și pe a doua id-ul de entitate (nil înseamnă entitatea curentă) Întoarce, separate prin virgulă, valorile cu rang preferred pentru entitatea și proprietatea specificate.
ViewSomething Un frame conținând în tabelul args o serie de elemente care împreună constituie o cale de urmat prin modelul de date de la Wikidata Întoarce data existentă pe calea specificată.
Dump Un frame conținând în tabelul args o serie de elemente care împreună constituie o cale de urmat prin modelul de date de la Wikidata Întoarce datele existente pe calea specificată; dacă datele sunt un tabel, el se expandează și se afișează toate datele din el. Funcția este de folosit pentru debug și pentru analiză
findOneValue
  • propertyId - id-ul proprietății
  • entityId - id-ul entității sau însăși entitatea; dacă este nil, e vorba de entitatea curentă
Returnează o singură valoare din cele cu rangul cel mai înalt cu referințele corespunzătoare pentru o proprietate specificată, împreună cu note de subsol care reprezintă referințele bibliografice. Se apelează din alte module.
findOneValueNoRef
  • propertyId - id-ul proprietății
  • entityId - id-ul entității sau însăși entitatea; dacă este nil, e vorba de entitatea curentă
Același lucru ca findOneValue, dar fără referințe bibliografice.
getOneValue Un frame conținând în tabelul args pe prima poziție id-ul de proprietate și pe a doua id-ul de entitate (nil înseamnă entitatea curentă) Returnează o singură valoare din cele cu rangul cel mai înalt cu referințele corespunzătoare pentru o proprietate specificată, împreună cu note de subsol care reprezintă referințele bibliografice.
getOneValueNoRef Un frame conținând în tabelul args pe prima poziție id-ul de proprietate și pe a doua id-ul de entitate (nil înseamnă entitatea curentă) Același lucru ca getOneValue, dar fără referințe bibliografice.
getLatestQualifierDateValueForOneProperty Un frame conținând în tabelul args pe prima poziție id-ul de proprietate și pe a doua id-ul qualifierului Returnează valoarea cea mai recentă a qualifierului specificat pentru proprietea specificată a entității curente
findLatestQualifierDateValueForOneProperty
  • propertyId - id-ul proprietății
  • qualifierId - id-ul qualifierului
Același lucru ca și getLatestQualifierDateValueForOneProperty, doar că de apelat din alte module
getReferenceForOneProperty Un frame conținând în tabelul args pe prima poziție id-ul proprietății Returnează un text ce conține referința pentru o proprietate a entității curente; de apelat din formate
findLabel
  • entityId - id-ul entității
  • lang - codul limbii
Returnează labelul unei entități în limba specificată; dacă nu se găsește, atunci se încearcă în limba wikiului și apoi în limba engleză
getLabel Un frame conținând în tabelul args pe prima poziție id-ul de entitate (nil înseamnă entitatea curentă) și pe a doua codul limbii Ca și findLabel, dar apelabil din formate sau pagini
findBestValues
  • propertyId - id-ul proprietății
  • entity - id-ul entității sau însăși entitatea; dacă este nil, e vorba de entitatea curentă
Returnează o listă a valorilor cu rangul cel mai înalt cu referințele corespunzătoare pentru o proprietate specificată. Apelabil din module.
getBestValuesWithSeparator Un frame conținând în tabelul args pe prima poziție un separator, pe a doua id-ul proprietății și pe a treia id-ul de entitate (nil înseamnă entitatea curentă). Returnează valorile cu rangul cel mai înalt și cu referințele corespunzătoare pentru o proprietate specificată, despărțite prin separatorul specificat
findLanguageText
  • propertyId - id-ul de proprietate
  • langcode - codul limbii
  • entityId - id-ul de entitate
Întoarce labelul unei entități asociate proprietății specificate a entității specificate, în limba specificată; dacă nu se specifică entityId, se folosește entitatea curentă; dacă nu se specifică langcode, se caută întâi în limba wikiului și apoi în limba engleză
getLanguageText Un frame conținând în tabelul args pe prima poziție id-ul de proprietate, pe a doua codul limbii și pe a treia id-ul de entitate Același lucru ca și findLanguageText, doar că apelabilă din formate și pagini
findClaimForTimestamp
  • entityId - id-ul entității; dacă este nil, e vorba de entitatea curentă
  • propertyId - id-ul proprietății
  • timestamp - un obiect de tip dată (cu valori numerice corespunzătoare în câmpurile day, month, year, precision)
Claimul din entitatea specificată, corespunzător proprietății specificate, cu valori ale calificatorilor pentru proprietățile start time și end time care cuprind între ele data specificată de timestamp. Dacă timestamp lipsește, se returnează primul claim întâlnit cu rangul cel mai mare.
findOnlineLinks
  • onlinelinksprops - un table ce conține id-uri de proprietăți care să fie explorate în vederea extragerii de legături externe
  • entityId - id-ul entității
Un table ce conține legăturile web formatate cu tot cu titlu, pentru entitatea specificată
getOnlineLinks Un frame ce conține pe pozițiile numerice valorile proprietăților de căutat, iar pe poziția qid ID-ul entității asociate; dacă nu este precizat, se consideră entitatea asociată paginii curente Ca și findOnlineLinks, doar că lista este concatenată cu fiecare link pe câte o linie.
findTitleOfWork entityId - id-ul entității Titlul unei opere așa cum ar trebui afișat aici. Se caută, în ordine: eticheta în română, titlul în română, titlul în limba originară, eticheta în limba originară, eticheta în engleză
findTitlesOfWorksFromProperty
  • propertyId - id-ul proprietății
  • entityId - id-ul entității
Caută cu ajutorul funcției findTitleOfWork de mai sus titlurile unor opere listate în proprietatea specificată a entității specificate și le returnează ca intrări într-un table; titlurile sunt linkuri trimit spre articolul sau itemul wikidata corespunzător operei;
getTitleOfWorkFromPropertyWithSeparator Un frame ce conține următoarele argumente:
  • sep - un separator
  • propertyId - id-ul proprietății
  • entityId - id-ul entității
Ca și findTitlesOfWorksFromProperty, dar primește frame, returnează lista serializată cu separatori și cu titlurile italicizate
loadOneValueInChain Un număr teoretic nelimitat de argumente înlănțuite care descriu o cale prin structurile Wikidata. Implicit, punctul de început este elementul Wikidata asociat paginii curente. Dacă un argument este un ID de element Wikidata, atunci acela este stabilit ca punct de început. Dacă este un ID de proprietate, atunci se trece la valoarea proprietății respective pentru elementul curent. Dacă este un ID de proprietate precedat de _ atunci se trece la calificatorul asociat proprietății respective asociate snakului curent. În cele două cazuri din urmă se folosește la fiecare pas doar un singur snak, de rangul cel mai mare. Forma textuală a snakului final de pe lanț; nil dacă nu există date sau lanțul nu poate fi parcurs până la destinație
getOneValueInChain Ca și mai sus, doar că apelabil cu un frame Ca și mai sus

local getArgs = require('Module:Arguments').getArgs
local SepEntries = require('Module:Separated entries')
local StringUtils = require('Modul:StringUtils')
local DateUtils = require('Modul:DateUtils')
local GregorianDate = require('Modul:GregorianDate')
local Citation = require('Modul:Citation/CS1')
local TableTools = require('Modul:TableTools')
local md5 = require('Modul:MD5')
local LangUtils = require('Modul:LangUtils')
local p = {}
local lang = mw.language.getContentLanguage()
local libraryUtil = require('libraryUtil')

-- internationalisation
local i18n = {
    ["errors"] = {
        ["property-not-found"] = "Proprietatea nu a fost găsită.",
        ["entity-not-found"] = "Itfemul Wikidata nu a fost găsit.",
        ["unknown-claim-type"] = "Tip de afirmație negăsit.",
        ["unknown-snak-type"] = "Tip de Snak negăsit.",
        ["unknown-datavalue-type"] = "Tip de date negăsit.",
        ["unknown-entity-type"] = "Tip de item negăsit.",
        ["qualifier-not-found"] = "Calificator negăsit.",
        ["site-not-found"] = "Proiect Wikimedia negăsit.",
    },
    ["somevalue"] = "O valoare",
    ["novalue"] = "Nicio valoare",
    ["datetime"] =
	{
		-- $1 is a placeholder for the actual number
		[0] = "$1 miliarde de ani",		-- precision: billion years
		[1] = "$100 milioane de ani",	-- precision: hundred million years
		[2] = "$10 milioane de ani",	-- precision: ten million years
		[3] = "$1 milioane de ani",		-- precision: million years
		[4] = "$100.000 de ani",	-- precision: hundred thousand years
		[5] = "$10.000 de ani",		-- precision: ten thousand years
		[6] = "mileniul $1", 	-- precision: millennium
		[7] = "secolul $1",	-- precision: century
		[8] = "deceniul anilor $1",				-- precision: decade
		-- the following use the format of #time parser function
		[9]  = "Y",					-- precision: year, 
		[10] = "F Y",				-- precision: month
		[11] = "j F Y",			-- precision: day
		[12] = 'j F Y, "orele" G',	-- precision: hour
		[13] = "j F Y G:i",		-- precision: minute
		[14] = "j F Y G:i:s",		-- precision: second
		["beforenow"] = "acum $1",	-- how to format negative numbers for precisions 0 to 5
		["afternow"] = "peste $1",		-- how to format positive numbers for precisions 0 to 5
		["bc"] = '$1 "î.e.n."',		-- how print negative years
		["ad"] = "$1"				-- how print positive years
	},
	["monolingualtext"] = '<span lang="%language">%text</span>',
	["warnDump"] = "[[Categorie:Apel de funcție 'Dump' din modulul Wikidata]]"
}

local function propAndEntity(arg1, arg2)
	local propId, entId
	for _,eachArg in ipairs({arg1, arg2}) do
		if mw.ustring.match(eachArg, 'Q%d+') == eachArg then
			entId = eachArg
		elseif mw.ustring.match(eachArg, 'P%d+') == eachArg then
			propId = eachArg
		end
	end
	return propId, entId
end

local function wrapInLangSpan(text, lang)
	if not text then return nil end
	if not lang or lang == 'ro' then return text end
	local langSpan = mw.html.create('span'):attr('lang', lang):wikitext(text)
	return tostring(langSpan)
end

function p.descriptionIn(frame)
	local langcode = frame.args[1]
	local id = frame.args[2]
	-- return description of a Wikidata entity in the given language or the default language of this Wikipedia site
	local entity = mw.wikibase.getEntityObject(id)
	if entity then
		return entity.descriptions[langcode or lang.code].value
	end
	return ""
end

function p.getEntityId(frame)
	return mw.wikibase.getEntityIdForCurrentPage()
end

function p.labelIn(frame)
	local langcode = frame.args[1]
	local id = frame.args[2]
	-- return label of a Wikidata entity in the given language or the default language of this Wikipedia site
	local entity
	if id then
		entity = mw.wikibase.getEntityObject(id)
	else 
		entity = mw.wikibase.getEntityObject()
	end
	if entity then
		return entity.labels[langcode or lang.code] and entity.labels[langcode or lang.code].value
	end
	return ""
end

local function isValueSnak(snak)
	return snak and snak.snaktype == 'value'
end

local function hasValueSnak(claim)
	return claim and claim.type == 'statement' and isValueSnak(claim.mainsnak)
end

local function computeLinkToItem(entityId, capitalize, callFunction, plainCallFunction)
	local sitelink = mw.wikibase.sitelink(StringUtils._prependIfMissing({tostring(entityId), 'Q'}))
	local label = nil
	local labelLang = nil
	local object = nil
	if plainCallFunction and type(plainCallFunction) == 'function' then
		label, labelLang = plainCallFunction()
	elseif callFunction and type(callFunction) == 'function' then
		object = mw.wikibase.getEntityObject(StringUtils._prependIfMissing({tostring(entityId), 'Q'}))
		label, labelLang = callFunction(object)
	end
	if label == nil or (labelLang and labelLang ~= lang.code) then label = mw.wikibase.label(StringUtils._prependIfMissing({tostring(entityId), 'Q'})) end
	if label == nil and object ~= nil then
		object = object or mw.wikibase.getEntityObject(StringUtils._prependIfMissing({tostring(entityId), 'Q'}))
		label = object:getLabel('en')
		labelLang = 'en'
	end
	if label == nil then label = StringUtils._prependIfMissing({tostring(entityId), 'Q'}) end

	if capitalize then
		label = lang:ucfirst(label)
	end
	if labelLang and labelLang ~= 'ro' then
		label = wrapInLangSpan(label, labelLang)
	end
	if sitelink then
		return "[[:" .. sitelink .. "|" .. label .. "]]"
	else
		return "[[:d:" .. StringUtils._prependIfMissing({tostring(entityId), 'Q'}) .. "|" .. label .. "]]<abbr title='Articolul încă nu există în acest wiki'>[*]</abbr>"
	end
end

p.findLinkToItemWithLabel = function(entityId, label)
	local sitelink = mw.wikibase.sitelink(StringUtils._prependIfMissing({tostring(entityId), 'Q'}))
	if sitelink then
		return "[[:" .. sitelink .. "|" .. label .. "]]"
	else
		return computeLinkToItem(entityId, false, nil, function() return label end)
	end
end

p.findLinkToItemWithCallback = function(entityId, capitalize, callBack, plainCallBack)
	return computeLinkToItem(entityId, capitalize, callBack, plainCallBack)
end

p.findLinkToItemWithLabelFromAnyClaim = function(entityId, capitalize, propertyIdsTable)
	local callFunction = nil
	if propertyIdsTable then
		callFunction = function(object)
			local returnValue = nil
			for propIdIdx,propertyId in pairs(propertyIdsTable) do
				if object and object.claims and object.claims[propertyId] and returnValue == nil then
					for eachClaimIdx, eachClaim in pairs(object.claims[propertyId]) do
						if hasValueSnak(eachClaim) and eachClaim.mainsnak.datavalue then
							if eachClaim.mainsnak.datavalue.type == 'monolingualtext' then
								if eachClaim.mainsnak.datavalue.value.language == 'ro' then returnValue = eachClaim.mainsnak.datavalue.value.text end
							elseif eachClaim.mainsnak.datavalue.type == 'wikibase-entityid' then
								returnValue = mw.wikibase.label(StringUtils._prependIfMissing({tostring(eachClaim.mainsnak.datavalue.value['numeric-id']), 'Q'}))
							elseif eachClaim.mainsnak.datavalue.type == 'string' then
								returnValue = eachClaim.mainsnak.datavalue.value
							end
						end
					end
				end
			end
			return returnValue
		end
	end
	return computeLinkToItem(entityId, capitalize, callFunction)
end

p.findLinkToItemWithLabelFromClaim = function(entityId, capitalize, propertyId)
	return p.findLinkToItemWithLabelFromAnyClaim(entityId, capitalize, { propertyId })
end

p.findLinkToItem = function(entityId, capitalize, feminine, shortestAlias)
	if type(entityId) == 'number' then entityId = StringUtils._prependIfMissing({tostring(entityId), 'Q'}) end
	if capitalize == nil then capitalize = false end
	local label
	local returnedLang = nil
	
	if shortestAlias then
		local returnedAlias = nil
		local bestShortNameClaims = mw.wikibase.getAllStatements(entityId, 'P1813')
		if bestShortNameClaims then
			local shortNameEn = nil
			for shortNameIdx,shortNameClaim in pairs(bestShortNameClaims) do
				if shortNameClaim.mainsnak.datavalue.value.language == 'en' then shortNameEn = shortNameClaim.mainsnak.datavalue.value.text end
				if shortNameClaim.mainsnak.datavalue.value.language == 'ro' then returnedAlias = shortNameClaim.mainsnak.datavalue.value.text end
			end
			if returnedAlias then
				returnedLang = 'ro'
			else
				returnedAlias = shortNameEn
				returnedLang = 'en'
			end
			returnedAlias = capitalize and StringUtils._capitalize({returnedAlias}) or returnedAlias
		end
		label = wrapInLangSpan(returnedAlias, returnedLang)
	end
	if feminine then
		local feminineForms = mw.wikibase.getBestStatements(entityId, 'P2521')
		if feminineForms then
			for _idx, eachFForm in pairs(feminineForms) do
				if hasValueSnak(eachFForm) and eachFForm.mainsnak.datatype == 'monolingualtext' and eachFForm.mainsnak.datavalue.type == 'monolingualtext' and eachFForm.mainsnak.datavalue.value and eachFForm.mainsnak.datavalue.value.language == 'ro' then
					label = eachFForm.mainsnak.datavalue.value.text
					returnedLang = eachFForm.mainsnak.datavalue.value.language
				end
			end
		end
	end
	return computeLinkToItem(entityId, capitalize, nil, function() return label, returnedLang end)
end

p.getLinkToItem = function(frame)
	local args = getArgs(frame, {frameOnly=true})
	local entityId = args[1]
	return p.findLinkToItem(entityId, false, false, false)
end

local function printRawValue(snak)
	if (isValueSnak(snak)) then
		if snak.datavalue.type == "wikibase-entityid" then
			return snak.datavalue.value.id
		elseif snak.datavalue.type == "time" then
			return snak.datavalue.value.time
		elseif snak.datavalue.type == "monolingualtext" then
			return snak.datavalue.value.text
		elseif snak.datavalue.type == "quantity" then
			return snak.datavalue.value.amount .. ' ' .. snak.datavalue.value.unit
		else
			return snak.datavalue.value
		end
	end
	return ''
end

local function snakToString(snak, feminine)
	if (isValueSnak(snak)) then
		if (snak.datavalue.type == "wikibase-entityid") then
			return p.findLinkToItem(snak.datavalue.value["numeric-id"], nil, feminine)
		end
		if (snak.datavalue.type == "time") then
			return formatDate(snak.datavalue.value.time, snak.datavalue.value.precision, snak.datavalue.value.timezone)
		end
		if (snak.datavalue.type == "monolingualtext") then
			return snak.datavalue.value.text
		end
		if (snak.datavalue.type == "quantity") then
			local unit = '1'
			local amount = snak.datavalue.value.amount
			local unitQ = mw.ustring.match(snak.datavalue.value.unit, 'Q%d+')
			if unitQ ~= nil then
				unit = p.findOneValueNoRef('P558', unitQ)
				if unit == nil or mw.ustring.len(unit) == 0 then
					unit = p.findLabel(unitQ, nil)
				end
                                if unit == nil then
                                        unit = "" 
                                end
	
			end
			if tonumber(amount) ~= nil then
				amount = mw.language.new(lang.code):formatNum(tonumber(amount))
			end
			
			return amount .. (unit ~= '1' and (mw.text.decode('&nbsp;') .. unit) or '')
		end
		return snak.datavalue.value
	end
	return ""
end

p.printSnak = function(snak)
	return snakToString(snak)
end

p.outputReferences = function (claim)
	local refMapping = {}
	local authorityPropertiesMap = {}
	local frame = mw.getCurrentFrame()
	
	refMapping["P1433"] = "publisher"
	refMapping["P123"] = "publisher"
	refMapping["P143"] = "publisher"
	refMapping["P1476"] = "contribution"
	refMapping["P854"] = "url"
	refMapping["P813"] = "accessdate"
	refMapping["P50"] = "author"
	refMapping["P577"] = "date"
	refMapping["P248"] = "title"
	refMapping["P304"] = "page"
	
	authorityPropertiesMap['Q36578'] = 'P227' -- GND identifier
	authorityPropertiesMap['Q20666306'] = 'P268' -- BnF identifier
	authorityPropertiesMap['Q37312'] = 'P345' -- IMDb identifier
	authorityPropertiesMap['Q1139587'] = 'P2334' -- Swedish film database identifier
	authorityPropertiesMap['Q278487'] = 'P662' -- PubChem identifier
	
	
	local primaryProperties = {}
	primaryProperties["P1433"] = "publisher"
	primaryProperties["P123"] = "publisher"
	primaryProperties["P1476"] = "contribution"
	primaryProperties["P248"] = "title"
	primaryProperties["P854"] = "url"
	primaryProperties["P50"] = "author"
	local out = ""
	if claim then
		for ref in pairs(claim.references or {}) do
			local citationArguments = {}
			local citationArgumentsFound = false
			local refname = ""
			for snakkey, snakval in pairs(claim.references[ref].snaks) do
				if refMapping[snakkey] ~= nil then
					local snakData = {}
					for snakIndex,snakValElement in ipairs(snakval) do
						local formattedSnakValElement = snakToString(snakValElement)
						if isValueSnak(snakValElement) and snakValElement.datatype == 'time' then
							formattedSnakValElement = DateUtils.formatDate(DateUtils.parseWikidataDate(snakValElement.datavalue.value.time, snakValElement.datavalue.value.precision), false , true)
						end	
						table.insert(snakData, formattedSnakValElement)
					end
					citationArguments[refMapping[snakkey]] = table.concat(snakData, ", ", 1, #snakData)
					refname = refname .. '_' .. refMapping[snakkey] .. '_' .. mw.ustring.gsub(mw.ustring.gsub(mw.text.nowiki(citationArguments[refMapping[snakkey]]), '&#%d+;', ''), ' ', '')
					if primaryProperties[snakkey] then
						citationArgumentsFound = true
					end
					if snakkey == 'P248' or snakkey == 'P143' then -- "stated in" or "imported from", can be an authority file
						if snakval[1].datavalue and snakval[1].datavalue.type == 'wikibase-entityid' then
							local statedInWbId = snakval[1].datavalue.value.id
							
							-- if Wikimedia project, ignore
							for _idx, eachStatedInInstanceOfClaim in pairs(mw.wikibase.getAllStatements(statedInWbId, 'P31')) do
								if eachStatedInInstanceOfClaim.mainsnak and eachStatedInInstanceOfClaim.mainsnak.datavalue and eachStatedInInstanceOfClaim.mainsnak.datavalue.type == 'wikibase-entityid' and 
								(eachStatedInInstanceOfClaim.mainsnak.datavalue.value['numeric-id'] == 10876391 or eachStatedInInstanceOfClaim.mainsnak.datavalue.value['numeric-id'] == 14827288) then
									citationArgumentsFound = false
									break
								end
							end
							for _idx, eachStatedInInstanceOfClaim in pairs(mw.wikibase.getAllStatements(statedInWbId, 'P1269')) do
								if eachStatedInInstanceOfClaim.mainsnak and eachStatedInInstanceOfClaim.mainsnak.datavalue and eachStatedInInstanceOfClaim.mainsnak.datavalue.type == 'wikibase-entityid' and 
								eachStatedInInstanceOfClaim.mainsnak.datavalue.value['numeric-id'] == 16222597 then
									citationArgumentsFound = false
									break
								end
							end
							-- extract data about authority file
							local authorityWbEntityId = authorityPropertiesMap[StringUtils._prependIfMissing({statedInWbId, 'Q'})]
							if authorityWbEntityId then
								local authorityUrlFormatClaims = mw.wikibase.getBestStatements(authorityWbEntityId, 'P1630')
								if authorityUrlFormatClaims and 0 < #authorityUrlFormatClaims then
								 	local formatterUrl = snakToString(authorityUrlFormatClaims[1].mainsnak)
								 	local crtEntityId = mw.wikibase.getEntityIdForCurrentPage()
								 	if crtEntityId then
								 		local entityAuthIdClaims = mw.wikibase.getBestStatements(crtEntityId, authorityWbEntityId)
								 		if entityAuthIdClaims and 0 < #entityAuthIdClaims and hasValueSnak(entityAuthIdClaims[1]) then
								 			citationArguments['chapterurl'] = mw.ustring.gsub(formatterUrl, '%$1', entityAuthIdClaims[1].mainsnak.datavalue.value)
								 			citationArguments['chapter'] = p.labelIn({args = {'ro'}}) or p.labelIn({args = {'en'}})
							 			end
						 			end
				 				end
	 						elseif citationArgumentsFound == true then
	 							--extract URL from target entity
	 							local statedInUrl = nil
	 							-- the order of the array is important, as we only search the first occurence
	 							local onlinelinksprops = {'P953', 'P854', 'P856', 'P1581', 'P2397','P1065'}
								for _,eachOnlineLinkProp in ipairs(onlinelinksprops) do
									local linkId = p.findOneValueNoRef(eachOnlineLinkProp, statedInWbId)
									
									if linkId then
										local linkFormatter = p.findOneValueNoRef('P1630', eachOnlineLinkProp) or '$1'
										if linkFormatter then
											linkId = mw.ustring.gsub(linkId, '%%', '%%%%')
											statedInUrl = mw.ustring.gsub(linkFormatter, '$1', linkId)
											break
										else
											statedInUrl = linkId
											break
										end
									end
								end
	 							if statedInUrl then
	 								citationArguments[refMapping[snakkey]] = StringUtils._capitalize({p.findTitleOfWork(statedInWbId)})
	 								citationArguments['url'] = statedInUrl
	 							else
	 								local props = p.getEntityIdsList(statedInWbId, 'P1687')
	 								if props then for _,eachOnlineLinkProp in ipairs(onlinelinksprops) do
		 								for _,prop in ipairs(props) do
		 									if eachOnlineLinkProp == 'P' .. prop then 
		 										citationArguments[refMapping[snakkey]] = StringUtils._capitalize({p.findTitleOfWork(statedInWbId)})
		 										citationArguments['url'] = p.findOneValueNoRef(eachOnlineLinkProp) 
		 									end
		 									break
		 								end
		 							end end
						        end
					        end
			 			end
					end
				end
			end
			if citationArgumentsFound then
				
				--post-process citation arguments:
				--1. if publisher is missing and contribution and title are present, change title to publisher and contribution to title
				if citationArguments['publisher'] == nil and citationArguments['contribution'] and citationArguments['title'] then
					citationArguments['publisher'] = citationArguments['title']
					citationArguments['title'] = citationArguments['contribution']
					citationArguments['contribution'] = nil
				end
				--2. if contribution is present but title is not, change contribution to title
				if citationArguments['contribution'] and citationArguments['title'] == nil then
					citationArguments['title'] = citationArguments['contribution']
					citationArguments['contribution'] = nil
				end
				--3. if title is a wikilink, break it down and assign article link separately
				if citationArguments['title'] then 
					local titlink, titplain = mw.ustring.match(citationArguments['title'], '%[%[(.*)|(.*)%]%]')
					if titlink and titplain then
						if not citationArguments['url'] then citationArguments['titlelink'] = titlink end
						citationArguments['title'] = titplain
					end
				end

				local parentFrame = frame:getParent()
				local childFrame = frame
				while (parentFrame ~= nil) do
					parentFrame = parentFrame:getParent()
					childFrame = childFrame:getParent()
				end
				local citFrame = childFrame:newChild{args = citationArguments}
				local cs1Frame = citFrame:newChild{args = {CitationClass = 'citation' } }
				local refText = Citation.citation(cs1Frame)
				out = out .. frame:extensionTag("ref", refText, { name = md5.sumhexa(refname) })
			end
		end
	end
	return out
end

p.getValueList = function(entityId, propertyId)
	entityId = entityId or mw.wikibase.getEntityIdForCurrentPage()
	if propertyId == nil or entityId == nil then return nil end
	local claims = mw.wikibase.getAllStatements(entityId, propertyId)
	if not claims then return nil end
	if #claims == 0 then return {} end
	local rez = {}
	local feminine = false
	local genders = mw.wikibase.getBestStatements(entityId, 'P21')
	if genders and #genders > 0 and genders[1] and genders[1].mainsnak and genders[1].mainsnak.datatype == 'wikibase-item' and genders[1].mainsnak.datavalue.type == 'wikibase-entityid' and genders[1].mainsnak.datavalue.value['numeric-id'] == 6581072 then
		feminine = true
	end
	for k, v in pairs(claims) do
		if hasValueSnak(v) then
			table.insert(rez, snakToString(v.mainsnak, feminine) .. p.outputReferences(v))
		end
	end
	return rez
end

local function findTimestampInTable(tbl)
	local crtEntry = ''
	if tbl then
		if tbl['P585'] then
			crtEntry = crtEntry .. snakToString(tbl['P585'][1].mainsnak or tbl['P585'][1])
		elseif tbl['P580'] then
			if tbl['P582'] then
				local starttime = snakToString(tbl['P580'][1].mainsnak or tbl['P580'][1])
				local endtime = snakToString(tbl['P582'][1].mainsnak or tbl['P582'][1])
				if starttime == endtime then
					crtEntry = crtEntry .. starttime
				else
					crtEntry = crtEntry .. starttime .. mw.text.decode('&ndash;', true) .. endtime
				end
			else 
				crtEntry = crtEntry .. 'din ' .. snakToString(tbl['P580'][1].mainsnak or tbl['P580'][1])
			end
		elseif tbl['P582'] then
			local endtime = DateUtils.extractDateFromWikidataSnak(tbl['P582'][1].mainsnak or tbl['P582'][1])
			if endtime then
				crtEntry = crtEntry .. 'până ' .. ((endtime.precision == 9 or endtime.precision == 10) and 'în' or 'la') .. ' ' .. DateUtils.formatDate(endtime)
			end
		end
	end
	return crtEntry
end

p.printTimestampForClaim = function(claim)
	if claim and claim.qualifiers then
		return ' (' .. findTimestampInTable(claim.qualifiers) .. ')'
	end
	return ''
end

p.findTimestamp = function(entityId)
	if type(entityId) == 'number' then entityId = StringUtils._prependIfMissing({tostring(entityId), 'Q'}) end
	if type(entityId) == 'table' then entityId = entityId.id end
	entityId = entityId or mw.wikibase.getEntityIdForCurrentPage()
	
	if entityId then
		local tbl = {}
		for _,propId in ipairs({'P580', 'P582', 'P585'}) do
			local propClaims = mw.wikibase.getAllStatements(entityId, propId)
			if propClaims and #propClaims > 0 then
				tbl[propId] = propClaims
			end
		end
		return findTimestampInTable(tbl)
	end
	return ''
end

p.getTimestamp = function(frame)
	return p.findTimestamp(frame and frame.args and frame.args[1] or nil)
end

p.getTimestampedValueList = function(entityId, propertyId, best)
	entityId = entityId or mw.wikibase.getEntityIdForCurrentPage()
	if propertyId == nil or entityId == nil then return nil end
	local claims
	if best then
		claims = mw.wikibase.getBestStatements(entityId, propertyId)
	else
		claims = mw.wikibase.getAllStatements(entityId, propertyId)
	end
	local rez = {}
	if claims and claims[1] then
		local rawclaims = {}
		for k, v in pairs(claims) do
			if hasValueSnak(v) then
				table.insert(rawclaims, v)
			end
		end
		for k, v in pairs(rawclaims) do
			local crtEntry = snakToString(v.mainsnak)
			crtEntry = crtEntry .. p.printTimestampForClaim(v)
			crtEntry = crtEntry .. p.outputReferences(v)
			table.insert(rez, crtEntry)
		end
	end
	return rez
end	

p._getValueListWithSeparator = function(funcArgs)
	local separator = mw.text.trim(funcArgs[1] or ", ")
	local propertyId = mw.text.trim(funcArgs[2] or "")
	local entityId = mw.text.trim(funcArgs[3] or "")
	if entityId == "" then entityId = mw.wikibase.getEntityIdForCurrentPage() end
	local limit = funcArgs[4] or funcArgs['limit']
	local limitVal = 0
	if limit and limit == mw.ustring.match(limit, '%d+') then
		limitVal = tonumber(limitVal)
	end
	
	local values = p.getValueList(entityId, propertyId)
	if not values then return nil end
	local extraSpec = nil
	if 0 < limitVal and #values > limitVal + 1 then
		local hiddenVals = #values - limitVal
		while #values > limitVal do
			table.remove(values, limitVal + 1)
		end
		extraSpec = '[[:d:' .. entityId .. '#' .. propertyId .. "|...''încă " .. tostring(limitVal) .. "'']]"
		table.insert(values, extraSpec)
	end
	return values and table.concat(values, separator)
end

p.getValueListWithSeparator = function(frame)
	local funcArgs = getArgs(frame, {frameOnly = true})
	return p._getValueListWithSeparator(funcArgs)
end

p.getValue = function(frame)
	local args = getArgs(frame)
	return p._getValueListWithSeparator({', ', args[1], mw.wikibase.getEntityIdForCurrentPage()})
end

p._getTimestampedValueListWithSeparator = function(funcArgs)
	local separator = funcArgs[1] or ", "
	local propertyId = funcArgs[2]
	local entityId = funcArgs[3]
	local best = funcArgs['best'] == 'y' or funcArgs['best'] == 'yes'
	local values = p.getTimestampedValueList(entityId, propertyId, best)
	return values and table.concat(values, separator)
end

p.getTimestampedValueListWithSeparator = function(frame)
	local funcArgs = getArgs(frame, {frameOnly = true})
	return p._getTimestampedValueListWithSeparator(funcArgs)
end

local function extractWikidataIdsFromClaimList(claims)
	local rez = {}
	if claims and #claims > 0 then
		for k, v in pairs(claims) do
			if hasValueSnak(v) and v.mainsnak.datavalue.type == 'wikibase-entityid' then
				table.insert(rez, v.mainsnak.datavalue.value['numeric-id'])
			end
		end
	end
	return rez
end

p.getEntityIdsList = function(entityId, propertyId)
	entityId = entityId or mw.wikibase.getEntityIdForCurrentPage()
	if propertyId == nil or entityId == nil then return nil end
	local claims = nil
	if entityId then
		claims = mw.wikibase.getAllStatements(entityId, propertyId)
	end
	return extractWikidataIdsFromClaimList(claims)
end

p.getBestEntityIdsList = function(entityId, propertyId)
	local claims = nil
	if propertyId == nil then return nil end
	if type(entityId) == 'table' then
		claims = entityId:getBestStatements(propertyId)
	else
		if type(entityId) == 'number' then entityId = StringUtils._prependIfMissing({tostring(entityId), 'Q'}) end
		if type(propertyId) == 'number' then propertyId = StringUtils._prependIfMissing({tostring(propertyId), 'P'}) end
		entityId = entityId or mw.wikibase.getEntityIdForCurrentPage()
		if propertyId == nil or entityId == nil then return nil end
		claims = mw.wikibase.getBestStatements(entityId, propertyId)
	end
	if not claims then return nil end
	return extractWikidataIdsFromClaimList(claims)
end

local timestampComparator = function(p1, p2)
	if p1 and p2 then
		local q1 = p1.qualifiers
		local q2 = p2.qualifiers
		local d1 = nil
		local d2 = nil
		if q1 and q2 then
			if q1['P580'] and q1['P580'][1] and q1['P580'][1].datavalue then
				d1 = p.extractDateFromClaim(q1['P580'][1])
			end
			if q2['P580'] and q2['P580'][1] and q2['P580'][1].datavalue then
				d2 = p.extractDateFromClaim(q2['P580'][1])
			end
			if d1 and d2 then return DateUtils.compare(d1, d2) > 0
			elseif d1 then return true
			elseif d2 then return false end
		elseif q1 then return true
		elseif q2 then return false
		end
	else
		if p1 then return true end
		if p2 then return false end
	end
	return false
end

p.findBestClaimsForProperty = function(entity, propertyId)
	if propertyId == nil then return nil end
	if entity == nil then entity = mw.wikibase.getEntityIdForCurrentPage() end
	if type(entity) == 'table' then return entity:getBestStatements(propertyId) end
	if type(entity) == 'number' then entity = StringUtils._prependIfMissing({tostring(entity), 'Q'}) end
	if entity == nil then return nil end
	return mw.wikibase.getBestStatements(entity, propertyId)
end

p.findClaimsForProperty = function(entity, propertyId)
	if propertyId == nil then return nil end
	if entity == nil then entity = mw.wikibase.getEntityIdForCurrentPage() end
	if type(entity) == 'table' and entity.claims then return entity.claims[propertyId] end
	if type(entity) == 'number' then entity = StringUtils._prependIfMissing({tostring(entity), 'Q'}) end
	if entity == nil then return nil end
	return mw.wikibase.getAllStatements(entity, propertyId)
end

p.findSortedClaimsForProperty = function(entity, propertyId)
	local rawClaims = p.findClaimsForProperty(entity, propertyId)
	if rawClaims == nil then return {} end
	
	table.sort(rawClaims, timestampComparator)
	return rawClaims
end

p.findQualifierValueListForClaim = function(claim, qualifierId)
	if claim == nil or claim.qualifiers == nil or qualifierId == nil then return {} end
	local quals = {}
	local wikidataQualifiers = claim.qualifiers[qualifierId]
	if wikidataQualifiers then
		for qualK, qualV in pairs(wikidataQualifiers) do
			table.insert(quals, snakToString(qualV))
		end
	end
	return quals
end

p.getQualifierValue = function(frame)
	local propertyID = mw.text.trim(frame.args[1] or "")
	local qualifierID = mw.text.trim(frame.args[2] or "")
	local entity = mw.wikibase.getEntity()
	if entity and entity.claims ~= nil and entity.claims[propertyID] ~= nil then
		local out = {}
		for k, v in pairs(entity.claims[propertyID]) do
			if v.qualifiers and v.qualifiers[qualifierID] then
				for k2, v2 in pairs(v.qualifiers[qualifierID]) do
					if isValueSnak(v2) == 'value' then
						table.insert(out, snakToString(v2))
					end
				end
			end
		end
		return table.concat(out, ", ")
	else
		return ""
	end
end

-- This is used to get a value like 'male' (for property p21) which won't be linked and numbers without the thousand separators
p.getRawValue = function(frame)
	local propertyID = mw.text.trim(frame.args[1] or "")
	local input_parm = mw.text.trim(frame.args[2] or "")
	local entity = mw.wikibase.getEntityObject()
	local claims = nil
	if entity and entity.claims then
		claims = entity.claims[propertyID]
	end
	if claims then
		local result = entity:formatPropertyValues(propertyID, mw.wikibase.entity.claimRanks).value
	
		-- if number type: remove thousand separators
		if (hasValueSnak(claims[1]) and claims[1].mainsnak.datavalue.type == "quantity") then
			result = mw.ustring.gsub(result, "(%d),(%d)", "%1%2")
		end
		return result
	else
		return ""
	end
end

p.getRawQualifierValue = function(frame)
	local propertyID = mw.text.trim(frame.args[1] or "")
	local qualifierID = mw.text.trim(frame.args[2] or "")
	local input_parm = mw.text.trim(frame.args[3] or "")
	if input_parm == "FETCH_WIKIDATA" then
		local entity = mw.wikibase.getEntity()
		if entity.claims[propertyID] ~= nil then
			local out = {}
			for k, v in pairs(entity.claims[propertyID]) do
				for k2, v2 in pairs(v.qualifiers[qualifierID]) do
					if isValueSnak(v2) then
						if v2.datavalue.value["numeric-id"] then
							out[#out + 1] = mw.wikibase.label("Q" .. v2.datavalue.value["numeric-id"])
						else
							out[#out + 1] = v2.datavalue.value
						end
					end
				end
			end
			local ret = table.concat(out, ", ")
			return string.upper(string.sub(ret, 1, 1)) .. string.sub(ret, 2)
		else
			return ""
		end
	else
		return input_parm
	end
end

p.extractDateFromClaim = function(claimOrSnak)
	local claim
	if claimOrSnak.mainsnak then claim = claimOrSnak.mainsnak else claim = claimOrSnak end
	if claim.datatype == 'time' and isValueSnak(claim) then
		local d = {}
		local iSOTimeSign = mw.ustring.sub(claim.datavalue.value.time, 1, 1)
		d.precision = tonumber(claim.datavalue.value.precision)
		d.calendarmodel = claim.datavalue.value.calendarmodel
		wdDate = DateUtils.parseWikidataDate(claim.datavalue.value.time, d.precision)
		if wdDate ~= nil then
			d.month = wdDate.month
		    d.day = wdDate.day
		else
			d.month = 1
			d.day = 1
		end
		if d.precision <= 9 then
			d.year = tonumber(mw.ustring.match(claim.datavalue.value.time, "%d+"))
			if iSOTimeSign == '-' then d.year = -d.year end
		elseif wdDate ~= nil then
			d.year = wdDate.year
		else
			d.year = 1
		end
		d.claim = claimOrSnak
		return d
	end
	return nil
end

p.findDateValues = function(propertyId, entityId)
	entityId = entityId or mw.wikibase.getEntityIdForCurrentPage()
	
	if entityId then
		local bestclaims = mw.wikibase.getBestStatements(entityId, propertyId)
		local bestdates = {}
		
		if bestclaims then for k, v in pairs(bestclaims) do
			if hasValueSnak(v) and v.mainsnak.datatype == 'time' then
				local d = p.extractDateFromClaim(v)
				table.insert(bestdates, d)
			elseif hasValueSnak(v) then
				local d = {}
				d.claim = v
				table.insert(bestdates, d)
			end
		end end
		return bestdates
	end
end

-- This is used to get a date value for date_of_birth (p569), etc. which won't be linked -- consolidate by testing if entity.claims[propertyID].mainsnak.datavalue.type is "time"
-- Dates are stored as 28 characters if the year  >99 -- e.g. +00000002014-01-01T00:00:00Z for 2014
-- Dates are stored as 26 characters if the year =<99 -- e.g. +000000050-01-01T00:00:00Z   for 50 CE
p.getDateValue = function(frame)
	local args = getArgs(frame, { frameOnly = true })
	local propertyId = args[1]
	local entityId = args[2] or mw.wikibase.getEntityIdForCurrentPage()
	if entityId then
		local claims = mw.wikibase.getAllStatements(entityId, propertyId)
		local out = {}
		if claims then for _,eachClaim in pairs(claims) do
			if hasValueSnak(eachClaim) then
				local extractedDate = p.extractDateFromClaim(eachClaim)
				table.insert(out, GregorianDate.displayDualDateIfInInterval(extractedDate, true))
			end
		end end
		return table.concat(out, ", ")
	else
		return ""
	end
end

p.getQualifierDateValue = function(frame)
	local propertyID = mw.text.trim(frame.args[1] or "")
	local qualifierID = mw.text.trim(frame.args[2] or "")
	local input_parm = mw.text.trim(frame.args[3] or "")
	local date_format = mw.text.trim(frame.args[4] or "dmy")
	if input_parm == "FETCH_WIKIDATA" then
		local entity = mw.wikibase.getEntity()
		if entity.claims[propertyID] ~= nil then
			local out = {}
			local dt = {}
			for k, v in pairs(entity.claims[propertyID]) do
				for k2, v2 in pairs(v.qualifiers[qualifierID]) do
					if isValueSnak(v2) then
						local d = v2.datavalue.value.time
						if #d > 26 then
							dt.year = string.sub(d, 9, 12)
							dt.month = string.sub(d, 14, 15)
							dt.day = string.sub(d, 17, 18)
						else
							dt.year = string.sub(d, 9, 10)
							dt.month = string.sub(d, 12, 13)
							dt.day = string.sub(d, 15, 16)
						end
						if date_format == "mdy" then
							out[#out + 1] = os.date("%B %e, %Y", os.time(dt))
						elseif date_format == "my" then
							out[#out + 1] = os.date("%B %Y", os.time(dt))
						elseif date_format == "y" then
							out[#out + 1] = os.date("%Y", os.time(dt))
						else
							out[#out + 1] = os.date("%e %B %Y", os.time(dt))
						end
					end
				end
			end
			return table.concat(out, ", ")
		else
			return ""
		end
	else
		return input_parm
	end
end

-- returns the value of the specified qualifier for the specified preferred value of the property of the specified entity (or the current entity)
p.findQualifierForPreferredPropertyValue = function(entityId, propertyId, qualifierId, separator)
	entityId = entityId or mw.wikibase.getEntityIdForCurrentPage()
	if entityId == nil then return nil end
	local claims = mw.wikibase.getAllStatements(entityId, propertyId)
	local out = {}
	if claims and claims[1] then
		for claimK, claimV in pairs(claims) do
			if claimV.rank == 'preferred' then
				local qual = claimV.qualifiers[qualifierId]
				if qual and qual.mainsnak then table.insert(out, snakToString(qual)) end
			end
		end
	end
	return table.concat(out, separator)
end

p.getQualifierForPreferredPropertyValue = function(frame)
	local args = getArgs(frame)
	local entityId = args['entityId'] or args[1]
	local propertyId = args['propertyId'] or args[2]
	local qualifierId = args['qualifierId'] or args[3]
	local separator = args['separator'] or args[4] or ', '
	
	return p.findQualifierForPreferredPropertyValue(entityId, propertyId, qualifierId, separator)
end

-- This is used to get the TA98 (Terminologia Anatomica first edition 1998) values like 'A01.1.00.005' (property P1323)
-- which are then linked to http://www.unifr.ch/ifaa/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/01.1.00.005%20Entity%20TA98%20EN.htm
-- uses the newer mw.wikibase calls instead of directly using the snaks
-- formatPropertyValues returns a table with the P1323 values concatenated with ", " so we have to split them out into a table in order to construct the return string
p.getTAValue = function(frame)
	local ent = mw.wikibase.getEntityObject()
	local props = ent:formatPropertyValues('P1323')
	local out = {}
	local t = {}
	for k, v in pairs(props) do
		if k == 'value' then
			t = mw.text.split( v, ", ")
			for k2, v2 in pairs(t) do
				out[#out + 1] = "[http://www.unifr.ch/ifaa/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/" .. string.sub(v2, 2) .. "%20Entity%20TA98%20EN.htm " .. v2 .. "]"
			end
		end
	end
	ret = table.concat(out, "<br> ")
	if #ret == 0 then
		ret = "Invalid TA"
	end
	return ret
end

-- returns the page id (Q...) of the current page or nothing of the page is not connected to Wikidata
p.pageId = p.getEntityId

-- the "qualifiers" and "snaks" field have a respective "qualifiers-order" and "snaks-order" field
-- use these as the second parameter and this function instead of the built-in "pairs" function
-- to iterate over all qualifiers and snaks in the intended order.
local function orderedpairs(array, order)
	if not order then return pairs(array) end
 
	-- return iterator function
    local i = 0
    return function()
        i = i + 1
        if order[i] then
            return order[i], array[order[i]]
        end
    end	
end

-- precision: 0 - billion years, 1 - hundred million years, ..., 6 - millennia, 7 - century, 8 - decade, 9 - year, 10 - month, 11 - day, 12 - hour, 13 - minute, 14 - second
local function normalizeDate(date)
	date = mw.text.trim(date, "+")
	-- extract year
	local yearstr = mw.ustring.match(date, "^\-?%d+")
	local year = tonumber(yearstr)
	-- remove leading zeros of year
	return year .. mw.ustring.sub(date, #yearstr + 1), year
end

function formatDate(indate, precision, timezone)
	precision = precision or 11
	date, year = normalizeDate(indate)
	if year == 0 and precision <= 9 then return "" end
 
 	-- precision is 10000 years or more
	if precision <= 5 then
		local factor = 10 ^ ((5 - precision) + 4)
		local y2 = math.ceil(math.abs(year) / factor)
		local relative = mw.ustring.gsub(i18n.datetime[precision], "$1", tostring(y2))
		if year < 0 then
			relative = mw.ustring.gsub(i18n.datetime.beforenow, "$1", relative)
		else
			relative = mw.ustring.gsub(i18n.datetime.afternow, "$1", relative)
		end			
		return relative
	end
 
 	-- precision is decades, centuries and millennia
	local era
	if precision == 6 then era = mw.ustring.gsub(i18n.datetime[6], "$1", tostring(math.floor((math.abs(year) - 1) / 1000) + 1)) end
	if era then
		if year < 0 then era = mw.ustring.gsub(mw.ustring.gsub(i18n.datetime.bc, '"', ""), "$1", era)
		elseif year > 0 then era = mw.ustring.gsub(mw.ustring.gsub(i18n.datetime.ad, '"', ""), "$1", era) end
		return era
	end
 
 	if precision >= 7 then
 		return DateUtils.formatDate(DateUtils.parseWikidataDate(indate, precision))
 	end
end

local function printDatavalueEntity(data, parameter)
	-- data fields: entity-type [string], numeric-id [int, Wikidata id]
	local id = "Q" .. data["numeric-id"]
	if parameter then
		if parameter == "link" then
			return "[[" .. (mw.wikibase.sitelink(id) or (":d:" .. id))  .. "|" ..  (mw.wikibase.label(id) or id)  .. "]]"
		else
			return data[parameter]
		end
	else
		if data["entity-type"] == "item" then return mw.wikibase.label("Q" .. data["numeric-id"]) or id else printError("unknown-entity-type") end
	end
end

local function printDatavalueTime(data, parameter)
	-- data fields: time [ISO 8601 time], timezone [int in minutes], before [int], after [int], precision [int], calendarmodel [wikidata URI]
	--   precision: 0 - billion years, 1 - hundred million years, ..., 6 - millennia, 7 - century, 8 - decade, 9 - year, 10 - month, 11 - day, 12 - hour, 13 - minute, 14 - second
	--   calendarmodel: e.g. http://www.wikidata.org/entity/Q1985727 for the proleptic Gregorian calendar or http://www.wikidata.org/wiki/Q11184 for the Julian calendar]
	if parameter then
		if parameter == "calendarmodel" then data.calendarmodel = mw.ustring.match(data.calendarmodel, "Q%d+") -- extract entity id from the calendar model URI
		elseif parameter == "time" then data.time = normalizeDate(data.time) end
		return data[parameter]
	else
		return formatDate(data.time, data.precision, data.timezone)
	end
end

function findClaims(entity, property)
	if not property or not entity or not entity.claims then return end
 
	if mw.ustring.match(property, "^P%d+$") then
		-- if the property is given by an id (P..) access the claim list by this id
		return entity.claims[property]
	else
		-- otherwise, iterate over all properties, fetch their labels and compare this to the given property name
		for k, v in pairs(entity.claims) do
			if mw.wikibase.label(k) == property then return v end
		end
		return
	end
end

function getSnakValue(snak, parameter)
	-- snaks have three types: "novalue" for null/nil, "somevalue" for not null/not nil, or "value" for actual data
	if snak.snaktype == "novalue" then return i18n["novalue"]
	elseif snak.snaktype == "somevalue" then return i18n["somevalue"]
	elseif snak.snaktype ~= "value" then return nil, printError("unknown-snak-type")
	end
 
	-- call the respective snak parser
	if snak.datavalue.type == "string" then return snak.datavalue.value
	elseif snak.datavalue.type == "globecoordinate" then return printDatavalueCoordinate(snak.datavalue.value, parameter)
	elseif snak.datavalue.type == "quantity" then return printDatavalueQuantity(snak.datavalue.value, parameter)
	elseif snak.datavalue.type == "time" then return printDatavalueTime(snak.datavalue.value, parameter)
	elseif snak.datavalue.type == "wikibase-entityid" then return printDatavalueEntity(snak.datavalue.value, parameter)
	elseif snak.datavalue.type == "monolingualtext" then return printDatavalueMonolingualText(snak.datavalue.value, parameter)
	else return nil, printError("unknown-datavalue-type")
	end
end
 
function getQualifierSnak(claim, qualifierId)
	-- 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.qualifiers[qualifierId]
			if qualifier then return qualifier[1] end
		end
		return nil, printError("qualifier-not-found")
	else
		-- otherwise return the main snak
		return claim.mainsnak
	end
end
 
function getValueOfClaim(claim, qualifierId, parameter)
	local error
	local snak
	snak, error = getQualifierSnak(claim, qualifierId)
	if snak then
		return getSnakValue(snak, parameter)
	else
		return nil, error
	end
end

function p.claim(frame)
	local property = frame.args[1] or ""
	local id = frame.args["id"]	-- "id" must be nil, as access to other Wikidata objects is disabled in Mediawiki configuration
	local qualifierId = frame.args["qualifier"]
	local parameter = frame.args["parameter"]
	local list = frame.args["list"]
	local references = frame.args["references"]
	local showerrors = frame.args["showerrors"]
	local default = frame.args["default"]
	if default then showerrors = nil end
 
	-- get wikidata entity
	local entity = mw.wikibase.getEntityObject(id)
	if not entity then
		if showerrors then return printError("entity-not-found") else return default end
	end
	-- fetch the first claim of satisfying the given property
	local claims = findClaims(entity, property)
	if not claims or not claims[1] then
		if showerrors then return printError("property-not-found") else return default 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 = rankmap[claims[a].rank or "normal"] ..  string.format("%08d", a)
		local rankb = rankmap[claims[b].rank or "normal"] ..  string.format("%08d", b)
		return ranka < rankb
 	end
	table.sort(sortindices, comparator)
 
	local result
	local error
	if list then
		local value
		-- iterate over all elements and return their value (if existing)
		result = {}
		for idx in pairs(claims) do
			local claim = claims[sortindices[idx]]
			value, error =  getValueOfClaim(claim, qualifierId, parameter)
			if not value and showerrors then value = error end
			if value and references then value = value .. p.outputReferences(claim) end
			result[#result + 1] = value
		end
		result = table.concat(result, list)
	else
		-- return first element	
		local claim = claims[sortindices[1]]
		result, error = getValueOfClaim(claim, qualifierId, parameter)
		if result and references then result = result .. p.outputReferences(claim) end
	end
 
	if result then return result else
		if showerrors then return error else return default end
	end
end

p.getPreferredValue = function(frame)
	local args = getArgs(frame)
	local propertyID = args[1] or args['propertyId'] or args['pid']
	local entityID = args[2] or args['entityId'] or args['qid'] or mw.wikibase.getEntityIdForCurrentPage()
	if entityID == nil or propertyID == nil then return nil end
	local claims = mw.wikibase.getAllStatements(entityID, propertyID)
	if claims then
		-- if wiki-linked value output as link if possible
		if hasValueSnak(claims[1]) then
			local out = {}
			for k, v in pairs(claims) do
				if (v.rank == 'preferred') then
					local snakText = snakToString(v.mainsnak) .. p.outputReferences(v)

					if snakText ~= "" then
						out[#out + 1] = snakText
					end
				end
			end
			return table.concat(out, ", ")
		end
	else
		return ""
	end
	return ""
end


-- look into entity object
function p.ViewSomething(frame)
	local data = mw.wikibase.getEntityObject()
	if not data then
		return nil
	end

	local f = frame.args[1] and frame or frame:getParent()

	local i = 1
	while true do
		local index = f.args[i]
		if not index then
			return tostring(data)
		end
		
		data = data[index] or data[tonumber(index)]
		if not data then
			return
		end
		
		i = i + 1
	end
end

function p.Dump(frame)
	local data = mw.wikibase.getEntityObject()
	if not data then
		return i18n.warnDump
	end

	local f = frame.args[1] and frame or frame:getParent()

	local i = 1
	while true do
		local index = f.args[i]
		if not index then
			return "<pre>"..mw.dumpObject(data).."</pre>".. i18n.warnDump
		end

		data = data[index] or data[tonumber(index)]
		if not data then
			return i18n.warnDump
		end

		i = i + 1
	end
end

-- Returnează o singură valoare din cele cu rangul cel mai înalt cu referințele corespunzătoare pentru o proprietate specificată
-- De apelat din alte module
function p.findOneValue(propertyID, entity)
	local entityId = nil
	if type(entity) == 'table' then entityId = entity.id
	elseif type(entity) == 'number' then entityId = StringUtils._prependIfMissing({tostring(entity), 'Q'})
	elseif type(entity) == 'string' then entityId = entity
	end
		
	entityId = entityId or mw.wikibase.getEntityIdForCurrentPage()
	if not entityId then return nil end
	local claims = mw.wikibase.getBestStatements(entityId, propertyID)
	if claims and 0 < #claims then
		for _,eachClaim in ipairs(claims) do
			if hasValueSnak(eachClaim) then
				return snakToString(eachClaim.mainsnak) .. p.outputReferences(eachClaim)
			end
		end
	end
	return nil
end	

-- Returnează o singură valoare din cele cu rangul cel mai înalt pentru o proprietate specificată
-- De apelat din alte module
function p.findOneValueNoRef(propertyID, entity)
	local claims = nil
	if type(entity) == 'table' then
		claims = entity:getBestStatements(propertyID)
	else
		if type(entity) == 'number' then entity = 'Q' .. tostring(entity) end
		entity = entity or mw.wikibase.getEntityIdForCurrentPage()
		if not entity then return nil end
		claims = mw.wikibase.getBestStatements(entity, propertyID)
	end
	if claims and 0 < #claims then
		for _,eachClaim in ipairs(claims) do
			if hasValueSnak(eachClaim) then
				return snakToString(eachClaim.mainsnak)
			end
		end
	end
	return nil
end	

-- Returnează o singură valoare din cele cu rangul cel mai înalt pentru o proprietate specificată
-- De apelat din formate
p.getOneValueNoRef = function(frame)
	local propertyID, entityID
	propertyID, entityID = propAndEntity(frame.args[1], frame.args[2])
	local entity = nil
	if entityID ~= "" then entity = mw.wikibase.getEntityObject(entityID) end
	if entity == nil then entity = mw.wikibase.getEntityObject() end

	if entity == nil then return nil end
	return p.findOneValueNoRef(propertyID, entity)
end

-- Returnează o singură valoare din cele cu rangul cel mai înalt și cu referințele corespunzătoare pentru o proprietate specificată
-- De apelat din formate
p.getOneValue = function(frame)
	local args = getArgs(frame)
	local propertyID, entityID
	propertyID, entityID = propAndEntity(args[1], args[2])
	local entity = nil
	if entityID ~= "" then entity = mw.wikibase.getEntityObject(entityID) end
	if entity == nil then entity = mw.wikibase.getEntityObject() end
	
	if entity == nil then return nil end
	return p.findOneValue(propertyID, entity)
end

local function findLatestQualifierValueForOnePropertyOfAnEntity(entity, propertyId, qualifierId)
	if entity == nil then
		entity = mw.wikibase.getEntityObject()
	end
	if entity == nil then return '' end
	local claims = entity:getBestStatements(propertyId)
	if claims then
		if claims[1] then
			if claims[1].qualifiers then
				if claims[1].qualifiers[qualifierId] then
					local allQualifiers = {}
					for qk, qv in pairs(claims[1].qualifiers[qualifierId]) do
						table.insert(allQualifiers, qv)
					end
					local qIndex = 1
					local maxQTime = nil
					while maxQTime == nil and qIndex <= #allQualifiers do
						if allQualifiers[qIndex].datatype == 'time' then
							maxQTime = allQualifiers[qIndex]
						end
						qIndex = qIndex + 1
					end
					if maxQTime ~= nil then
						for i=qIndex,#allQualifiers do
							local msCrtQTime = tonumber(mw.language.new(lang.code):formatDate('U', allQualifiers[i].datavalue.value.time, nil))
							local msMaxQTime = tonumber(mw.language.new(lang.code):formatDate('U', maxQTime.datavalue.value.time, nil))
							if msCrtQTime > msMaxQTime then
								maxQTime = allQualifiers[i]
							end
						end
						if isValueSnak(maxQTime) then
							return formatDate(maxQTime.datavalue.value.time, maxQTime.datavalue.value.precision, maxQTime.datavalue.value.timezone)
						end
					end
					return ""
				else
					return ""
				end
			else
				return ""
			end
		else
			return ""
		end
	else 
		return ""
	end
end

-- Returnează valoarea cea mai recentă a qualifierului specificat pentru proprietea specificată a entității curente
-- De apelat din alte module
p.getLatestQualifierDateValueForOneProperty = function(frame)
 	local propertyId = mw.text.trim(frame.args[1] or "")
	local qualifierId = mw.text.trim(frame.args[2] or "")
	local entity = mw.wikibase.getEntityObject()
	
	return findLatestQualifierValueForOnePropertyOfAnEntity(entity, propertyId, qualifierId)
end

-- Returnează valoarea cea mai recentă a qualifierului specificat pentru proprietea specificată a entității curente
-- De apelat din formate
p.findLatestQualifierDateValueForOneProperty = function(propertyId, qualifierId)
	local entity = mw.wikibase.getEntityObject()
	return entity ~= nil and findLatestQualifierValueForOnePropertyOfAnEntity(entity, propertyId, qualifierId) or ''
end

-- Returnează un text ce conține referința pentru o proprietate; de apelat din formate
p.getReferenceForOneProperty = function(frame)
	local entity = mw.wikibase.getEntityObject()
	local propertyId = mw.text.trim(frame.args[1])
	local claims = entity:getBestStatements(propertyId)

	return p.outputReferences(claims[1])
end

-- Returnează o listă cu obiecte value asociate unei proprietăți a unei entități
-- Creată pentru a obține lista de coordonate a unui oraș în formă pură (listă cu obiectele value asociate)
-- Funcționează pentru: coordonate
-- TODO - de extins la mai multe tipuri de date, de exemplu texte multilingve, date calendaristice, itemuri wikibase
p.findDataValueObjects = function(entityId, propertyId)
	if propertyId == nil then return {} end
	entityId = entityId or mw.wikibase.getEntityIdForCurrentPage()
	if entityId == nil then return {} end
	local ret = {}
	local claims = mw.wikibase.getAllStatements(entityId, propertyId)
	if claims == nil then return ret end
	for claimIdx = 1, #claims do
		local snak = claims[claimIdx].mainsnak
		if isValueSnak(snak) then
			if snak.datatype == 'globe-coordinate' then
				table.insert(ret, snak.datavalue.value)
			end
		end
	end
	
	return ret		
end

-- Returnează labelul unei entități în limba specificată; dacă nu se găsește, atunci se încearcă în limba wikiului și apoi în limba engleză
p.findLabel = function(entityId, languageCode, default)
	local entity, ret
	if type(entityId) == 'string' then 
		ret = mw.wikibase.label(entityId)
		if ret then return ret end
		entity = mw.wikibase.getEntityObject(entityId)
	else
		entity = entityId
	end
	if entityId == nil then 
		entity = mw.wikibase.getEntityObject()
	end
	if not entity then return entityId or default or '' end
	if not languageCode or languageCode == '' then languageCode = lang.code end
	ret = entity:getLabel(languageCode) or entity:getLabel(lang.code) or default or entity:getLabel('en')
	return ret
end

p.getLabel = function(frame)
	local args = getArgs(frame, {frameOnly=true})
	local entityId = args[1]
	local languageCode = args[2] or lang.code
	local default = args['default']
	return p.findLabel(entityId, languageCode, default)
end

function formatCoordinates(entityId)
	entityId = entityId or mw.wikibase.getEntityIdForCurrentPage()
	if entityId == nil then return '' end
	local coordClaims = mw.wikibase.getAllStatements(entityId, 'P625')
	local formattedCoordsList = {}
	if coordClaims and coordClaims[1] then
		for coordIdx=1,#coordClaims do
			if coordClaims[coordIdx].mainsnak.datatype == 'globe-coordinate' then
				local latDir = coordClaims[coordIdx].mainsnak.datavalue.value.latitude < 0 and 'S' or 'N'
				local lonDir = coordClaims[coordIdx].mainsnak.datavalue.value.longitude < 0 and 'V' or 'E'
				local coordsText = mw.getCurrentFrame():expandTemplate{title='Coord', args={tostring(math.abs(coordClaims[coordIdx].mainsnak.datavalue.value.latitude)), latDir, tostring(math.abs(coordClaims[coordIdx].mainsnak.datavalue.value.longitude)), lonDir}}

				table.insert(formattedCoordsList, coordsText)
			end
		end
	end
	return table.concat(formattedCoordsList, ', ')
end

p.getFormattedCoordinates = function(frame)
	local origArgs = getArgs(frame)
	return formatCoordinates(origArgs[1] or origArgs['entityId'])
end

-- Returnează o numărul de valori cu cel mai mare rang pentru o proprietate specificată
-- De apelat din alte module
function p.countBestValues(propertyID, entity)
	if type(entity) == 'table' then
		entity = entity.id
	elseif type(entity) == 'number' then
		entity = 'Q' .. tostring(entity)
	elseif entity == nil then
		entity = mw.wikibase.getEntityIdForCurrentPage()
		if entity == nil then return 0 end
	end
	local claims = mw.wikibase.getBestStatements(entity, propertyID)
	local outList = {}
	if not claims then return 0 end
	return #claims
end	

-- Returnează o singură valoare din cele cu rangul cel mai înalt cu referințele corespunzătoare pentru o proprietate specificată
-- De apelat din alte module
function p.findBestValues(propertyID, entity)
	if type(entity) == 'table' then
		entity = entity.id
	elseif type(entity) == 'number' then
		entity = 'Q' .. tostring(entity)
	end
	if entity == nil then
		entity = mw.wikibase.getEntityIdForCurrentPage()
		if entity == nil then return {} end
	end
	if not StringUtils._emptyToNil({propertyID}) then return nil end
	local claims = mw.wikibase.getBestStatements(entity, propertyID)
	local outList = {}
	if claims then for claimIdx, actualClaim in pairs(claims) do
		if hasValueSnak(actualClaim) then
			table.insert(outList, snakToString(actualClaim.mainsnak) .. p.outputReferences(actualClaim))
		end
	end end
	return outList
end	

p._getBestValuesWithSeparator = function(entity, propertyID, sep)
	if propertyID == nil then return '' end
	local valueList = p.findBestValues(propertyID, entity)
	return valueList and table.concat(valueList, sep)
end

-- Returnează o listă a valorilor cu rangul cel mai înalt și cu referințele corespunzătoare pentru o proprietate specificată
-- De apelat din formate
p.getBestValuesWithSeparator = function(frame) 
	local sep = frame.args[1]
	if sep == nil or sep == '' then sep = ', ' end
	local propertyID = mw.text.trim(frame.args[2] or "")
	local entityID = mw.text.trim(frame.args[3] or "")
	local entity = nil
	if entityID ~= "" then entity = mw.wikibase.getEntityObject(entityID) end
	if entity == nil then entity = mw.wikibase.getEntityObject() end
	
	return p._getBestValuesWithSeparator(entity, propertyID, sep)
end

function p.findLanguageText(propertyId, langcode, entityId)
	-- return label of a Wikidata entity in the given language or the default language of this Wikipedia site
	entityId = entityId or mw.wikibase.getEntityIdForCurrentPage()
	if not entityId then return nil end
	local returnValue = nil
	langcode = langcode or 'ro'
	for eachClaimIdx, eachClaim in pairs(mw.wikibase.getAllStatements(entityId, propertyId)) do
		if hasValueSnak(eachClaim) and eachClaim.mainsnak.datavalue then
			if eachClaim.mainsnak.datavalue.type == 'monolingualtext' then
				if eachClaim.mainsnak.datavalue.value.language == langcode then returnValue = eachClaim.mainsnak.datavalue.value.text end
			elseif eachClaim.mainsnak.datavalue.type == 'string' then
				returnValue = eachClaim.mainsnak.datavalue.value
			elseif eachClaim.mainsnak.datavalue.type == 'wikibase-entityid' then
				returnValue = p.findLabel(eachClaim.mainsnak.datavalue.value.id, langcode)
			end
		end
	end
		
	return returnValue
end

function p.getLanguageText(frame)
	return p.findLanguageText(frame.args[1], frame.args[2] or 'ro', frame.args[3]) or ''
end

p.findShortestAlias = function(entityId)
	return p.findLinkToItem(entityId, false, false, true)
end

p.findImageAndCaption = function(entityId)
	local wikidataImages = p.findBestClaimsForProperty(entityId, 'P18')
	local imageName, imageCaption
	if wikidataImages and #wikidataImages > 0 then
		local wikidataImage = wikidataImages[1]
		if hasValueSnak(wikidataImage) and wikidataImage.mainsnak.datavalue then
			imageName = wikidataImage.mainsnak.datavalue.value
			local roDescr = p.findLabel(entityId, nil)
			if wikidataImage.qualifiers and wikidataImage.qualifiers['P2096'] then
				for _,eachImageDescrLangString in pairs(wikidataImage.qualifiers['P2096']) do
					if isValueSnak(eachImageDescrLangString) and eachImageDescrLangString.datavalue and eachImageDescrLangString.datavalue.value.language == 'ro' then
						roDescr = eachImageDescrLangString.datavalue.value.text or roDescr
					end
				end
			end
			imageCaption = roDescr
		end
	end
	return imageName, imageCaption
end

p.findLinkToWikidataItem = function(itemId, prefix)
	libraryUtil.checkType('findLinkToWikidataItem', 2, prefix, 'string', false)
	local qId = StringUtils._prependIfMissing({itemId, prefix})
	local itemLabel = p.findLabel(qId)
	return '[[:d:' .. (prefix == 'P' and 'Property:' or '') .. qId .. '|' .. (itemLabel or '') .. ' ' .. tostring(mw.html.create('small'):wikitext('(' .. qId .. ')')) .. ']]'
end

p.getLinkToWikidataItem = function(frame)
	local args = getArgs(frame)
	local prefix = args['prefix'] or 'Q'
	if not args[1] then return "''id de " .. (prefix == 'P' and 'proprietate' or 'item') .. " Wikidata nespecificat''" end
	return p.findLinkToWikidataItem(args[1], prefix)
end

p.formatExternalLink = function(pId, qId, text)
	local formatterUrl = p.findOneValueNoRef('P1630', pId) or '$1'
	local urlComponent = text or p.findOneValueNoRef(pId, qId)
	local formattedLink = mw.ustring.gsub(formatterUrl, '%$1', text or urlComponent)
	return formattedLink
end

p.isFemale = function(qId)
	local entityId = qId or mw.wikibase.getEntityIdForCurrentPage()
	if not entityId then return false end
	local genders = mw.wikibase.getBestStatements(entityId, 'P21')
	local feminineIds = { 6581072, 1052281, 43445 }
	
	if genders then for genderIdx,eachGender in ipairs(genders) do
		if hasValueSnak(eachGender) then for _,eachFemId in ipairs(feminineIds) do
			if eachFemId == eachGender.mainsnak.datavalue.value['numeric-id'] then return true end
		end end
	end end
	return false
end

p.findClaimForTimestamp = function(entityId, propertyId, timestamp)
	local propClaims = p.findSortedClaimsForProperty(entityId, propertyId)
	local bestClaim = nil
	if propClaims then for _,eachPropClaim in ipairs(propClaims) do
		if hasValueSnak(eachPropClaim)
			and mw.wikibase.entity.claimRanks['RANK_' .. mw.ustring.upper(eachPropClaim.rank)] >= mw.wikibase.entity.claimRanks.RANK_NORMAL then
			
			if eachPropClaim.mainsnak.datavalue.type ~= 'monolingualtext' or eachPropClaim.mainsnak.datavalue.value.language == 'ro' then
				local before = nil
				local after = nil
				if eachPropClaim.qualifiers then
					if eachPropClaim.qualifiers['P580'] and eachPropClaim.qualifiers['P580'][1] and isValueSnak(eachPropClaim.qualifiers['P580'][1]) then
						after = GregorianDate.convertToGregorianIfInInterval(DateUtils.extractDateFromWikidataSnak(eachPropClaim.qualifiers['P580'][1]))
					end
					if eachPropClaim.qualifiers['P582'] and eachPropClaim.qualifiers['P582'][1] and isValueSnak(eachPropClaim.qualifiers['P582'][1]) then
						before = GregorianDate.convertToGregorianIfInInterval(DateUtils.extractDateFromWikidataSnak(eachPropClaim.qualifiers['P582'][1]))
					end
			end
				if timestamp then
					if before and DateUtils.compare(timestamp, before) > 0 then --the claim list is sorted by before
						break
					elseif after == nil and before and DateUtils.compare(timestamp, before) < 0 then
						return eachPropClaim
					elseif after and before and DateUtils.compare(timestamp, before) < 0 and DateUtils.compare(timestamp, after) > 0 then 
						return eachPropClaim
					elseif after and before == nil and DateUtils.compare(timestamp, after) > 0 then
						return eachPropClaim
					end
				end
				if not bestClaim or mw.wikibase.entity.claimRanks['RANK_' .. mw.ustring.upper(bestClaim.rank)] < mw.wikibase.entity.claimRanks['RANK_' .. mw.ustring.upper(eachPropClaim.rank)] 
						or (mw.wikibase.entity.claimRanks['RANK_' .. mw.ustring.upper(bestClaim.rank)] < mw.wikibase.entity.claimRanks['RANK_' .. mw.ustring.upper(eachPropClaim.rank)] and not after) then
					bestClaim = eachPropClaim
				end
			end
		end
	end end

	if bestClaim then
		return bestClaim
	else
		return nil
	end
end

p.findOnlineLinks = function(onlinelinksprops, entityId)
	local onlinelinks = {}
	local onlinelinksprops = onlinelinksprops and #onlinelinksprops > 0 and onlinelinksprops or {'P856', 'P1581', 'P2013', 'P2002', 'P2847', 'P345', 'P3265', 'P3579', 'P3435', 'P2003', 'P2471', 'P2397', 'P953', 'P1065'}
	for _,eachOnlineLinkProp in ipairs(onlinelinksprops) do
		local linkId = p.findOneValueNoRef(eachOnlineLinkProp, entityId)
		if linkId then
			local linkFormatter = p.findOneValueNoRef('P1630', eachOnlineLinkProp) or '$1'
			if linkFormatter then
				linkId = mw.ustring.gsub(linkId, '%%', '%%%%')
				local link = mw.ustring.gsub(linkFormatter, '$1', linkId)
				local linkentities = p.getBestEntityIdsList(eachOnlineLinkProp, 'P1629')
				if linkentities and #linkentities > 0 then
					local linklabel = p.findLabel(StringUtils._prependIfMissing({linkentities[1], 'Q'}))
					table.insert(onlinelinks, '[' .. link .. ' ' .. linklabel .. ']')
				end
			end
		end
	end
	return onlinelinks
end

p.getOnlineLinks = function(frame)
	local args = getArgs(frame)
	local _,entityId = propAndEntity(StringUtils._prependIfMissing({args['qid'], 'Q'}))
	local onlinelinksprops = {}
	local passedProps = TableTools.compressSparseArray(args)
	for __,eachProp in ipairs(passedProps) do
		if mw.ustring.match(eachProp, 'P%d+') == eachProp then
			table.insert(onlinelinksprops, eachProp)
		end
	end
	
	return table.concat(p.findOnlineLinks(onlinelinksprops, entityId), tostring(mw.html.create('br')))
end

p.findTitleOfWork = function(entityId)
	local entity = nil
	if entityId then
		entityId = StringUtils._prependIfMissing({tostring(entityId), 'Q'})
	else
		entityId = mw.wikibase.getEntityIdForCurrentPage()
	end

	--- this comes first just for performance reasons
	if entityId then
		local localLabel, localLang = mw.wikibase.getLabelWithLang(entityId)
		if localLabel and localLang == 'ro' then
			return localLabel
		end
	else
		return nil
	end

	local langCode = nil
	for _,eachProperty in ipairs({'P364', 'P407'}) do
		for _,eachLangClaim in ipairs(mw.wikibase.getAllStatements(entityId, eachProperty)) do
			if not langCode and hasValueSnak(eachLangClaim) then
				local langEntityId = eachLangClaim.mainsnak.datavalue.value.id
				if LangUtils[langEntityId] then
					langCode = LangUtils[langEntityId]
					break
				end
				if langEntityId then
					for _,eachLangCodeClaim in ipairs(mw.wikibase.getAllStatements(langEntityId, 'P424')) do
						if not langCode and hasValueSnak(eachLangCodeClaim) then
							langCode = eachLangCodeClaim.mainsnak.datavalue.value
						end
					end
				end
			end
		end
	end
	
	local titles = {}
	for _,eachTitleClaim in ipairs(mw.wikibase.getAllStatements(entityId, 'P1476')) do
		if hasValueSnak(eachTitleClaim) then
			titles[eachTitleClaim.mainsnak.datavalue.value.language] = eachTitleClaim.mainsnak.datavalue.value.text
		end
	end

	return titles['ro'] or wrapInLangSpan(titles[langCode], langCode) or wrapInLangSpan(mw.wikibase.getEntity(entityId):getLabel(langCode)) or wrapInLangSpan(mw.wikibase.getEntity(entityId):getLabel('en'))
end

p.findTitlesOfWorksFromProperty = function(propertyId, entityId, limit)
	if limit == nil then limit = 10 end
	if entityId then entityId = StringUtils._prependIfMissing({tostring(entityId), 'Q'})
	else entityId = mw.wikibase.getEntityIdForCurrentPage() end
	
	local ret = {}
	local bestWorksClaims = mw.wikibase.getBestStatements(entityId, propertyId)
	for workIdx = 1,math.min(limit, #bestWorksClaims) do
		local eachWorkClaim = bestWorksClaims[workIdx]
		if hasValueSnak(eachWorkClaim) then
			local workId = eachWorkClaim.mainsnak.datavalue.value.id
			table.insert(ret, computeLinkToItem(workId, true, nil, function() return p.findTitleOfWork(workId) end))
		end
	end
	return ret
end

p.getTitleOfWorkFromPropertyWithSeparator = function(frame)
	local args = getArgs(frame)
	local sep = args[1]
	local propertyId = args[2]
	local entityId = args[3]
	local limitStr = args['limit']
	local limit = tonumber(limitStr or '10')
	local retListRaw = p.findTitlesOfWorksFromProperty(propertyId, entityId, limit)
	local retList = {}
	for _,eachRetVal in ipairs(retListRaw) do
		table.insert(retList, "''" .. eachRetVal .. "''")
	end
	return table.concat(retList, sep)
end

p.loadOneValueInChain = function(chain)
	local crtChainElementId = mw.wikibase.getEntityIdForCurrentPage()
	local crtChainClaim = nil
	local crtChainSnak = nil
	local coordComponent = nil
	local raw = false
	local label = false
	for _,eachChainRing in ipairs(chain) do
		if mw.ustring.match(eachChainRing, 'Q%d+') == eachChainRing then
			crtChainElementId = eachChainRing
		elseif mw.ustring.match(eachChainRing, '_P%d+') and crtChainSnak then
			local qualPropertyId = mw.ustring.sub(eachChainRing, 2, mw.ustring.len(eachChainRing))
			if crtChainClaim.qualifiers and crtChainClaim.qualifiers[qualPropertyId] and #(crtChainClaim.qualifiers[qualPropertyId]) > 0 then
				local qualIdx = 1
				local propertyQuals = crtChainClaim.qualifiers[qualPropertyId]
				while qualIdx <= #propertyQuals and not isValueSnak(propertyQuals[qualIdx]) do
					qualIdx = qualIdx + 1
				end
				if qualIdx <= #propertyQuals and isValueSnak(propertyQuals[qualIdx]) then
					local firstValueSnakIdx = qualIdx
					if propertyQuals[qualIdx].datavalue.type == 'monolingualtext' then
						while qualIdx <= #propertyQuals and (not isValueSnak(propertyQuals[qualIdx]) or propertyQuals[qualIdx].datavalue.value.language ~= 'ro') do
							qualIdx = qualIdx + 1
						end
					end
					crtChainSnak = qualIdx <= #propertyQuals and isValueSnak(propertyQuals[qualIdx]) and propertyQuals[qualIdx] or propertyQuals[firstValueSnakIdx]
				else 
					return nil
				end
			else 
				return nil
			end
		elseif mw.ustring.match(eachChainRing, 'P%d+') == eachChainRing then
			if isValueSnak(crtChainSnak) and crtChainSnak.datavalue.type == 'wikibase-entityid' then
				crtChainElementId = crtChainSnak.datavalue.value.id
				crtChainClaim = nil
				crtChainSnak = nil
			end
			if crtChainElementId and not crtChainSnak then
				local propertyClaims = mw.wikibase.getBestStatements(crtChainElementId, eachChainRing)
				if #propertyClaims < 1 then return nil end
				local claimIdx = 1
				
				if propertyClaims[claimIdx].mainsnak.datavalue and propertyClaims[claimIdx].mainsnak.datavalue.type == 'monolingualtext' then
					while claimIdx <= #propertyClaims and (not hasValueSnak(propertyClaims[claimIdx]) or propertyClaims[claimIdx].mainsnak.datavalue.value.language ~= 'ro') do
						claimIdx = claimIdx + 1
					end
				else
					while claimIdx <= #propertyClaims and not hasValueSnak(propertyClaims[claimIdx]) do
						claimIdx = claimIdx + 1
					end
				end
				if claimIdx <= #propertyClaims and hasValueSnak(propertyClaims[claimIdx]) then
					crtChainClaim = propertyClaims[claimIdx]
					crtChainSnak = crtChainClaim.mainsnak
				else 
					return nil
				end
			end
		elseif eachChainRing == 'lat' or eachChainRing == 'long' then
			coordComponent = eachChainRing .. 'itude'
		elseif eachChainRing == 'raw' then
			raw = true
		elseif eachChainRing == 'label' then
			if crtChainSnak then crtChainElementId = crtChainSnak.datavalue.value.id end
			crtChainClaim = nil
			crtChainSnak = nil
			label = true
		end
	end
	if crtChainSnak then
		if coordComponent and crtChainSnak.datavalue.value[coordComponent] then return crtChainSnak.datavalue.value[coordComponent] end
		return raw and printRawValue(crtChainSnak) or snakToString(crtChainSnak)
	end
	if crtChainElementId then return raw and crtChainElementId or label and p.findLabel(crtChainElementId) or p.findLinkToItem(crtChainElementId) end
	return nil
end

p.getOneValueInChain = function(frame)
	local args = getArgs(frame)
	return p.loadOneValueInChain(args)
end
return p