Modul:Wîkîdane2

Belgekirina modulê
--script that retrieves basic data stored in Wikidata, for the datamodel, see https://www.mediawiki.org/wiki/Extension:Wikibase_Client/Lualocal p = {}local linguistic = require('Module:Zimanzanî')--local formatDate = require('Module:Complex date') only loaded when needed to save memory in large pages like Wikidata:List of properties/alllocal fb = require('Module:Fallback')local i18nmessages = mw.loadData('Module:i18n/wîkîdane')-- Wiki-specific parameterslocal defaultlang = mw.getCurrentFrame():preprocess("{{int:lang}}")local defaultlink = 'wikidata'local function i18n(str, lang)local message = i18nmessages[str]if type(message) == 'string' thenreturn messageendreturn fb._langSwitch(message, lang or defaultlang)endlocal function formatError( key, text )return error(i18n(key) .. (text or ''))endlocal function addTrackingCat(prop, cat)if not prop and not cat thenreturn error("ti malê pêşkêşkirin")endif not cat thencat = i18nmessages.trackingcat .. '/' .. string.upper(prop)endreturn '[[Category:' .. cat .. ']]'endlocal function removeBlanks(args)for i, j in pairs(args) do -- does not work ??if (j == '') or (j == '-') then args[i] = nil endendreturn argsendlocal function formatTheUnknown() -- voir si on peut accorder/adapter l'usage de "inconnu"return i18n('somevalue')endlocal function isSpecial(snak)return snak.snaktype ~= 'value'endlocal function sameValue(snak, target)return not isSpecial(snak) and p.getRawvalue(snak) == targetendlocal function showLang(statement, str) -- TODO (not yet in proper format)--adds a lang indication at the start of the string, based on data in statementlocal mainsnak = statement.mainsnakif isSpecial(mainsnak) thenreturn strendlocal langlist = {}if mainsnak.datavalue.type == 'monolingualtext' thenlanglist = {mainsnak.datavalue.value.language}elseif statement.qualifiers and statement.qualifiers.P407 thenlocal convertlangcode = mw.loadData('Module:Ferheng/kodên ziman')for i, j in pairs( statement.qualifiers.P407 ) doif not isSpecial(j) thenlocal val = convertlangcode[j.datavalue.value['numeric-id']]table.insert(langlist, val)endendendif #langlist == 0 thenreturn strelsereturn '('.. table.concat(langlist) .. ')' .. strendendfunction p.getEntity( val )if type(val) == 'table' thenreturn valendreturn mw.wikibase.getEntityObject(val)end-- DATE FUNCTIONSlocal function splitTimestamp(timestamp, calendar)local pattern = "(%W)(%d+)%-(%d+)%-(%d+)"local era, year, month, day = timestamp:match(pattern)if calendar == 'julian' then--todo  year, month, day = formatdate.gregorianToJulian( era .. year, month, day )endreturn {day = day, month = month, year = year, era = era, timestamp = timestamp, type = 'dateobject'}endlocal function rangeObject(begin, ending)local timestampif begin thentimestamp = begin.timestampelseif ending thentimestamp = ending.timestampendreturn {begin = begin, ending = ending, timestamp = timestamp, type = 'rangeobject'}endlocal function dateObject(orig, params) -- transforme un snak en un nouvel objet utilisable par Module:Date complexeif not params thenparams = {}endlocal newobj = splitTimestamp(orig.time, orig.calendar) -- initalise l'object en mettant la valeur des datesnewobj.precision = params.precision or orig.precisionnewobj.type = 'dateobject'return newobjendlocal function formatDatepoint(obj, params) -- TO IMPROVEif not obj thenreturn nilendlocal formatDate = require('Module:Complex date')local lang = params.lang or defaultlanglocal precision = math.min(obj.precision, params.precision or 15) -- if we don't want to show the value to its full detailif precision >= 11 thenreturn formatDate.complex_date{args={date1 = obj.year .. '-' .. obj.month .. '-' .. obj.day, lang= lang}}elseif precision == 10 thenreturn formatDate.complex_date{args={date1 = obj.year .. '-' .. obj.month, lang= lang}}elseif precision == 9 thenreturn formatDate.complex_date{args={date1 = tostring(obj.year), lang= lang}}elseif precision == 8 thenreturn formatDate.complex_date{args={date1 = string.sub(tostring(obj.year), 1, 3) .. '0', lang = lang, precision = 'decade'}}elseif precision == 7 thenreturn formatDate.complex_date{args={date1 = string.sub(tostring(obj.year + 100), 1, 2), lang = lang, precision = 'century'}}endreturn nilendlocal function formatDaterange(obj, params) --TODOlocal begin = formatDatepoint(obj.begin, params) or ''local ending = formatDatepoint(obj.ending, params) or ''return begin .. '-' .. endingendlocal function objectToText(obj, params)if obj.type == 'dateobject' thenreturn formatDatepoint(obj, params)elseif obj.type == 'rangeobject' thenreturn formatDaterange(obj, params)endreturn nilendlocal function tableToText(values, params) -- takes a list of already formatted values and make them a textif not values thenreturn nilendreturn linguistic.conj(values, params.lang or defaultlang, params.conjtype)--linguistic.conj( values, params.lang, params.conjtype )endfunction p.getDate(obj)--[[returns an object containing a timestamp for easy sorting, and other datapossible types of object:dateobject{timestamp = string, year = number, month = number, day = number, calendar = string}rangeobject{timestamp = string, begin = dateobject, ending = dateobject}]]--if not obj thenreturn nilendif type(obj) == 'string' thenobj = p.getEntity(obj)end-- if obj is a statement with date, get itif obj.mainsnak and not isSpecial(obj.mainsnak) and obj.mainsnak.datatype == 'time' thenreturn dateObject(obj.mainsnak.datavalue.value.time)end-- else preload relevant datalocal qualifs = obj.qualifiers -- when obj is a statement, look in qualifierslocal claims = obj.claims -- when obj is an item, look in claimslocal pointprop = {'P585', 'P571'} -- dates corresponding to a punctual factlocal beginprop = {'P580', 'P569'} -- start date, birth date == start of a date rangelocal endingprop = {'P582', 'P570'}local function getval(prop)local valif claims and claims[prop] and not isSpecial(claims[prop][1].mainsnak) thenval = claims[prop][1].mainsnak.datavalue.valueelseif qualifs and qualifs[prop] and not isSpecial(qualifs[prop][1]) thenval = qualifs[prop][1].datavalue.valueendif val thenreturn dateObject(val)endreturn nilendfor i, prop in pairs(pointprop) dolocal val = getval(prop)if val then return val endend--if no date has not been found, look for startdate or enddatelocal begin, endingfor i, prop in pairs(beginprop) dobegin = getval(prop)if begin thenbreakendendfor i, prop in pairs(endingprop) doending = getval(prop)if ending thenbreakendendif begin or ending thenreturn rangeObject(begin, ending)endreturn nilendfunction p.getFormattedDate(statement, params)local datetable = p.getDate(statement)if not datetable thenreturn nilendreturn objectToText(datetable, params)endlocal function hasTargetValue(claim, target)if target == nil thenreturn trueendreturn sameValue(claim.mainsnak, target)endlocal function hasRank(claim, target)if target == 'valid' thenreturn hasRank(claim, 'preferred') or hasRank(claim, 'normal')elsereturn claim.rank == targetendendlocal function bestRanked(claims)if not claims thenreturn nilendlocal preferred, normal = {}, {}for i, j in pairs(claims) doif j.rank == 'preferred' thentable.insert(preferred, j)elseif j.rank == 'normal' thentable.insert(normal, j)endendif #preferred > 0 thenreturn preferredelsereturn normalendendlocal function hasQualifier(claim, qualifier, qualifiervalues)if not qualifier then -- si aucun qualificatif est demandé, ça passereturn trueendqualifier = string.upper(qualifier)if not claim.qualifiers or not claim.qualifiers[qualifier] thenreturn falseendif type(qualifiervalues) == 'string' thenqualifiervalues = mw.text.split(qualifiervalues, ',')endif (not qualifiervalues) or (qualifiervalues == {}) thenreturn true -- si aucune valeur spécifique n'est exigéeendfor i, j in pairs(claim.qualifiers[qualifier]) dofor k, l in pairs(qualifiervalues) doif p.getRawvalue(j) == l thenreturn trueendendendreturn false endlocal function hasSource(statement, source, sourceproperty)if not statement.references thenreturn falseendsourceproperty = string.upper(sourceproperty or 'P248')local sourcevalue = string.upper(source or '')for i, ref in pairs(statement.references) dofor prop, content in pairs(ref.snaks) doif prop == sourceproperty thenif sourcevalue == '' thenreturn trueelsefor j, k in pairs(content) doif p.getRawvalue(k) == source thenreturn trueendendendendendendreturn falseendlocal function hasDate(statement)if not statement.qualifiers thenreturn falseendlocal dateprops = {'P580', 'P585', 'P582'}for i, prop in pairs(dateprops) doif statement.qualifiers[prop] thenreturn trueendendreturn falseendlocal function isInLanguage(snak, lang) -- ne fonctionne que pour les monolingualtext / étendre aux autres types en utilisant les qualifiers ?return not isSpecial(snak) and snak.datavalue.type == 'monolingualtext' and snak.datavalue.value.language == langendlocal function numval(claims, numval) -- retourn les numval premières valeurs de la table claimslocal numval = tonumber(numval) or 0 -- raise a error if numval is not a positive integer ?if #claims <= numval thenreturn claimsendlocal newclaims = {}while #newclaims < numval dotable.insert(newclaims, claims[#newclaims + 1])endreturn newclaimsendfunction p.comparedate(a, b) -- returns true if a is earlier than B or if a has a date but not bif a and b thenreturn a.timestamp < b.timestampelseif a thenreturn trueendreturn falseendfunction p.chronosort(objs, inverted)table.sort(objs, function(a, b)local timeA = p.getDate(a)local timeB = p.getDate(b)if inverted thenreturn p.comparedate(timeB, timeA)elsereturn p.comparedate(timeA, timeB)endend)return objsendfunction p.sortclaims(claims, sorttype)if type(sorttype) == 'function' thentable.sort(claims, sorttype)elseif sorttype == 'chronological' thenreturn p.chronosort(claims)elseif sorttype == 'inverted' thenreturn p.chronosort(claims, true)endreturn claimsendfunction p.getRawvalue(snak)return p.getDatavalue(snak, {displayformat = 'raw'})endfunction p.showentity(entity, lang)if not entity thenreturn nilendif type(entity) == 'string' thenentity = p.getEntity(entity)endif not entity or not entity.type thenreturn formatError('entity-not-found')endlocal label = p._getLabel(entity, lang)local id = entity.idlocal link = idif entity.type == 'property' thenlink = 'Mal:' .. linkendreturn '[[' .. link .. '|' .. label .. ']] <small>(' .. id .. ')</small>'endfunction p.getDatavalue(snak, params)if isSpecial(snak) thenreturn nilendif not params thenparams = {}endlocal displayformat = params.displayformatlocal datatype = snak.datavalue.typelocal value = snak.datavalue.valueif datatype == 'wikibase-entityid' thenif type(displayformat) == 'function' thenreturn displayformat(snak, params)endlocal prefix = 'Q'if snak.datavalue.value["entity-type"] == 'property' thenprefix = 'P'endlocal id = prefix .. tostring(value['numeric-id'])if displayformat == 'raw' thenreturn idelseif displayformat == 'wikidatastyle' thenreturn p.showentity(id, params.lang)elsereturn p.formatEntity(id, params)endelseif datatype == 'string' thenlocal showntext = params.showntextif displayformat == 'weblink' thenif showntext thenreturn '[' .. value .. ' ' .. showntext .. ']'elsereturn valueendendif snak.datatype == 'math' and displayformat ~= 'raw' thenvalue = mw.getCurrentFrame():extensionTag('math', value)endif params.urlpattern thenshowntext = mw.text.nowiki(showntext or value)value = mw.ustring.gsub(value, '%%', '%%%%') -- escape '%'value = '[' .. mw.ustring.gsub(mw.ustring.gsub(params.urlpattern, '$1', value), ' ', '%%20') .. ' ' .. showntext .. ']'endreturn valueelseif datatype == 'time' then -- format example: +00000001809-02-12T00:00:00Zif displayformat == 'raw' thenreturn value.timeelsereturn objectToText(dateObject(value), params)endelseif datatype == 'globecoordinate' then-- retourne une table avec clés latitude, longitude, précision et globe à formater par un autre module (à changer ?)if displayformat == 'latitude' thenreturn value.latitudeelseif displayformat == 'longitude' thenreturn value.longitudeelseif displayformat == 'qualifier' thenlocal coord = require 'Module:Koordînat'value.globe = require('Module:Wîkîdane/Globes')[value.globe]value.precision = nilreturn coord._coord(value)elsevalue.globe = require('Module:Wîkîdane/Globes')[value.globe] -- transforme l'ID du globe en nom anglais utilisable par geohackreturn value -- note : les coordonnées Wikidata peuvent être utilisée depuis Module:Coordinates. Faut-il aussi autoriser à appeler Module:Coordiantes ici ?endelseif datatype == 'quantity' then -- todo : gérer les paramètre précisionif displayformat == 'raw' thenreturn tonumber(value.amount)elselocal formatNum = require 'Module:Formatnum'local number = formatNum.formatNum(value.amount)local unit = mw.ustring.match(value.unit, '(Q%d+)')if unit thennumber = number .. '&nbsp;' .. p.formatEntity(unit, params)endreturn numberendelseif datatype == 'monolingualtext' thenreturn '<span lang="' .. value.language .. '">' .. value.text .. '</span>'elsereturn formatError( 'unknown-datavalue-type', datatype )endendlocal function getMultipleClaims(args)local newargs = argslocal claims = {}for i, j in pairs(args.property) donewargs.property = jlocal newclaims = p.getClaims(args)if newclaims thenfor k, l in pairs(newclaims) dotable.insert(claims, l)endendendreturn claimsendfunction p.getClaims( args ) -- returns a table of the claims matching some conditions given in argsargs = removeBlanks(args)if not args.property thenreturn formatError( 'property-param-not-provided' )endif type(args.property) == 'table' thenreturn getMultipleClaims(args)end--Get entityif args.item then -- synonymsargs.entity = args.itemendlocal entity = args.entityif type(entity) ~= 'table' thenentity = p.getEntity(entity)endlocal property = string.upper(args.property)if not entity or not entity.claims or not entity.claims[property] thenreturn nilendif not args.rank thenargs.rank = 'baş'endlocal claims = {}-- ~= '' lorsque le paramètre est écrit mais laissé blanc dans une fonction framefor i, statement in pairs(entity.claims[property]) doif(not args.excludespecialornot (isSpecial(statement.mainsnak)))and(not args.targetvalueorhasTargetValue(statement, args.targetvalue))and(not args.qualifierorhasQualifier(statement, args.qualifier, args.qualifiervalues or args.qualifiervalue))and(not args.withsource or args.withsource == '-'orhasSource(statement, args.withsource, args.sourceproperty))and(not args.isinlanguageorisInLanguage(statement.mainsnak, args.isinlanguage))and(args.rank == 'baş' -- rank == best est traité à a finorhasRank(statement, args.rank))thentable.insert(claims, statement)endendif #claims == 0 thenreturn nilendif args.rank == 'baş' thenclaims = bestRanked(claims)endif args.sorttype thenclaims = p.sortclaims(claims, args.sorttype)endif args.numval thenreturn numval(claims, args.numval)endreturn claimsendfunction p.formatClaimList(claims, args)if not claims thenreturn nilendfor i, j in pairs(claims) doclaims[i] = p.formatStatement(j, args)endreturn claimsendfunction p.stringTable(args) -- like getClaims, but get a list of string rather than a list of snaks, for easier manipulationlocal claims = p.getClaims(args)return p.formatClaimList(claims, args)endlocal function getQualifiers(statement, qualifs, params)if not statement.qualifiers thenreturn nilendlocal vals = {}for i, j in pairs(qualifs) doj = string.upper(j)if statement.qualifiers[j] thenlocal inserted = falseif statement.qualifiers[j][1].datatype == 'monolingualtext' thenlocal in_preferred_langfor _, language in pairs(fb.fblist(params.lang or defaultlang)) dofor _, snak in pairs(statement.qualifiers[j]) doif isInLanguage(snak, language) thenin_preferred_lang = snakbreakendendif in_preferred_lang thenbreakendendif in_preferred_lang thentable.insert(vals, in_preferred_lang)inserted = trueendendif not inserted thenfor _, snak in pairs(statement.qualifiers[j]) dotable.insert(vals, snak)endendendendif #vals == 0 thenreturn nilendreturn valsendfunction p.getFormattedQualifiers(statement, qualifs, params)if not params then params = {} endlocal qualiftable = getQualifiers(statement, qualifs, params)if not qualiftable thenreturn nilendfor i, j in pairs(qualiftable) dolocal params = paramsif j.datatype == 'globe-coordinate' thenparams.displayformat = 'qualifier'endqualiftable[i] = p.formatSnak(j, params)endreturn linguistic.conj(qualiftable, params.lang or defaultlang)endfunction p.formatStatement( statement, args )if not statement.type or statement.type ~= 'statement' thenreturn formatError( 'unknown-claim-type', statement.type )endif not args then args = {} endlocal lang = args.lang or defaultlanglocal str = p.formatSnak( statement.mainsnak, args )if args.showlang == true thenstr = showLang(statement, str)endlocal qualifs = args.showqualifiersif qualifs thenif type(qualifs) == 'string' thenqualifs = mw.text.split(qualifs, ',')endlocal foundvalues = p.getFormattedQualifiers(statement, qualifs, args)if foundvalues thenif args.delimiter thenstr = str .. args.delimiter .. foundvalueselsestr = str .. linguistic.inparentheses(foundvalues, lang)endendendif args.showdate then -- when "showdate and p.chronosort are both set, date retrieval is performed twicelocal timedata = p.getDate(statement)if timedata thenlocal formatteddate = objectToText(timedata, args)formatteddate = linguistic.inparentheses(formatteddate, lang)str = str .. '<small>' .. formatteddate ..'</small>'endendif args.showsource and statement.references thenlocal cite = require 'Module:Cite'local frame = mw.getCurrentFrame()local sourcestring = ''for i, ref in pairs(statement.references) doif ref.snaks.P248 thenfor j, source in pairs(ref.snaks.P248) doif not isSpecial(source) thenlocal pageif ref.snaks.P304 and not isSpecial(ref.snaks.P304[1]) thenpage = ref.snaks.P304[1].datavalue.valueendlocal s = cite.citeitem('Q' .. source.datavalue.value['numeric-id'], lang, page)s = frame:extensionTag( 'ref', s )sourcestring = sourcestring .. sendendelseif ref.snaks.P854 and not isSpecial(ref.snaks.P854[1]) thens = frame:extensionTag( 'ref', p.getDatavalue(ref.snaks.P854[1]) )sourcestring = sourcestring .. sendendstr = str .. sourcestringendreturn strendfunction p.formatSnak(snak, params)--local params = params or {} pour faciliter l'appel depuis d'autres modulesif snak.snaktype == 'tigiranî' thenreturn p.getDatavalue(snak, params)elseif snak.snaktype == 'çendgiranî' thenreturn formatTheUnknown()elseif snak.snaktype == 'tigiranî' thenreturn i18n('tigiranî') --todoelsereturn formatError( 'unknown-snak-type', snak.snaktype )endendlocal function defaultLabel(entity, lang, displayformat) -- label when no label is availableif entity and displayformat == 'id' thenreturn entity.idendreturn i18n('ti-etîket', lang)endfunction p._getLabel(entity, lang, default)if not entity thenreturn nilendif type(entity) ~= 'table' thenentity = p.getEntity(entity)endif entity and entity.labels thenfor i, lg in pairs(fb.fblist(lang or defaultlang)) doif entity.labels[lg] thenreturn entity.labels[lg].valueendendendreturn defaultLabel(entity, lang, default)endfunction p._getDescription(entity, lang)if not entity thenreturn i18n('ti danasîn')endif type(entity) ~= 'table' thenentity = p.getEntity(entity)endlocal descriptions = entity.descriptionsif not descriptions thenreturn i18n('ti danasîn')endif descriptions[lang] thenreturn descriptions[lang].valueendlocal langlist = fb.fblist(lang or defaultlang) -- list of fallback languages if no label in the desired languagefor i, lg in pairs(langlist) doif descriptions[lg] thenreturn descriptions[lg].valueendendreturn i18n('ti danasîn')endlocal function wikipediaLink(entity, lang)local link = entity:getSitelink(lang .. 'wiki')if link thenreturn ':' .. lang .. ':' .. linkendreturn nilendlocal function getLink(entity, typelink, lang)if not typelink or typelink == '-' thenreturn nilendif not lang thenlang = defaultlangendif typelink == 'wikidata' thenif entity.type == 'mal' thenreturn 'd:P:' .. entity.idelsereturn 'd:' .. entity.idendelseif typelink == 'wikipedia' thenreturn wikipediaLink(entity, lang)elseif typelink == 'anywikipedia' thenlocal fallbacklist = fb.fblist(lang)for i, lg in pairs(fallbacklist) dolink = wikipediaLink(entity, lg)if link then return link endendendreturn nilendlocal function formattedLabel(label, entity, args)if not args then args = {} endlocal link = getLink(entity, args.link, args.lang)if not link thenlink = getLink(entity, defaultlink, args.lang)endif not link thenreturn labelelsereturn '[[' .. link .. '|' .. label .. ']]'endendfunction p.getmainid(claim)if claim and not isSpecial(claim.mainsnak) thenreturn 'Q' .. claim.mainsnak.datavalue.value['numeric-id']endreturn nilendfunction p.formatEntity( entity, args )if not entity thenreturn nilendif not args then args = {} endif type(entity) == 'string' thenentity = p.getEntity(entity)endlocal label = p._getLabel(entity, args.lang)if not label thenlabel = entity.idendreturn formattedLabel(label, entity, args)endfunction p.getLabel(frame) -- simple for simple templates like {{Q|}}}local args = frame.argslocal entity = args.entitylocal lang = args.langif lang == '' thenlang = defaultlangendif string.sub(entity, 1, 10) == 'Mal:P' thenentity = string.sub(entity, 10)elseif (string.sub(entity, 1, 1) ~= 'P' and string.sub(entity, 1, 1) ~= 'Q') or (not tonumber(string.sub(entity, 2))) thenreturn i18n('invalid-id')endif not args.link or args.link == '' then -- by default: no linkargs.link = '-'endif args.link == '-' thenreturn p._getLabel(entity, lang) or i18n('invalid-id')elsereturn p.formatEntity(entity, args)endendfunction p._formatStatements( args )--Format statements and concat them cleanlyif args.value == '-' thenreturn nilend--If a value is already set, use itif args.value and args.value ~= '' thenreturn args.valueendlocal valuetable = p.stringTable(args)return tableToText(valuetable, args)endfunction p.showQualifier( args )local qualifs = args.qualifiers or args.qualifierif type(qualifs) == 'string' thenqualifs = mw.text.split(qualifs, ',')endif not qualifs thenreturn formatError( 'property-param-not-provided' )endlocal claims = p.getClaims(args)if not claims thenreturn nilendlocal str = ''for i, j in pairs(claims) dolocal new = p.getFormattedQualifiers(j, qualifs, args) or ''str = str .. newendreturn strendfunction p._formatAndCat(args)local val = p._formatStatements(args)if val thenreturn val .. addTrackingCat(args.property)endreturn nilendfunction p.getTheDate(args)local claims = p.getClaims(args)if not claims thenreturn nilendlocal formattedvalues = {}for i, j in pairs(claims) dotable.insert(formattedvalues, p.getFormattedDate(j))endlocal val = linguistic.conj(formattedvalues)if val and args.addcat == true thenreturn val .. addTrackingCat(args.property)elsereturn valendend---FONCTIONS depuis le FRAMEfunction p.getaDate(frame)return p.getTheDate(frame.args)endfunction p.getQualifier(frame)return p.showQualifier(frame.args)endfunction p.getDescription(frame) -- simple for simple templates like {{Q|}}}local entity = frame.args.entitylocal lang = frame.args.langreturn p._getDescription(entity, lang) or i18n('invalid-id')endfunction p.formatStatements( args )return p._formatStatements( args )endfunction p.formatStatementsE(frame)local args = {}if frame == mw.getCurrentFrame() thenargs = frame:getParent().args -- paramètres du modèle appelant (est-ce vraiment une bonne idée ?)for k, v in pairs(frame.args) doargs[k] = vendelseargs = frameendreturn p._formatStatements( args )endfunction p.formatAndCat(frame)local args = {}if frame == mw.getCurrentFrame() thenargs = frame:getParent().args -- paramètres du modèle appelant (est-ce vraiment une bonne idée ?)for k, v in pairs(frame.args) doargs[k] = vendelseargs = frameendreturn p._formatAndCat( args )endfunction p.getEntityFromId(id)return p.getEntity(id)endreturn p