Khác biệt giữa bản sửa đổi của “Mô đun:Thông tin khu dân cư”

Bách khoa toàn thư mở Wikipedia
Nội dung được xóa Nội dung được thêm vào
Không có tóm lược sửa đổi
Xóa chuỗi thử nghiệm
Dòng 1.379: Dòng 1.379:


function p.subdivisions(frame)
function p.subdivisions(frame)
local entity = mw.wikibase.getEntityObject("Q843993")
local entity = mw.wikibase.getEntityObject()
if not entity then return nil end
if not entity then return nil end

Phiên bản lúc 07:32, ngày 19 tháng 8 năm 2015

Tài liệu mô đun[tạo]
local p = {}
local lang = mw.getContentLanguage()

local leader_fmt = {
	[=[<tr class="mergedrow">
	<th>&nbsp;-&nbsp;%s
	<td>%s %s
</tr>]=],
}

local event_fmt = {
	[=[<tr class="mergedrow">
	<th>%s
	<td>%s %s
</tr>]=],
}

local pop_fmt = {
	[=[<tr class="mergedtoprow">
	<td>'''Dân số''' %s
	<td>%s %s
</tr>]=],
	"%s %s %s",
}

local coord_fmt = {
	[=[<tr class="mergedbottomrow">
	<th colspan="2" style="text-align: center; font-size: smaller; padding-bottom: 0.7em;">Tọa độ: <span>%s</span> %s</th>
</tr>]=],
}

local map_fmt = {
	[=[<tr class="mergedrow">
        <td colspan="2" align="center">
%s
        </td>
    </tr>]=],
    "<center>%s</center>",
}

local date_fmts_by_precision = {
	[6] = function (os_time)
		local year = os.date("*t", os_time).year
		local century
		if year > 0 then
			century = math.floor((year - 1) / 1000 + 1)
		else
			century = math.ceil((year + 1) / 1000 - 1)
		end
		return mw.ustring.format("Thiên niên kỷ %i", century)
	end,
	[7] = function (os_time)
		local year = os.date("*t", os_time).year
		local century
		if year > 0 then
			century = year / 100 + 1
		else
			century = year / 100 - 1
		end
		return mw.ustring.format("Thế kỷ %i", century)
	end,
	[8] = '"Thập niên" Y',
	[9] = "Y",
	[10] = '"Tháng" n "năm" Y',
	[11] = 'j "tháng" n "năm" Y',
	[12] = 'j "tháng" n "năm" Y "lúc" G "giờ"',
	[13] = 'j "tháng" n "năm" Y "lúc" G:i',
	[14] = 'j "tháng" n "năm" Y "lúc" G:i:s',
}

function map(domain, func)
	local range = {}
	for i, item in ipairs(domain) do
		table.insert(func(item))
	end
	return range
end

function all_pass(items, test)
	for i, item in ipairs(items) do
		if not test(item) then return false end
	end
	return true
end

function any_pass(items, test)
	for i, item in ipairs(items) do
		if test(item) then return true end
	end
	return false
end

function has(items, item)
	for i, it in ipairs(items) do
		if it == item then return true end
	end
	return false
end

---Returns the maximum item in the given list, as defined by a function that
-- returns true if and only if the first parameter is less than the second.
function max(items, comp)
	local item = items[1]
	if #items > 1 then
		for i = 2, #items do
			if comp(item, items[i]) then
				item = items[i]
			end
		end
	end
	return item
end

---Creates a time object compatible with os.time() given an ISO 8601 date
-- string. See [[mw:Wikibase/DataModel#Dates and times]].
function create_time(iso_time)
	local t = {}
	t.year = string.sub(iso_time, 1, 12)
	t.month = string.sub(iso_time, 14, 15)
	t.day = string.sub(iso_time, 17, 18)
	t.hour = string.sub(iso_time, 20, 21)
	t.min = string.sub(iso_time, 23, 24)
	t.sec = string.sub(iso_time, 26, 27)
	return os.time(t)
end
--p.create_time = create_time														-- debug

---Returns whether the given qualifier is in the past.
function is_past(qualifier)
	local iso_time = qualifier and qualifier.datavalue
		and qualifier.datavalue.value and qualifier.datavalue.value.time
	return os.difftime(os.time(), create_time(iso_time)) > 0
end

---Returns whether the given qualifier is in the future.
function is_future(qualifier)
	local iso_time = qualifier and qualifier.datavalue
		and qualifier.datavalue.value and qualifier.datavalue.value.time
	return os.difftime(create_time(iso_time), os.time()) > 0
end

---Returns claims that are currently in effect or are not time-qualified.
function claim_is_current(claim)
	local start_dates = claim.qualifiers and claim.qualifiers.P580
	local end_dates = claim.qualifiers and claim.qualifiers.P582
	return (not start_dates or #start_dates < 1 or all_pass(start_dates, is_past))
		and (not end_dates or #end_dates < 1 or all_pass(end_dates, is_future))
end

function qualifier_entities(claim, prop_id)
	local qualifiers = claim.qualifiers and claim.qualifiers["P" .. prop_id]
	if not qualifiers then return nil end
	
	local qualifier_ids = {}
	for i, qualifier in ipairs(qualifiers) do
		local qualifier_id = qualifier.datavalue.value["numeric-id"]
		if qualifier_id then
			table.insert(qualifier_ids, qualifier_id)
		end
	end
	return qualifier_ids
end

function entity_link(entity_id, ucfirst)
	local title = mw.wikibase.sitelink("Q" .. entity_id)
	if ucfirst and title then title = lang:ucfirst(title) end
	local label = mw.wikibase.label("Q" .. entity_id)
	if ucfirst and label then label = lang:ucfirst(label) end
	if title then return mw.ustring.format("[[%s|%s]]", title, label or title) end
	return mw.ustring.format("[[d:Q%s|%s]]", entity_id,
		label or "Q" .. entity_id)
end

function p.leaders(frame)
	if frame.args.override and #frame.args.override > 1 then return frame.args.override end
	
	local entity = mw.wikibase.getEntityObject()
	if not entity then return nil end
	
	local leaders = entity.claims.P6
	if not leaders then return nil end
	
	local version = tonumber(frame.args.version) or #leader_fmt
	local edit_button = frame:expandTemplate{
		title = "Sửa dữ liệu",
		args = {
			p = 6,
		},
	}
	
	local rows = {}
	for i, leader in ipairs(leaders) do
		local leader_id = leader.mainsnak.datavalue.value["numeric-id"]
		if leader_id and claim_is_current(leader) then
			local leader_name = entity_link(leader_id)
			local leader_title_ids = qualifier_entities(leader, 39)
			if leader_title_ids and #leader_title_ids > 0 then
				for i, leader_title_id in ipairs(leader_title_ids) do
					local row = mw.ustring.format(leader_fmt[version],
						entity_link(leader_title_id, true), leader_name,
						edit_button)
					table.insert(rows, row)
				end
			else
				local row = mw.ustring.format(leader_fmt[version],
					"Viên chức", leader_name, edit_button)
				table.insert(rows, row)
			end
		end
	end
	return table.concat(rows, "\n")
end

---Returns the os.time() compatible object represented by the given claim.
function time_from_claim(claim)
	local iso_time = claim and claim.mainsnak.datavalue
		and claim.mainsnak.datavalue.value and claim.mainsnak.datavalue.value.time
	return create_time(iso_time)
end

function time_str_from_claim(claim)
	local os_time = time_from_claim(claim)
	local precision = claim and claim.mainsnak.datavalue
		and claim.mainsnak.datavalue.value and claim.mainsnak.datavalue.value.precision
	if not os_time and precision then return end
	
	local fmt = date_fmts_by_precision[precision]
	if not fmt then return end
	if type(fmt) == "function" then return fmt(os_time) end
	
	local fmt_date = lang:formatDate(fmt, claim.mainsnak.datavalue.value.time:sub(9))
	if os.date("*t", os_time).year < 1 then
		fmt_date = fmt_date .. " TCN"
	end
	return fmt_date
end

function p.events(frame)
	if frame.args.override and #frame.args.override > 1 then return frame.args.override end
	
	local entity = mw.wikibase.getEntityObject()
	if not entity then return nil end
	
	local events = entity.claims.P571
	if not events then return nil end
	table.sort(events, function (a, b)
		return os.difftime(time_from_claim(b), time_from_claim(a)) > 0
	end)
	
	local version = tonumber(frame.args.version) or #event_fmt
	local edit_button = frame:expandTemplate{
		title = "Sửa dữ liệu",
		args = {
			p = 571,
		},
	}
	
	local rows = {}
	for i, event in ipairs(events) do
		local event_str = time_str_from_claim(event)
		if event_str then
			local event_title_ids = qualifier_entities(event, 132)
			if event_title_ids and #event_title_ids > 0 then
				for i, event_title_id in ipairs(event_title_ids) do
					local row = mw.ustring.format(event_fmt[version],
						entity_link(event_title_id, true), event_str,
						edit_button)
					table.insert(rows, row)
				end
			else
				local row = mw.ustring.format(event_fmt[version],
					"Thành lập", event_str, edit_button)
				table.insert(rows, row)
			end
		end
	end
	return table.concat(rows, "\n")
end

---Returns an os.time() compatible object representing the time by which the
-- given claim is qualified.
function time_of_claim(claim)
	local qualifiers = claim.qualifiers and claim.qualifiers.P585
	local iso_time = qualifiers and qualifiers[1] and qualifiers[1].datavalue
		and qualifiers[1].datavalue.value and qualifiers[1].datavalue.value.time
	return (iso_time and create_time(iso_time)) or os.time()
end

function latest_population_claim()
	local entity = mw.wikibase.getEntityObject()
	if not entity then return nil end
	
	local pops = entity.claims.P1082
	if not pops then return nil end
	local latest_pop = max(pops, function (a, b)
		return os.difftime(time_of_claim(b), time_of_claim(a)) > 0
	end)
	return latest_pop
end

function number_from_claim(claim)
	return claim and claim.mainsnak.datavalue.value
		and tonumber(claim.mainsnak.datavalue.value.amount)
end

function claim_is_estimate(claim)
	local method_ids = qualifier_entities(claim, 459)
	return method_ids and has(method_ids, 791801)
end

function p.population(frame)
	if frame.args.override and #frame.args.override > 1 then return frame.args.override end
	
	local latest_pop = latest_population_claim()
	if not latest_pop then return end
	
	local pop = number_from_claim(latest_pop)
	if not pop or frame.args.plain then return pop end
	
	local version = tonumber(frame.args.version) or #pop_fmt
	local edit_button = frame:expandTemplate{
		title = "Sửa dữ liệu",
		args = {
			p = 1082,
		},
	}
	
	local os_time = time_of_claim(latest_pop)
	local is_estimate = claim_is_estimate(latest_pop)
	local fmt_date
	if os_time then
		local year = os.date("*t", os_time).year
		fmt_date = string.format("%i", year)
		if year < 1 then
			fmt_date = fmt_date:sub(2) .. " TCN"
		end
		if fmt_date then
			if is_estimate then fmt_date = "ước lượng " .. fmt_date end
			fmt_date = mw.ustring.format("(%s)", fmt_date)
		end
	end
	if is_estimate and not fmt_date then
		fmt_date = "(ước lượng)"
	end
	
	local pop_str = lang:formatNum(pop)
	if version == 2 then
		return mw.ustring.format(pop_fmt[version], pop_str, fmt_date, edit_button)
	end
	return mw.ustring.format(pop_fmt[version], fmt_date, pop_str, edit_button)
end

function p.coordinates(frame)
	if frame.args.override and #frame.args.override > 1 then return frame.args.override end
	
	local entity = mw.wikibase.getEntityObject()
	if not entity then return nil end
	
	local coords = entity.claims.P625
	if not coords or #coords < 1 then return nil end
	local coord = coords[1] and coords[1].mainsnak.datavalue
		and coords[1].mainsnak.datavalue.value
	if not coord then return nil end
	
	local version = tonumber(frame.args.version) or #pop_fmt
	local edit_button = frame:expandTemplate{
		title = "Sửa dữ liệu",
		args = {
			p = 625,
		},
	}
	
	if not frame.args.type or frame.args.type == "city" then
		local pop = number_from_claim(latest_population_claim())
		if pop then
			frame.args.type = string.format("city(%i)", pop + 1)
		else
			frame.args.type = "city"
		end
	end
	
	-- [[mw:Wikibase/DataModel#Geographic locations]], [[:en:Template:Coord#globe:G]]
	if not frame.args.globe and coord.globe then
		local globes_by_entity = {
			[2] = "earth",
			-- Maybe someday?
			[308] = "mercury", [313] = "venus", [405] = "moon", [111] = "mars",
			[7547] = "phobos", [7548] = "deimos", [596] = "ceres",
			[3030] = "vesta", [3169] = "ganymede", [3134] = "callisto",
			[3123] = "io", [3143] = "europa", [15034] = "mimas",
			[3303] = "enceladus", [15047] = "tethys", [15040] = "dione",
			[15050] = "rhea", [2565] = "titan", [15037] = "hyperion",
			[15037] = "iapetus", [17975] = "phoebe", [3352] = "miranda",
			[3343] = "ariel", [3338] = "umbriel", [3322] = "titania",
			[3332] = "oberon", [3359] = "triton", [339] = "pluto",
		}
		local globe_entity = tonumber(string.match(coord.globe, "https?://www.wikidata.org/entity/Q(%d+)"))
		frame.args.globe = globes_by_entity[globe_entity]
	end
	
	local valid_params = {"type", "scale", "dim", "region", "globe", "source"}
	local params = {}
	for i, param in ipairs(valid_params) do
		if frame.args[param] and #frame.args[param] > 0 then
			table.insert(params, param .. ":" .. frame.args[param])
		end
	end
	
	local coord_str = frame:expandTemplate{
		title = "Tọa độ",
		args = {
			coord.latitude,
			coord.longitude,
			table.concat(params, "_"),
			display = (frame.args.display and "inline,title") or "inline",
			format = (frame.args.format and #frame.args.format > 0 and frame.args.format) or "dms",
			name = frame.args.name,
			notes = frame.args.notes,
		},
	}
	
	return mw.ustring.format(coord_fmt[version], coord_str, edit_button)
end

function p.rawCoordinates(frame)
	local entity = mw.wikibase.getEntityObject()
	if not entity then return nil end
	
	local coords = entity.claims.P625
	if not coords or #coords < 1 then return nil end
	local coord = coords[1] and coords[1].mainsnak.datavalue
		and coords[1].mainsnak.datavalue.value
	if not coord then return nil end
	
	return coord[frame.args[1]]
end

function p.map(frame)
	if frame.args.override and #frame.args.override > 1 then return frame.args.override end
	
	local entity = mw.wikibase.getEntityObject()
	if not entity then return nil end
	
	local coords = entity.claims.P625
	if not coords or #coords < 1 then return nil end
	local coord = coords[1] and coords[1].mainsnak.datavalue
		and coords[1].mainsnak.datavalue.value
	if not coord then return nil end
	
	local version = tonumber(frame.args.version) or #pop_fmt
	local map_str = frame:expandTemplate{
		title = "Bản đồ định vị",
		args = {
			frame.args[1],
			label = frame.args.label,
			lat = coord.latitude,
			long = coord.longitude,
			float = frame.args.float or "none",
			caption = (frame.args.caption and
				mw.ustring.format("<center>%s</center>", frame.args.caption)),
			border = frame.args.border or "none",
			position = frame.args.position or "right",
			width = frame.args.width or 250,
		},
	}
	
	return mw.ustring.format(map_fmt[version], map_str)
end

local math_module = require( "Module:Math" )
local precision = math_module._precision
local infobox_module = require('Module:Infobox')
local image_module = require('Module:InfoboxImage')
local locationmap_module = require('Module:Location map')

local function isnotempty(s)
	return s and s:match( '^%s*(.-)%s*$' ) ~= ''
end

local function firstnonempty(s)
	for i=1,#s do
		if (s[i] and s[i]:match( '^%s*(.-)%s*$' ) ~= '') then
			return s[i]
		end
	end
	return ''
end

local function yesno(s, yes, no, ukn, blank)
	-- this function implements yesno
	local vals = {['yes'] = 1, ['y'] = 1, ['1'] = 1, ['no'] = 0, ['n'] = 0, ['0'] = 0}
	if( s and s:match( '^%s*(.-)%s*$' ) ~= '') then
		local outval = vals(s:lower())
		if( outval == nil ) then
			return ukn
		else
			return (outval == 1) and yes or no
		end
	else
		return blank
	end
end

local function rnd(num, digits)
	-- This function implements {{rnd}}
	return math_module._precision_format(tostring(num), tostring(digits))
end

local function order_of_magnitude(num)
	-- This function partially implements {{Order of magnitude}}
    if( num ) then
		num = math.abs(num)
		if( num == 0 ) then
			return 0
		else
			return math.floor( math.log10(num) )
		end
	else
		return 0
	end
end

local function page_exists( title )
    -- This function implements #ifexist
    local noError, titleObject = pcall(mw.title.new, title)
    if not noError then
        return false
    else
        if titleObject then
            return titleObject.exists
        else
            return false
        end
    end
end

local function link(pagelink, linktext, name)
    -- This function implements {{Infobox settlement/link}}
    pagelink = pagelink or ''
    linktext = linktext or ''
    name     = name or ''
    
    if( pagelink ~= '' ) then
        -- use "[[pagelink|linktext]]"
        return string.format('[[%s|%s]]', pagelink, linktext)
    else
        -- try "[[linktext of PAGENAME|linktext]]"
        pagelink = string.format('%s of %s',linktext, mw.title.getCurrentTitle().text)
        if( page_exists( pagelink ) ) then
            return string.format('[[%s|%s]]', pagelink, linktext)
        elseif( name ~= '' ) then
            -- try "[[linktext of name|linktext]]"
            pagelink = string.format('%s of %s', linktext, name)
            if( page_exists(pagelink) ) then
               return string.format('[[%s|%s]]', pagelink, linktext)
            end
        end
    end

    return linktext
end

local function columns(cell1, cell2, cell3, cell4)
    --- This function implements {{Infobox settlement/columns}} with no cell0
    local function makecell( c1 )
        if isnotempty(c1) then
			local root = mw.html.create('td')
			root:attr('align', 'center')
				:css('vertical-align', 'middle')
				:wikitext(c1)
            return tostring(root)
        end
        return ''
    end
    
    local function makerow( c1, c2 )
        local root = mw.html.create('')
        if isnotempty(c1) then
            if isnotempty(c2) then
            	root:tag('td')
					:attr('align', 'center')
					:css('vertical-align', 'middle')
					:wikitext(c1)
				root:tag('td')
					:attr('align', 'center')
					:css('vertical-align', 'middle')
					:wikitext(c2)
            else
            	root:tag('td')
					:attr('colspan', '2')
					:attr('align', 'center')
					:css('vertical-align', 'middle')
					:wikitext(c1)
            end
        elseif isnotempty(c2) then
			root:tag('td')
				:attr('colspan', '2')
				:attr('align', 'center')
				:css('vertical-align', 'middle')
				:wikitext(c2)
        end
        return tostring(root)
    end
    
    local count = 0
    count = count + (isnotempty(cell1) and 1 or 0)
    count = count + (isnotempty(cell2) and 1 or 0)
    count = count + (isnotempty(cell3) and 1 or 0)
    count = count + (isnotempty(cell4) and 1 or 0)

    if(count > 0) then
		local root = mw.html.create('table')
		root:css('width', '100%')
			:css('background', 'transparent')
		if(count > 2) then
			root:tag('tr')
					:wikitext(makerow(cell1, cell2))
			root:tag('tr')
					:wikitext(makerow(cell3, cell4))
		else
			root:tag('tr')
				:wikitext(makecell(cell1))
				:wikitext(makecell(cell2))
				:wikitext(makecell(cell3))
				:wikitext(makecell(cell4))
		end
		return tostring(root)
	else
		return ''
	end
end

local function columns2(cell0, cell1, cell2, cell3, cell4, cell5)
    -- This function implements {{Infobox settlement/columns}} with cell0
    local function makerow( c1 )
		if isnotempty(c1) then
			local root = mw.html.create('tr')
			root:tag('td')
				:attr('align', 'center')
				:css('style', 'vertical-align:middle')
				:wikitext(c1)
			return tostring(root)
		else
			return ''
		end
	end
    
	local count = 0
	count = count + (isnotempty(cell1) and 1 or 0)
	count = count + (isnotempty(cell2) and 1 or 0)
	count = count + (isnotempty(cell3) and 1 or 0)
	count = count + (isnotempty(cell4) and 1 or 0)
	count = count + (isnotempty(cell5) and 1 or 0)

	if(count > 0) then
		local root = mw.html.create('table')
		root:css('width', '100%')
			:css('background', 'transparent')
		local row = root:tag('tr')
		row
			:tag('td')
				:tag('table')
					:css('width', '100%')
					:css('background', 'transparent')
					:wikitext(makerow(cell1))
					:wikitext(makerow(cell2))
					:wikitext(makerow(cell3))
					:wikitext(makerow(cell4))
					:wikitext(makerow(cell5))
        if isnotempty(cell0) then
			row
				:tag('td')
					:attr('align', 'center')
					:css('vertical-align', 'top')
					:wikitext(cell0)
		end
		return tostring(root)
	else
		return cell0
	end
end

local function translitlangbox(transtype, transinfo)
	local args = {}
	args['child'] = 'yes'
	local count = 0
	for i=0,6 do
		if(isnotempty(transinfo[i]) and isnotempty(transtype[i])) then
			args['rowclass' .. tostring(i+1)] = isnotempty(transtype[i+1]) and 'mergedrow' or 'mergedbottomrow'
			args['label' .. tostring(i+1)] = '&nbsp;•&nbsp;' .. transtype[i]
			args['data' .. tostring(i+1)] = transinfo[i]
			count = count + 1
		end
	end
	return ( count > 0 ) and args or nil
end

local function unitpref(pref, region, unit_type)
    -- This function implements {{Infobox settlement/pref}}
    local pref_impus = { ['imperial'] = 1, ['english'] = 1, ['uk'] = 1, ['us'] = 1, 
        ['u.s.'] = 1, ['standard'] = 1, ['us customary'] = 1, ['u.s. customary'] = 1}
    local pr = (pref and pref:lower()) or ''
    local r = region or ''
    local u = unit_type or ''

    pr = mw.ustring.gsub(pr, '^%s*([a-z].*[a-z\.])%s*$','%1')

    if( pref_impus[pr] ) then
        return 'impus'
    end
    if( mw.ustring.match( r, 'United States' ) ) then
        return 'impus'
    end
    if( mw.ustring.match( r, 'United Kingdom' ) ) then
        return 'impus'
    end
    if( (u .. '_' .. pr ) == 'area_dunam' ) then
        return 'dunam'
    end
    
    return 'metric'
end

local function areadisp(frame, pref, name, mag, ha, km2, sqmi, acre, dunam, percent, link)
    -- This function implements {{Infobox settlement/areadisp}}
    local function formatnum(num)
        return frame:callParserFunction{ name = 'formatnum', args = num }
    end
    
    local metv, metu = '', ''
    local impv, impu = '', ''
    local dunv, dunu = '', ''
    local lstr1, lstr2 = '', ''
    local rndv = 0
    
    pref = pref or ''
    name = name or ''
    mag = mag or ''
    ha = ha or ''
    km2 = km2 or ''
    sqmi = sqmi or ''
    acre = acre or ''
    dunam = dunam or ''
    percent = percent or ''
    link = link or ''
    
    if ( ha ~= '' ) then
        metv = formatnum( ha )
        metu = 'ha'
    elseif ( km2 ~= '' ) then
        metv = formatnum( km2 )
        metu = 'km<sup>2</sup>'
    elseif ( dunam ~= '' ) then
        if (tonumber(dunam) < 1E3) then
            -- convert dunams to hectares
            metv = dunam/10
            metu = 'ha'
            rndv = precision(dunam)+1
            metv = rnd(metv,rndv)
        else
            -- convert dunams to square kilometers
            metv = dunam/1000
            metu = 'km<sup>2</sup>'
            rndv = precision(dunam)+3
            metv = rnd(metv,rndv)
        end
    elseif( acre ~= '' ) then 
        -- convert acres to hectares
        metv = acre*0.4046856422
        metu = 'ha'
        rndv = math.max(precision(acre),-1*order_of_magnitude(metv))
        metv = rnd(metv,rndv)
    elseif( sqmi ~= '' ) then
        -- convert sqmi to km2
        metv = sqmi*2.589988110336
        metu = 'km<sup>2</sup>'
        rndv = math.max(precision(sqmi)-1,-1*order_of_magnitude(metv))
        metv = rnd(metv,rndv)
    end

    if ( acre ~= '' ) then
        impv = formatnum( acre )
        impu = 'acre'
    elseif ( sqmi ~= '' ) then
        impv = formatnum( sqmi )
        impu = 'sq&nbsp;mi'
    elseif (ha ~= '' ) then
        -- convert hectares to acres
        impv = ha/0.4046856422
        impu = 'acre'
        rndv = precision(ha)
        impv = rnd(impv,rndv)
    elseif (km2 ~= '' ) then
        -- convert square kilometres to square miles
        impv = km2/2.589988110336
        impu = 'sq&nbsp;mi'
        rndv = math.max(precision(km2),-1*order_of_magnitude(impv))
        impv = rnd(impv,rndv)
    elseif (dunam ~= '' ) then
        if (tonumber(dunam) < 2589) then
            -- convert dunams to acres
            impv = dunam/4.046856422
            impu = 'acre'
            rndv = math.max(precision(dunam),-1*order_of_magnitude(impv))
            impv = rnd(impv,rndv)
        else
            -- convert dunams to square miles
            impv = dunam/2589.988110336
            impu = 'sq&nbsp;mi'
            rndv = math.max(precision(dunam)+3,-1*order_of_magnitude(impv))
            impv = rnd(impv,rndv)
        end
    end

    if( mw.ustring.match(pref:lower(), '^%s*dunam%s*$') and (dunam == '') ) then
        if( km2 ~= '' ) then
            -- convert square kilometres to dunams
            dunv = km2*1000
            rndv = precision(km2)-3
            dunv = rnd(dunv,rndv)
        elseif( ha ~= '' ) then
            -- convert hectares to dunams
            dunv = ha*10
            rndv = precision(ha)-1
            dunv = rnd(dunv,rndv)
        elseif( sqmi ~= '' ) then
            -- convert square miles to dunams
            dunv = sqmi*2589.988110336
            rndv = math.max(precision(sqmi)-4,-1*order_of_magnitude(dunv))
            dunv = rnd(dunv,rndv)
        elseif( acre ~= '' ) then
            -- convert acres to dunams
            dunv = acre*4.046856422
            rndv = math.max(precision(acre)-1,-1*order_of_magnitude(dunv))
            dunv = rnd(dunv,rndv)
        end
    else
        dunv = formatnum( dunam )
    end
    if( link ~= '' ) then
        dunu = '[[dunum]]'
    else
        dunu = 'dunam'
    end
    
    if( (impu == 'acre') and (tonumber(impv) ~= 1) ) then
        impu = impu .. 's'
    end    
    if( tonumber(dunv) ~= 1 ) then
        dunu = dunu .. 's'
    end
    
    if( metv ~= '' and impv ~= '' ) then
        pref = unitpref(pref, name, 'area')
        if( percent ~= '' ) then
            percent = ' &nbsp;' .. percent .. '%'
        end
        
        if( mag ~= '' ) then
            if( metu == 'ha' ) then
                lstr1 = tostring( order_of_magnitude( metv * 1E4 ) ) 
            else
                lstr1 = tostring( order_of_magnitude( metv * 1E6 ) )
            end
            lstr1 = '[[1_E+' .. lstr1 .. '_m²|'
            lstr2 = ']]'
         end
   
         if( pref == 'impus' ) then
             return string.format('%s&nbsp;%s (%s%s&nbsp;%s%s)%s', 
                 impv, impu, lstr1, metv, metu, lstr2, percent)
         elseif ( pref == 'dunam' ) then
             return string.format('%s&nbsp;%s (%s%s&nbsp;%s%s&nbsp;or&nbsp;%s&nbsp;%s)%s', 
                 dunv, dunu, lstr1, metv, metu, lstr2, impv, impu, percent)
         else
             return string.format('%s%s&nbsp;%s%s (%s&nbsp;%s)%s', 
                 lstr1, metv, metu, lstr2, impv, impu, percent)
         end
     end
end

local function densdisp(frame, pref, name, perkm2, persqmi, pop, ha, km2, sqmi, acre, dunam)
    -- This function implements {{Infobox settlement/densdisp}}
    local function numorzero( num )
        num = num or ''
        num = tonumber(frame:callParserFunction{ name = 'formatnum', args = {num, 'R'}})
        if( num == nil ) then
            return 0
        else
            return num
        end
    end

    local function formatnum(num)
        return frame:callParserFunction{ name = 'formatnum', args = num }
    end
    
    local function formatnumR(num)
        return frame:callParserFunction{ name = 'formatnum', args = {num, 'R'} }
    end

    local metv, metu = '', 'km<sup>2</sup>'
    local impv, impu = '', 'sq&nbsp;mi'
    local rndv = 0
    local perkm2num = tonumber(formatnumR(perkm2 or ''))
    local persqminum = tonumber(formatnumR(persqmi or ''))
    local popnum = tonumber(formatnumR(pop or ''))

    pref = pref or ''
    name = name or ''
    perkm2 = perkm2 or ''
    persqmi = persqmi or ''
    pop = pop or ''
    ha = numorzero(ha)
    km2 = numorzero(km2)
    acre = numorzero(acre)
    sqmi = numorzero(sqmi)
    dunam = numorzero(dunam)
    
    if( (perkm2num == nil) and (persqminum == nil) ) then
       if( mw.ustring.match(perkm2:lower(), '^%s*auto%s*$') or mw.ustring.match(persqmi:lower(), '^%s*auto%s*$') ) then
           if( popnum ~= nil ) then
               if( km2 > 0 ) then
                   metv = popnum/km2
                   rndv = 1 - order_of_magnitude(metv)
                   metv = rnd(metv,rndv)
               elseif( ha > 0 ) then
                   metv = 100*popnum/ha
                   rndv = 1 - order_of_magnitude(metv)
                   metv = rnd(metv,rndv)
               elseif( dunam > 0 ) then
                   metv = 1000*popnum/dunam
                   rndv = 1 - order_of_magnitude(metv)
                   metv = rnd(metv,rndv)
               elseif( acre > 0 ) then
                   metv = (popnum/acre)/0.004046856422
                   rndv = 1 - order_of_magnitude(metv)
                   metv = rnd(metv,rndv)
               elseif( sqmi > 0 ) then
                   metv = (popnum/sqmi)/2.589988110336
                   rndv = 1 - order_of_magnitude(metv)
                   metv = rnd(metv,rndv)
               end
               if( sqmi > 0 ) then
                   impv = popnum/sqmi
                   rndv = 1 - order_of_magnitude(impv)
                   impv = rnd(impv,rndv)
               elseif( acre > 0 ) then
                   impv = 640*popnum/acre
                     rndv = 1 - order_of_magnitude(impv)
                   impv = rnd(impv,rndv)
               elseif( km2 > 0 ) then
                   impv = 2.589988110336*popnum/km2
                   rndv = 1 - order_of_magnitude(impv)
                   impv = rnd(impv,rndv)
               elseif( ha > 0 ) then
                   impv = 258.9988110336*popnum/ha
                   rndv = 1 - order_of_magnitude(impv)
                   impv = rnd(impv,rndv)
               elseif( dunam > 0 ) then
                   impv = 2589.988110336*popnum/dunam
                   rndv = 1 - order_of_magnitude(impv)
                   impv = rnd(impv,rndv)
               end
           end
       end
   elseif( perkm2num ~= nil ) then
       if( persqminum ~= nil ) then
           metv = formatnum( perkm2 )
           impv = formatnum( persqmi )
       else
           metv = formatnum( perkm2 )
           impv = perkm2num*2.589988110336
           rndv = math.max(precision(perkm2num)-1,-1*order_of_magnitude(impv)) 
           impv = rnd(impv,rndv)
       end
    elseif( persqminum ~= nil ) then
        metv = persqminum/2.589988110336
        rndv = math.max(precision(persqminum),-1*order_of_magnitude(metv))
        metv = rnd(metv,rndv)
        impv = formatnum( persqmi )
    end

    if( metv ~= '' and impv ~= '') then
      pref = unitpref(pref, name, 'area')
      if( pref == 'impus' ) then
         return string.format('%s/%s (%s/%s)', impv, impu, metv, metu)
      else
         return string.format('%s/%s (%s/%s)', metv, metu, impv, impu)
      end
    else
      return ''
    end  
end

local function lengthdisp(frame, pref, name, km, m, mi, ft)
    -- This function implements {{Infobox settlement/lengthdisp}}
    local function formatnum(num)
        return frame:callParserFunction{ name = 'formatnum', args = num }
    end
    
    local metv, metu = '', ''
    local impv, impu = '', ''
    pref = pref or ''
    name = name or ''
    m = m or ''
    km = km or ''
    ft = ft or ''
    mi = mi or ''
    
    if ( km ~= '' ) then
        metv = formatnum( km )
        metu = 'km'
    elseif ( m ~= '' ) then
        metv = formatnum( m )
        metu = 'm'
    elseif ( mi ~= '' ) then
        metv = mi*1.609344
        metu = 'km'
        rndv = precision(mi)
        metv = rnd(metv,rndv)
    elseif ( ft ~= '' ) then
        metv = ft*0.3048
        metu = 'm'
        rndv = math.max(precision(ft),-1*order_of_magnitude(metv))
        metv = rnd(metv,rndv)
    end
    
    if ( mi ~= '' ) then
        impv = formatnum( mi )
        impu = 'mi'
    elseif ( ft ~= '' ) then
        impv = formatnum( ft )
        impu = 'ft'
    elseif ( km ~= '' ) then
        impv = km/1.609344
        impu = 'mi'
        rndv = math.max(precision(km),-1*order_of_magnitude(impv))
        impv = rnd(impv,rndv)
    elseif ( m ~= '' ) then
        impv = m/0.3048
        impu = 'ft'
        rndv = precision(m)
        impv = rnd(impv,rndv)
    end
    
    if( impv ~= '' and metv ~= '' ) then
        pref = unitpref(pref, name, 'length')
        if( pref == 'impus' ) then
           return string.format('%s&nbsp;%s (%s&nbsp;%s)', impv, impu, metv, metu)
        else
           return string.format('%s&nbsp;%s (%s&nbsp;%s)', metv, metu, impv, impu)
        end
    else
        return ''
    end    
end

function p.areadisp(frame)
    local args = frame.args
    return areadisp(frame, args['pref'], args['name'], args['mag'], 
        args['ha'], args['km2'], args['sqmi'], args['acre'], args['dunam'], args['percent'], args['link'])
end

function p.densdisp(frame)
    local args = frame.args
    return densdisp(frame, args['pref'], args['name'], 
        args['/km2'], args['/sqmi'], args['pop'], args['ha'], args['km2'], args['sqmi'], args['acre'], args['dunam'])
end

function p.lengthdisp(frame)
    local args = frame.args
    return lengthdisp(frame, args['pref'], args['name'], args['km'], args['m'], args['mi'], args['ft'])
end

function p.link(frame)
    local args = frame.args
    return link(args['link'], args['type'], args['name'])
end

function p.columns(frame)
    local args = frame.args
    if( args[0] and args[0] ~= '' ) then
      return columns2(args[0], args[1], args[2], args[3], args[4], args[5])
    else
      return columns(args[1], args[2], args[3], args[4])
    end
end

function p.infobox(frame)
    local args = {}
    local oargs = frame:getParent().args
    local pname = firstnonempty({oargs['name'], oargs['official_name'], mw.title.text})
    local narrowmap = isnotempty(oargs['pushpin_map_narrow']) and isnotempty(oargs['pushpin_map'])
    args['bodyclass'] = 'geography vcard'
    args['bodystyle'] = 'width:23em'
    args['headerstyle'] = 'text-align:left'
    args['abovestyle'] = 'font-size:1.25em; white-space:nowrap'
    -- build the names, type, and transliterations subbox
    local sargs = {}
    local scount = 0
    sargs['child'] = 'yes'
    if( (isnotempty(oargs['name']) or isnotempty(oargs['official_name']) ) and
    	(isnotempty(oargs['settlement_type']) or isnotempty(oargs['type']) ) ) then
	    sargs['subheaderstyle'] = 'background-color:#cddeff; font-weight:bold;'
    	sargs['subheader'] = '<span class="category">'
    		.. firstnonempty(oargs['settlement_type'], oargs['type']) .. '</span>'
    	scount = scount + 1
    end
    if( isnotempty(oargs['name']) and isnotempty(oargs['official_name']) ) then
    	sargs['rowclass1'] = 'mergedtoprow'
    	sargs['header1'] = oargs['official_name']
    	scount = scount + 1
    end
    if( isnotempty(oargs['translit_lang1']) ) then
    	local targs = translitlangbox(
    		{oargs['translit_lang1_type'],
    		 oargs['translit_lang1_type1'],
    		 oargs['translit_lang1_type2'],
    		 oargs['translit_lang1_type3'],
    		 oargs['translit_lang1_type4'],
    		 oargs['translit_lang1_type5'],
    		 oargs['translit_lang1_type6']},
    		{oargs['translit_lang1_info'],
    		 oargs['translit_lang1_info1'],
    		 oargs['translit_lang1_info2'],
    		 oargs['translit_lang1_info3'],
    		 oargs['translit_lang1_info4'],
    		 oargs['translit_lang1_info5'],
    		 oargs['translit_lang1_info6']})
    	if( targs ) then
    		sargs['rowclass2'] = 'mergedtoprow'
    		sargs['header2'] = oargs['translit_lang1'] .. '&nbsp;transcription(s)' .. infobox_module._infobox(targs)
	    	scount = scount + 1
    	end
    end
    if( isnotempty(oargs['translit_lang2']) ) then
    	local targs = translitlangbox(
    		{oargs['translit_lang2_type'],
    		 oargs['translit_lang2_type1'],
    		 oargs['translit_lang2_type2'],
    		 oargs['translit_lang2_type3'],
    		 oargs['translit_lang2_type4'],
    		 oargs['translit_lang2_type5'],
    		 oargs['translit_lang2_type6']},
    		{oargs['translit_lang2_info'],
    		 oargs['translit_lang2_info1'],
    		 oargs['translit_lang2_info2'],
    		 oargs['translit_lang2_info3'],
    		 oargs['translit_lang2_info4'],
    		 oargs['translit_lang2_info5'],
    		 oargs['translit_lang2_info6']})
    	if( targs ) then
    		sargs['rowclass3'] = 'mergedtoprow'
    		sargs['header3'] = oargs['translit_lang2'] .. '&nbsp;transcription(s)' .. infobox_module._infobox(targs)
	    	scount = scount + 1
    	end
	end
    -- End of names, type, and transliterations

    args['above'] =  '<span class="fn org">' .. pname .. '</span>'
    if(isnotempty(oargs['native_name'])) then
    	args['above'] = args['above'] .. '<br /><span class="nickname"'
    		.. isnotempty(oargs['native_name_lang']) and ' lang="' .. oargs['native_name_lang'] .. '">'
    		.. oargs['native_name'] .. '</span>'
    end
    if(isnotempty(oargs['other_name'])) then
    	args['above'] = args['above'] .. '<br /><span class="nickname" style="font-size:78%">'
    		.. oargs['other_name'] .. '</span>'
    end
   	if( scount > 0 ) then
	    args['above'] = args['above'] .. infobox_module._infobox(sargs)
	end
	-- Skyline image
	if( isnotempty(oargs['image_skyline']) ) then
		args['imagestyle'] = 'padding:0.7em 0.8em'
		args['image'] = image_module._InfoboxImage(
			{['image'] = oargs['image_skyline'], 
			 ['size'] = oargs['imagesize'], 
			 ['sizedefault'] = '250px', 
			 ['alt'] = oargs['image_alt'],
			 ['title'] = oargs['image_caption'] or ('Hình nền trời của ' .. pname)
			 })
		if( isnotempty(oargs['image_caption']) ) then
			args['image'] = args['image'] .. '<br /><small>' .. oargs['image_caption'] .. '</small>'
		end
	end
	-- Other image
	if( isnotempty(oargs['image']) ) then
		args['image2'] = oargs['image']
	end
	-- Primary map
	local image_map = nil
	if( isnotempty(oargs['image_map']) ) then
		local msize = narrowmap and '100px' or '250px'
		
		image_map = image_module._InfoboxImage({
			['image'] = oargs['image_map'],
			['size'] = oargs['mapsize'],
			['sizedefault'] = msize,
			['alt'] = oargs['map_alt'],
			['title'] = oargs['map_caption'] or 'Vị trí của ' .. pname,
			})
		if( isnotempty(oargs['map_caption'])) then
			image_map = image_map .. '<br /><small>' .. oargs['map_caption'] .. '</small>'
		end
	end
	-- Primary pushpin map
	local pushpin_map = nil
	if( isnotempty(oargs['pushpin_map']) and isnotempty(oargs['latd']) and isnotempty(oargs['longd'])) then
		local plabel
		if(oargs['pushpin_label_position'] and oargs['pushpin_label_position']:lower() == 'none') then
			plabel = ''
		else if( isnotempty(oargs['pushpin_label']) ) then
			plabel = oargs['pushpin_label']
		else
			plabel = pname
		end
		local pwidth = ''
		if(narrowmap) then
			pwidth = firstnonempty(oargs['pushpin_mapsize'], '150')
		end
		local lat, lat_deg, lat_min, lat_sec
		if(isnotempty(oargs['latm']) or isnotempty(oargs['latNS'])) then
			lat = ''
			lat_deg = oargs['latd'] or ''
			lat_min = oargs['latm'] or ''
			lat_sec = oargs['lats'] or ''
		else
			lat = oargs['latd'] or ''
		end
		local long, lon_deg, lon_min, lon_sec
		if(isnotempty(oargs['longm']) or isnotempty(oargs['longEW'])) then
			long = ''
			lon_deg = oargs['longd'] or ''
			lon_min = oargs['longm'] or ''
			lon_sec = oargs['longs'] or ''
		else
			long = oargs['longd'] or ''
		end
		local caption = firstnonempty({oargs['pushpin_map_caption'], oargs['map_caption']})
		pushpin_map = '<center>' .. locationmap_module._main({
			['1'] = oargs['pushpin_map'],
			['border'] = 'none',
			['alt'] = oargs['pushpin_map_alt'],
			['caption'] = '',
			['float'] = 'none',
			['width'] = pwidth,
			['default_width'] = '250',
			['relief'] = oargs['pushpin_relief'],
			['AlternativeMap'] = oargs['pushpin_image'],
			['label'] = plabel,
			['lat'] = lat, ['long'] = long,
			['lat_deg'] = lat_deg, ['lat_min'] = lat_min, ['lat_sec'] = lat_sec,
			['lat_dir'] = oargs['latNS'] or '',
			['lon_deg'] = lon_deg, ['lon_min'] = lon_min, ['lon_sec'] = lon_sec,
			['lon_dir'] = oargs['lonEW'] or '',
			['marksize'] = '6',
			['position'] = oargs['pushpin_label_position'] or ''
			})
		if( caption ) then
			pushpin_map = pushpin_map .. '<small>' .. caption .. '</small>'
		end
			pushpin_map = pushpin_map .. '</center>'
		end
	end
	-- Flag, Seal, Shield and Coat of arms
	if( isnotempty(oargs['image_flag']) or isnotempty(oargs['image_seal']) 
		or isnotempty(oargs['image_shield']) or isnotempty(oargs['image_blank_emblem'])
		or narrowmap) then
		args['rowclass1'] = 'mergedtoprow'
		args['class1'] = 'maptable'
		local isize = (isnotempty(oargs['pushpin_map_narrow']) and isnotempty(oargs['pushpin_map'])) and '85px' or '100px'
		local targs = {}
		if( isnotempty(oargs['image_flag']) ) then
			local iborder = yesno(oargs['flag_border'], 'yes', '', 'yes', 'yes')
			targs[1] = image_module._InfoboxImage({
				['image'] = oargs['image_flag'],
				['size'] = oargs['flag_size'],
				['sizedefault'] = isize,
				['border'] = iborder,
				['alt'] = oargs['flag_alt'],
				['title'] = 'Hiệu kỳ của ' .. pname,
				}) .. '<br /><small>\'\'\'' .. link(oargs['flag_link'], 'Flag', oargs['official_name']) .. '\'\'\'</small>'
		end
		if( isnotempty(oargs['image_seal']) ) then
			targs[2] = image_module._InfoboxImage({
				['image'] = oargs['image_seal'],
				['size'] = oargs['seal_size'],
				['sizedefault'] = isize,
				['alt'] = oargs['seal_alt'],
				['title'] = 'Con dấu chính thức của ' .. pname,
				}) .. '<br /><small>\'\'\'' .. link(oargs['seal_link'], firstnonempty(oargs['seal_type'], 'Seal'), oargs['official_name']) .. '\'\'\'</small>'
		end
		if( isnotempty(oargs['image_shield']) ) then
			targs[3] = image_module._InfoboxImage({
				['image'] = oargs['image_shield'],
				['size'] = oargs['shield_size'],
				['sizedefault'] = isize,
				['alt'] = oargs['shield_alt'],
				['title'] = 'Huy hiệu của ' .. pname,
				}) .. '<br /><small>\'\'\'' .. link(oargs['shield_link'], 'Coat of arms', oargs['official_name']) .. '\'\'\'</small>'
		end
		if( isnotempty(oargs['image_blank_emblem']) ) then
			targs[4] = image_module._InfoboxImage({
				['image'] = oargs['image_blank_emblem'],
				['size'] = oargs['blank_emblem_size'],
				['sizedefault'] = isize,
				['alt'] = oargs['blank_emblem_alt'],
				['title'] = 'Biểu trưng chính thức của ' .. pname,
				}) .. '<br /><small>\'\'\'' .. link(oargs['blank_emblem_link'], firstnonempty(oargs['blank_emblem_type'], 'Logo'), oargs['official_name']) .. '\'\'\'</small>'
		end
		targs[5] = image_map
		if( narrowmap and pushpin_map) then
			args['data1'] = columns2(pushpin_map, targs[1], targs[2], targs[3], targs[4], targs[5])
		else
			args['data1'] = columns(targs[1], targs[2], targs[3], targs[4])
		end
	end
	-- Nickname
	if( isnotempty(oargs['nickname']) ) then
		args['rowclass2'] = 'mergedrow'
		args['data2'] = 'Tên hiệu: <span class="nickname">' .. oargs['nickname'] .. '</span>'
	end
	-- Motto
	if( isnotempty(oargs['motto']) ) then
		args['rowclass3'] = 'mergedrow'
		args['data3'] = 'Khẩu hiệu: ' .. oargs['motto']
	end
	-- Anthem
	if( isnotempty(oargs['anthem']) ) then
		args['rowclass4'] = 'mergedrow'
		args['data4'] = 'Nhạc hiệu: ' .. oargs['anthem']
	end
	-- Map
	if( narrowmap  and image_map ) then
		args['rowclass5'] = mergedrow
		args['data5'] = image_map
	end
	if( isnotempty(oargs['image_map1']) ) then
		args['rowclass6'] = mergedrow
		args['data6'] = image_module._InfoboxImage({
			['image'] = oargs['image_map1'],
			['size'] = oargs['mapsize1'],
			['sizedefault'] = '250px',
			['alt'] = oargs['map_alt1'],
			['title'] = oargs['map_caption1'] or 'Vị trí của ' .. pname,
			})
		if( isnotempty(oargs['map_caption1'])) then
			image_map = image_map .. '<br /><small>' .. oargs['map_caption1'] .. '</small>'
		end
	end
	-- Dot map
	if( isnotempty(oargs['image_dot_map']) ) then
		args['rowclass7'] = 'mergedrow'
		args['data7'] = '<center>Bản đồ vị trí không hỗ trợ!</center>'
	end
	
    -- Pushpin map
	if( narrowmap == nil and pushpin_map) then
		args['rowclass8'] = 'mergedtoprow'
		args['data8'] = pushpin_map
	end

    return infobox_module._infobox(args)
 
end

local function _superdivisions(entity, divisions, i)
	if not divisions[i] then divisions[i] = {} end
	if divisions[i][entity.id:sub(2)] then return end
	divisions[i][entity.id:sub(2)] = true
	local claims = entity.claims.P131
	for j, claim in ipairs(claims or {}) do
		local superentity = mw.wikibase.getEntity("Q" .. claim.mainsnak.datavalue.value["numeric-id"])
		_superdivisions(superentity, divisions, i + 1)
	end
end

function p.subdivisions(frame)
	local entity = mw.wikibase.getEntityObject()
	if not entity then return nil end
	
	local edit_button = frame:expandTemplate{
		title = "Sửa dữ liệu",
		args = {
			p = 131,
		},
	}
	
	local divisions = {}
	_superdivisions(entity, divisions, 1)
	local rows = {}
	for i = #divisions, 2, -1 do
		local row = {}
		for id, _ in pairs(divisions[i]) do
			table.insert(row, entity_link(id))
		end
		table.insert(rows, "* " .. table.concat(row, ", "))
	end
	
	return frame:expandTemplate{
		title = "Liệt kê",
		args = {
			table.concat(rows, "\n"),
		},
	} .. " " .. edit_button
end
 
return p