for i2, v2 in ipairs(proptbl) do
local parttbl = v2.qualifiers and v2.qualifiers.P518
if parttbl then
-- this higher location has qualifier 'applies to part' (P518)
for i3, v3 in ipairs(parttbl) do
if v3.snaktype == "value" and v3.datavalue.value.id == prevqid then
-- it has a value equal to the previous location
prop = proptbl[i2]
break
end -- of test for matching last location
end -- of loop through values of 'applies to part'
else
-- there's no qualifier 'applies to part' (P518)
-- so check if the previous location had a P131 that matches this alternate
if qid == prevP131id then
prop = proptbl[i2]
break
end -- of test for matching previous P131
end
end -- of loop through parent locations
-- fallback to second value if match not found
prop = prop or proptbl[2]
elseif #proptbl > 0 then
prop = proptbl[1]
end
if prop then break end
end  
-- check if it's an instance of (P31) a country (Q6256) or sovereign state (Q3624078)
-- and terminate the chain if it is
local inst = mw.wikibase.getAllStatements(qid, "P31")
if #inst > 0 then
for k, v in ipairs(inst) do
local instid = v.mainsnak.datavalue and v.mainsnak.datavalue.value.id
-- stop if it's a country (or a country within the United Kingdom if skip is true)
if instid == "Q6256" or instid == "Q3624078" or (skip and instid == "Q3336843") then
prop = nil -- this will ensure this is treated as top-level location
break
end
end
end  
-- get the name of this location and update qid to point to the parent location
if prop and prop.mainsnak.datavalue then
if not skip or count == 0 then
local args = { lprefix = ":" }
out[#out+1] = linkedItem(qid, args) -- get a linked value if we can
end
qid, prevqid = prop.mainsnak.datavalue.value.id, qid
else
-- This is top-level location, so get short name except when this is the first item
-- Use full label if there's no short name or this is the first item
local prop1813 = mw.wikibase.getAllStatements(qid, "P1813")
-- if there's a short name and this isn't the only item
if prop1813[1] and (#out > 0)then
local shortname
-- short name is monolingual text, so look for match to the local language
-- choose the shortest 'short name' in that language
for k, v in pairs(prop1813) do
if v.mainsnak.datavalue.value.language == langcode then
local name = v.mainsnak.datavalue.value.text
if (not shortname) or (#name < #shortname) then
shortname = name
end
end
end
-- add the shortname if one is found, fallback to the label
-- but skip it if it's "USA"
if shortname ~= "USA" then
out[#out+1] = shortname or labelOrId(qid)
else
if skip then out[#out+1] = "US" end
end
else
-- no shortname, so just add the label
local loc = labelOrId(qid)
-- exceptions go here:
if loc == "United States of America" then
out[#out+1] = "United States"
else
out[#out+1] = loc
end
end
finished = true
end
count = count + 1
until finished or count >= 10 -- limit to 10 levels to avoid infinite loops  
-- remove the first location if not required
if not first then table.remove(out, 1) end  
-- we might have duplicate text for consecutive locations, so remove them
if #out > 2 then
local plain = {}
for i, v in ipairs(out) do
-- strip any links
plain[i] = v:gsub("^%[%[[^|]*|", ""):gsub("]]$", "")
end
local idx = 2
repeat
if plain[idx] == plain[idx-1] then
-- duplicate found
local removeidx = 0
if (plain[idx] ~= out[idx]) and (plain[idx-1] == out[idx-1]) then
-- only second one is linked, so drop the first
removeidx = idx - 1
elseif (plain[idx] == out[idx]) and (plain[idx-1] ~= out[idx-1]) then
-- only first one is linked, so drop the second
removeidx = idx
else
-- pick one
removeidx = idx - (os.time%2)
end
table.remove(out, removeidx)
table.remove(plain, removeidx)
else
idx = idx +1
end
until idx >= #out
end
return out
end  
---
-- _getsumofparts scans the property 'has part' (P527) for values matching a list.
-- The list (args.vlist) consists of a string of Qids separated by spaces or any usual punctuation.
-- If the matched values have a qualifer 'quantity' (P1114), those quantites are summed.
-- The sum is returned as a number (i.e. 0 if )
-- a table of arguments is supplied implementing the usual parameters.
---
-- Dependencies: setRanks; parseParam; parseInput; sourced; assembleoutput;
---
local _getsumofparts = function(args)
local vallist = (args.vlist or ""):upper
if vallist == "" then return end
args.reqranks = setRanks(args.rank)
local f = {}
f.args = args
local qid, props = parseInput(f, "", "P527")
if not qid then return 0 end
local onlysrc = parseParam(args.onlysourced or args.osd, true)
local sum = 0
for k1, v1 in ipairs(props) do
if (onlysrc == false or sourced(v1))
and v1.mainsnak.snaktype == "value"
and v1.mainsnak.datavalue.type == "wikibase-entityid"
and vallist:match( v1.mainsnak.datavalue.value.id )
and v1.qualifiers
then
local quals = v1.qualifiers["P1114"]
if quals then
for k2, v2 in ipairs(quals) do
sum = sum + v2.datavalue.value.amount
end
end
end
end
return sum
end  
---
---
-- Public functions
---
---
-- _getValue makes the functionality of getValue available to other modules
---
-- Dependencies: setRanks; parseInput; propertyvalueandquals; assembleoutput; parseParam; sourced;
-- labelOrId; i18n.latestdatequalifier; format_Date; makeOrdinal; roundto; decimalPrecision; decimalToDMS;
---
p._getValue = function(args)
-- parameter sets for commonly used groups of parameters
local paraset = tonumber(args.ps or args.parameterset or 0)
if paraset == 1 then
-- a common setting
args.rank = "best"
args.fetchwikidata = "ALL"
args.onlysourced = "no"
args.noicon = "true"
elseif paraset == 2 then
-- equivalent to raw
args.rank = "best"
args.fetchwikidata = "ALL"
args.onlysourced = "no"
args.noicon = "true"
args.linked = "no"
args.pd = "true"
elseif paraset == 3 then
-- third set goes here
end  
-- implement eid parameter
local eid = args.eid
if eid == "" then
return nil
elseif eid then
args.qid = eid
end  
local propertyID = mw.text.trim(args[1] or "")  
args.reqranks = setRanks(args.rank)  
-- replacetext (rt) is a string that is returned instead of any non-empty Wikidata value
-- this is useful for tracking and debugging, so we set fetchwikidata=ALL to fill the whitelist
local replacetext = mw.text.trim(args.rt or args.replacetext or "")
if replacetext ~= "" then
args.fetchwikidata = "ALL"
end  
local f = {}
f.args = args
local entityid, props = parseInput(f, f.args[2], propertyID)  
if not entityid then
return props -- either the input parameter or nothing
end  
-- qual is a string containing the property ID of the qualifier(s) to be returned
-- if qual == "ALL" then all qualifiers returned
-- if qual == "DATES" then qualifiers P580 (start time) and P582 (end time) returned
-- if nothing or an empty string is passed set it nil -> no qualifiers returned
local qualID = mw.text.trim(args.qual or ""):upper
if qualID == "" then qualID = nil end  
-- set a language object and code in the args table
args.langobj = findLang(args.lang)
args.lang = args.langobj.code  
-- table 'out' stores the return value(s):
local out = propertyvalueandquals(props, args, qualID)  
-- format the table of values and return it as a string:
return assembleoutput(out, args, entityid, propertyID)
end  
---
-- getValue is used to get the value(s) of a property
-- The property ID is passed as the first unnamed parameter and is required.
-- A locally supplied parameter may optionaly be supplied as the second unnamed parameter.
-- The function will now also return qualifiers if parameter qual is supplied
---
-- Dependencies: _getValue; setRanks; parseInput; propertyvalueandquals; assembleoutput; parseParam; sourced;
-- labelOrId; i18n.latestdatequalifier; format_Date; makeOrdinal; roundto; decimalPrecision; decimalToDMS;
---
p.getValue = function
local args= .args
if not args[1] then
args = :getParent.args
if not args[1] then return i18n.errors["No property supplied"] end
end  
return p._getValue(args)
end  
---
-- getPreferredValue is used to get a value,
-- (or a comma separated list of them if multiple values exist).