Jump to content

Module:Election results-STV

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Gonnym (talk | contribs) at 07:09, 24 July 2024 (There is a large amount of code duplication written in this module which makes it more complicated to debug. Consider using for loops and smaller functions to reduce the size of the code). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
require('strict')
local p = {}
local political_party = require('Module:Political party')

function p.main(frame)
	local args = require('Module:Arguments').getArgs(frame)
	local index, headings, showtotal = {}, {}, {}
	local cols, rounds = 0, 1
	local valid = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
	local invalidblank = {tonumber(args.invalidblank) or 0,}
	local invalid = {tonumber(args.invalid) or 0}
	local blank = {tonumber(args.blank) or 0}
	local totalvotes = {tonumber(args.totalvotes)}
	local electorate = {tonumber(args.electorate)}
	local turnout = {tonumber(args.turnout)}
	local row, secondrow
	local tracking = ''
	local max_rows = 0

	-- helper functions
	local lang = mw.getContentLanguage()
	local function fmt(n)
		return n and tonumber(n) and lang:formatNum(tonumber(n)) or nil
	end
	local function pct(n, d)
		n, d = tonumber(n), tonumber(d)
		if n and d and d > 0 then
			return string.format('%.2f', n / d * 100)
		end
		return '–'
	end
	local function tonumdash(s)
		if s then
			s = mw.ustring.gsub(s, '&[MmNn][Dd][Aa][Ss][Hh];', '-')
			s = mw.ustring.gsub(s, '&[Mm][Ii][Nn][Uu][Ss];', '-')
			s = mw.ustring.gsub(s, '[—–−]', '-')
			return tonumber(s) or 0
		end
	end
	local function unlink(s)
		if s then
			s = s:match("^[^%[]-%[%[([^%]]-)|[^%]]-%]%].*$") or s
			s = s:match("^[^%[]-%[%[([^%]]-)%]%].*$") or s
		end
		return s
	end
	local function get_color(color, party)
		if color == nil then
			local party = unlink(party) or ''
			if party ~= '' then
				color = political_party._fetch({party, 'color'})
			end
		end

		if color ~= nil then
			color = mw.ustring.gsub(color, '&(#)35;', '%1')
		end
		return color
	end

	-- preprocess the input
	local stop_flag = false
	local i = 0
	local has_votes = args['votes' .. i]
	local has_votes2 = args['votes' .. i .. '_2']
	local has_votes3 = args['votes' .. i .. '_3']
	local has_votes4 = args['votes' .. i .. '_4']
	local has_votes5 = args['votes' .. i .. '_5']
	local has_votes6 = args['votes' .. i .. '_6']
	local has_votes7 = args['votes' .. i .. '_7']
	local has_votes8 = args['votes' .. i .. '_8']
	local has_votes9 = args['votes' .. i .. '_9']
	local has_votes10 = args['votes' .. i .. '_10']
	local has_votes11 = args['votes' .. i .. '_11']
	local has_votes12 = args['votes' .. i .. '_12']
	local has_votes13 = args['votes' .. i .. '_13']
	local has_party = args['party' .. i]
	local has_nopercentage = args['nopercentage']
	while stop_flag == false do
		stop_flag = true
		for kk = 1, 20 do
			i = i + 1
			for k, key in ipairs({'cand', 'party', 'ivotes', 'ipct', 'totalvotes', 'acolor', 'rcolor'}) do
				if args[key .. i] then
					headings[key] = true
					stop_flag = false
					max_rows = i > max_rows and i or max_rows
				end
			end
			if args['row' .. i] then
				stop_flag = false
				max_rows = i > max_rows and i or max_rows
			end
			if args['row' .. i] or args['cand' .. i] or args['header' .. i] then
				table.insert(index, i)
				if args['votes' .. i] then
					if tonumber(args['votes' .. i]) then showtotal.votes = 1 end
					local votesi = tonumber(args['votes' .. i]) or 0
					args['votes' .. i] = votesi
					valid[1] = valid[1] + votesi
					has_votes = true
				end
				if args['party' .. i] then
					has_party = true
				end
				
				--[[Do something like this to reduce code duplication below
				local has_votes = {}
				for j = 2, 13 do
				    if args['votes' .. i .. "_" .. j] then
						has_votes[j] = true
					end
				end]]--
				if args['votes' .. i .. '_2'] then
					has_votes2 = true
				end
				if args['votes' .. i .. '_3'] then
					has_votes3 = true
				end
				if args['votes' .. i .. '_4'] then
					has_votes4 = true
				end
				if args['votes' .. i .. '_5'] then
					has_votes5 = true
				end
				if args['votes' .. i .. '_6'] then
					has_votes6 = true
				end
				if args['votes' .. i .. '_7'] then
					has_votes7 = true
				end
				if args['votes' .. i .. '_8'] then
					has_votes8 = true
				end
				if args['votes' .. i .. '_9'] then
					has_votes9 = true
				end
				if args['votes' .. i .. '_10'] then
					has_votes10 = true
				end
				if args['votes' .. i .. '_11'] then
					has_votes11 = true
				end
				if args['votes' .. i .. '_12'] then
					has_votes12 = true
				end
				if args['votes' .. i .. '_13'] then
					has_votes13 = true
				end
				if args['nopercentage'] then
					has_nopercentage = true
				end
				if args['votes' .. i .. '_2'] then
					if tonumber(args['votes' .. i .. '_2']) then showtotal.votes_2 = 1 end
					local votesi = tonumber(args['votes' .. i .. '_2']) or 0
					args['votes' .. i .. '_2'] = votesi
					valid[2] = valid[2] + votesi
				end
				if args['votes' .. i .. '_3'] then
					if tonumber(args['votes' .. i .. '_3']) then showtotal.votes_3 = 1 end
					local votesi = tonumber(args['votes' .. i .. '_3']) or 0
					args['votes' .. i .. '_3'] = votesi
					valid[3] = valid[3] + votesi
				end
				if args['votes' .. i .. '_4'] then
					if tonumber(args['votes' .. i .. '_4']) then showtotal.votes_4 = 1 end
					local votesi = tonumber(args['votes' .. i .. '_4']) or 0
					args['votes' .. i .. '_4'] = votesi
					valid[4] = valid[4] + votesi
				end
				if args['votes' .. i .. '_5'] then
					if tonumber(args['votes' .. i .. '_5']) then showtotal.votes_5 = 1 end
					local votesi = tonumber(args['votes' .. i .. '_5']) or 0
					args['votes' .. i .. '_5'] = votesi
					valid[5] = valid[5] + votesi
				end
				if args['votes' .. i .. '_6'] then
					if tonumber(args['votes' .. i .. '_6']) then showtotal.votes_6 = 1 end
					local votesi = tonumber(args['votes' .. i .. '_6']) or 0
					args['votes' .. i .. '_6'] = votesi
					valid[6] = valid[6] + votesi
				end
				if args['votes' .. i .. '_7'] then
					if tonumber(args['votes' .. i .. '_7']) then showtotal.votes_7 = 1 end
					local votesi = tonumber(args['votes' .. i .. '_7']) or 0
					args['votes' .. i .. '_7'] = votesi
					valid[7] = valid[7] + votesi
				end
				if args['votes' .. i .. '_8'] then
					if tonumber(args['votes' .. i .. '_8']) then showtotal.votes_8 = 1 end
					local votesi = tonumber(args['votes' .. i .. '_8']) or 0
					args['votes' .. i .. '_8'] = votesi
					valid[8] = valid[8] + votesi
				end
				if args['votes' .. i .. '_9'] then
					if tonumber(args['votes' .. i .. '_9']) then showtotal.votes_9 = 1 end
					local votesi = tonumber(args['votes' .. i .. '_9']) or 0
					args['votes' .. i .. '_9'] = votesi
					valid[9] = valid[9] + votesi
				end
				if args['votes' .. i .. '_10'] then
					if tonumber(args['votes' .. i .. '_10']) then showtotal.votes_10 = 1 end
					local votesi = tonumber(args['votes' .. i .. '_10']) or 0
					args['votes' .. i .. '_10'] = votesi
					valid[10] = valid[10] + votesi
				end
				if args['votes' .. i .. '_11'] then
					if tonumber(args['votes' .. i .. '_11']) then showtotal.votes_11 = 1 end
					local votesi = tonumber(args['votes' .. i .. '_11']) or 0
					args['votes' .. i .. '_11'] = votesi
					valid[11] = valid[11] + votesi
				end
				if args['votes' .. i .. '_12'] then
					if tonumber(args['votes' .. i .. '_12']) then showtotal.votes_12 = 1 end
					local votesi = tonumber(args['votes' .. i .. '_12']) or 0
					args['votes' .. i .. '_12'] = votesi
					valid[12] = valid[12] + votesi
				end
				if args['votes' .. i .. '_13'] then
					if tonumber(args['votes' .. i .. '_13']) then showtotal.votes_13 = 1 end
					local votesi = tonumber(args['votes' .. i .. '_13']) or 0
					args['votes' .. i .. '_13'] = votesi
					valid[13] = valid[13] + votesi
				end
			end
		end
	end

	local ovalid = {valid[1], valid[2], valid[3], valid[4], valid[5], valid[6], valid[7], valid[8], valid[9], valid[10], valid[11], valid[12], valid[13]}
	if has_votes or args['valid'] then
		max_rows = max_rows + 1
		local i = max_rows
		table.insert(index, i)
		args['row' .. i] = 'Total'
		args['votes' .. i] = showtotal.votes and valid[1] or nil
		args['votes' .. i .. '_2'] = showtotal.votes_2 and valid[2] or nil
		args['votes' .. i .. '_3'] = showtotal.votes_3 and valid[3] or nil
		args['votes' .. i .. '_4'] = showtotal.votes_4 and valid[4] or nil
		args['votes' .. i .. '_5'] = showtotal.votes_5 and valid[5] or nil
		args['votes' .. i .. '_6'] = showtotal.votes_6 and valid[6] or nil
		args['votes' .. i .. '_7'] = showtotal.votes_7 and valid[7] or nil
		args['votes' .. i .. '_8'] = showtotal.votes_8 and valid[8] or nil
		args['votes' .. i .. '_9'] = showtotal.votes_9 and valid[9] or nil
		args['votes' .. i .. '_10'] = showtotal.votes_10 and valid[10] or nil
		args['votes' .. i .. '_11'] = showtotal.votes_11 and valid[11] or nil
		args['votes' .. i .. '_12'] = showtotal.votes_12 and valid[12] or nil
		args['votes' .. i .. '_13'] = showtotal.votes_13 and valid[13] or nil
		args['colour' .. i] = 'inherit'
		args['color' .. i] = 'inherit'
		args['font-weight' .. i] = 'bold'
		args['class' .. i] = 'sortbottom'
		ovalid[1] = tonumber(args['valid']) or valid[1]
		ovalid[2] = tonumber(args['valid2']) or valid[2]
		ovalid[3] = tonumber(args['valid3']) or valid[3]
		ovalid[4] = tonumber(args['valid4']) or valid[4]
		ovalid[5] = tonumber(args['valid5']) or valid[5]
		ovalid[6] = tonumber(args['valid6']) or valid[6]
		ovalid[7] = tonumber(args['valid7']) or valid[7]
		ovalid[8] = tonumber(args['valid8']) or valid[8]
		ovalid[9] = tonumber(args['valid9']) or valid[9]
		ovalid[10] = tonumber(args['valid10']) or valid[10]
		ovalid[11] = tonumber(args['valid11']) or valid[11]
		ovalid[12] = tonumber(args['valid12']) or valid[12]
		ovalid[13] = tonumber(args['valid3']) or valid[13]
	end

	-- build the table
	local root = mw.html.create(args['embed'] and '' or 'table')
	if args['embed'] == nil then
		root
			:addClass('wikitable sortable')
			:tag('caption')
				:wikitext(args.caption)
				:done()
	end

	local topcell = nil
	if args['image'] then
		topcell = root
			:tag('th')
				:css('text-align', 'center')
				:css('background', '#F8F9FA')
				:wikitext(args['image'])
	end
	if args['reporting'] then
		if (topcell == nil) then
			topcell = root
				:tag('td')
					:css('text-align', 'center')
					:css('background', '#F8F9FA')
		end
		topcell:tag('div')
				:addClass('center')
				:wikitext(frame:expandTemplate{
					title = 'percentage bar',
					args = {args.reporting, 
						args.reporting .. '% reporting',
						['width'] = '200px',
						['hex'] = '1BCE0E'
						}})
	end

	row = args['embed'] and mw.html.create('') or root:tag('tr')
	if not has_party then
		row
			:tag('th')
				:wikitext('Candidate' or args.candtitle)
				:attr('scope', 'col')
				:attr('rowspan', 2)
				:done()
		cols = cols + 1
	else
		row
			:tag('th')
				:wikitext('Candidate' or args.candtitle)
				:attr('scope', 'col')
				:attr('rowspan', 2)
				:attr('colspan', 2)
				:done()
		cols = cols + 2
	end
	if has_party then
		row
			:tag('th')
			:wikitext('Party' or args.partytitle)
			:attr('rowspan', 2)
			:attr('scope', 'col')
			:done()
		cols = cols + 1
	end
		secondrow = args['embed'] and mw.html.create('') or root:tag('tr')
		if not has_nopercentage then
		row
			:tag('th')
			:wikitext('First count')
			:attr('colspan', 2)
			
		--[[consider using a smaller function which accepts a text to handle this
		local function create_row(row, text)
			row
				:tag('th')
				:wikitext(text)
				:attr('colspan', 2)
			return row
		end
		]]
		if has_votes2 then
			row
				:tag('th')
				:wikitext('Second count')
				:attr('colspan', 2)
		end
		if has_votes3 then
			row
				:tag('th')
				:wikitext('Third count')
				:attr('colspan', 2)
		end
		if has_votes4 then
			row
				:tag('th')
				:wikitext('Fourth count')
				:attr('colspan', 2)
		end
		if has_votes5 then
			row
				:tag('th')
				:wikitext('Fifth count')
				:attr('colspan', 2)
		end
		if has_votes6 then
			row
				:tag('th')
				:wikitext('Sixth count')
				:attr('colspan', 2)
		end
		if has_votes7 then
			row
				:tag('th')
				:wikitext('Seventh count')
				:attr('colspan', 2)
		end
		if has_votes8 then
			row
				:tag('th')
				:wikitext('Eighth count')
				:attr('colspan', 2)
		end
		if has_votes9 then
			row
				:tag('th')
				:wikitext('Ninth count')
				:attr('colspan', 2)
		end
		if has_votes10 then
			row
				:tag('th')
				:wikitext('Tenth count')
				:attr('colspan', 2)
		end
		if has_votes11 then
			row
				:tag('th')
				:wikitext('Eleventh count')
				:attr('colspan', 2)
		end
		if has_votes12 then
			row
				:tag('th')
				:wikitext('Twelfth count')
				:attr('colspan', 2)
		end
		if has_votes13 then
			row
				:tag('th')
				:wikitext('Thirteenth count')
				:attr('colspan', 2)
		end
		elseif has_nopercentage then
		row
			:tag('th')
				:wikitext('First<br>preferences')
				:attr('colspan', 2)
				:attr('rowspan', 2)
		cols = cols + 2
		if has_votes2 then
			row
				:tag('th')
				:wikitext('Subsequent counts')
				:attr('colspan', 15)
		end
		end
		if not has_nopercentage then
		secondrow
			:tag('th')
				:wikitext('Votes')
				:attr('scope', 'col')
				:done()
			:tag('th')
				:wikitext('%')
				:attr('scope', 'col')
				:done()
			cols = cols + 2
		if has_votes2 then
		secondrow
				:tag('th')
					:wikitext('Votes')
					:attr('scope', 'col')
					:done()
				:tag('th')
					:wikitext('%')
					:attr('scope', 'col')
					:done()
			cols = cols + 2
		end
		if has_votes3 then
		secondrow
				:tag('th')
					:wikitext('Votes')
					:attr('scope', 'col')
					:done()
				:tag('th')
					:wikitext('%')
					:attr('scope', 'col')
					:done()
			cols = cols + 2
		end
		if has_votes4 then
		secondrow
				:tag('th')
					:wikitext('Votes')
					:attr('scope', 'col')
					:done()
				:tag('th')
					:wikitext('%')
					:attr('scope', 'col')
					:done()
			cols = cols + 2
		end
		if has_votes5 then
		secondrow
				:tag('th')
					:wikitext('Votes')
					:attr('scope', 'col')
					:done()
				:tag('th')
					:wikitext('%')
					:attr('scope', 'col')
					:done()
			cols = cols + 2
		end
		if has_votes6 then
		secondrow
				:tag('th')
					:wikitext('Votes')
					:attr('scope', 'col')
					:done()
				:tag('th')
					:wikitext('%')
					:attr('scope', 'col')
					:done()
			cols = cols + 2
		end
		if has_votes7 then
		secondrow
				:tag('th')
					:wikitext('Votes')
					:attr('scope', 'col')
					:done()
				:tag('th')
					:wikitext('%')
					:attr('scope', 'col')
					:done()
			cols = cols + 2
		end
		if has_votes8 then
		secondrow
				:tag('th')
					:wikitext('Votes')
					:attr('scope', 'col')
					:done()
				:tag('th')
					:wikitext('%')
					:attr('scope', 'col')
					:done()
			cols = cols + 2
		end
		if has_votes9 then
		secondrow
				:tag('th')
					:wikitext('Votes')
					:attr('scope', 'col')
					:done()
				:tag('th')
					:wikitext('%')
					:attr('scope', 'col')
					:done()
			cols = cols + 2
		end
		if has_votes10 then
		secondrow
				:tag('th')
					:wikitext('Votes')
					:attr('scope', 'col')
					:done()
				:tag('th')
					:wikitext('%')
					:attr('scope', 'col')
					:done()
			cols = cols + 2
		end
		if has_votes11 then
		secondrow
				:tag('th')
					:wikitext('Votes')
					:attr('scope', 'col')
					:done()
				:tag('th')
					:wikitext('%')
					:attr('scope', 'col')
					:done()
			cols = cols + 2
		end
		if has_votes12 then
		secondrow
				:tag('th')
					:wikitext('Votes')
					:attr('scope', 'col')
					:done()
				:tag('th')
					:wikitext('%')
					:attr('scope', 'col')
					:done()
			cols = cols + 2
		end
		if has_votes13 then
		secondrow
				:tag('th')
					:wikitext('Votes')
					:attr('scope', 'col')
					:done()
				:tag('th')
					:wikitext('%')
					:attr('scope', 'col')
					:done()
			cols = cols + 2
		end
		elseif has_nopercentage then
		if has_votes2 then
		secondrow
			:tag('th')
				:wikitext('2')
				:attr('scope', 'col')
				:done()
			cols = cols + 1
		end
		if has_votes3 then
		secondrow
			:tag('th')
				:wikitext('3')
				:attr('scope', 'col')
				:done()
			cols = cols + 1
		end
		if has_votes4 then
		secondrow
			:tag('th')
				:wikitext('4')
				:attr('scope', 'col')
				:done()
			cols = cols + 1
		end
		if has_votes5 then
		secondrow
			:tag('th')
				:wikitext('5')
				:attr('scope', 'col')
				:done()
			cols = cols + 1
		end
		if has_votes6 then
		secondrow
			:tag('th')
				:wikitext('6')
				:attr('scope', 'col')
				:done()
			cols = cols + 1
		end
		if has_votes7 then
		secondrow
			:tag('th')
				:wikitext('7')
				:attr('scope', 'col')
				:done()
			cols = cols + 1
		end
		if has_votes8 then
		secondrow
			:tag('th')
				:wikitext('8')
				:attr('scope', 'col')
				:done()
			cols = cols + 1
		end
		if has_votes9 then
		secondrow
			:tag('th')
				:wikitext('9')
				:attr('scope', 'col')
				:done()
			cols = cols + 1
		end
		if has_votes10 then
		secondrow
			:tag('th')
				:wikitext('10')
				:attr('scope', 'col')
				:done()
			cols = cols + 1
		end
		if has_votes11 then
		secondrow
			:tag('th')
				:wikitext('11')
				:attr('scope', 'col')
				:done()
			cols = cols + 1
		end
		if has_votes12 then
		secondrow
			:tag('th')
				:wikitext('12')
				:attr('scope', 'col')
				:done()
			cols = cols + 1
		end
		if has_votes13 then
		secondrow
			:tag('th')
				:wikitext('13')
				:attr('scope', 'col')
				:done()
			cols = cols + 1
		end
		end

	if topcell then
		topcell:attr('colspan', cols)
	end

	local rsuff = (rounds > 1) and {'', '_2'} or (rounds > 2) and {'', '_3'} or (rounds > 3) and {'', '_4'} or (rounds > 4) and {'', '_5'} or (rounds > 5) and {'', '_6'} or (rounds > 6) and {'', '_7'} or (rounds > 7) and {'', '_8'} or (rounds > 8) and {'', '_9'} or (rounds > 9) and {'', '_10'} or (rounds > 10) and {'', '_11'} or (rounds > 11) and {'', '_12'} or (rounds > 12) and {'', '_13'} or {''}
	for i, v in ipairs(index) do
		local has_votesrow = args['votes' .. v] or args['ivotes' .. v] or args['avotes' .. v] or args['ipct' .. v] or args['apct' .. v] or args['atotal' .. v]
		local has_votesrow2 = args['votes' .. v .. '_2'] or args['ivotes' .. v .. '_2'] or args['avotes' .. v .. '_2'] or args['ipct' .. v .. '_2']
		local has_votesrow3 = args['votes' .. v .. '_3'] or args['ivotes' .. v .. '_3'] or args['avotes' .. v .. '_3'] or args['ipct' .. v .. '_3']
		local has_votesrow4 = args['votes' .. v .. '_4'] or args['ivotes' .. v .. '_4'] or args['avotes' .. v .. '_4'] or args['ipct' .. v .. '_4']
		local has_votesrow5 = args['votes' .. v .. '_5'] or args['ivotes' .. v .. '_5'] or args['avotes' .. v .. '_5'] or args['ipct' .. v .. '_5']
		local has_votesrow6 = args['votes' .. v .. '_6'] or args['ivotes' .. v .. '_6'] or args['avotes' .. v .. '_6'] or args['ipct' .. v .. '_6']
		local has_votesrow7 = args['votes' .. v .. '_7'] or args['ivotes' .. v .. '_7'] or args['avotes' .. v .. '_7'] or args['ipct' .. v .. '_7']
		local has_votesrow8 = args['votes' .. v .. '_8'] or args['ivotes' .. v .. '_8'] or args['avotes' .. v .. '_8'] or args['ipct' .. v .. '_8']
		local has_votesrow9 = args['votes' .. v .. '_9'] or args['ivotes' .. v .. '_9'] or args['avotes' .. v .. '_9'] or args['ipct' .. v .. '_9']
		local has_votesrow10 = args['votes' .. v .. '_10'] or args['ivotes' .. v .. '_10'] or args['avotes' .. v .. '_10'] or args['ipct' .. v .. '_10']
		local has_votesrow11 = args['votes' .. v .. '_11'] or args['ivotes' .. v .. '_11'] or args['avotes' .. v .. '_11'] or args['ipct' .. v .. '_11']
		local has_votesrow12 = args['votes' .. v .. '_12'] or args['ivotes' .. v .. '_12'] or args['avotes' .. v .. '_12'] or args['ipct' .. v .. '_12']
		local has_votesrow13 = args['votes' .. v .. '_13'] or args['ivotes' .. v .. '_13'] or args['avotes' .. v .. '_13'] or args['ipct' .. v .. '_13']
					row = root:tag('tr')
			:addClass(args['class' .. v])
			:css('font-weight', args['font-weight' .. v])

		-- determine the colors
		local color = get_color(args['colour' .. v] or args['color' .. v] or nil, args['party' .. v])
		local rcolor = get_color(args['rcolour' .. v] or args['rcolor' .. v] or nil)

		if args['row' .. v] and has_party then
			row
				:css('background-color', rcolor)
				:tag('td')
				:attr('colspan', 3)
				:wikitext(args['row' .. v])
		end
		if has_party and not args['row' .. v] then
			row
				:tag('td')
					:css('width', '0px')
					:css('background-color', color)
		end
		if args['cand' .. v] then
			row
					:css('background-color', rcolor)
				:tag('td')
					:attr('rowspan', args['candspan' .. v] or args['aspan' .. v])
					:wikitext(args['cand' .. v])
		end
		if has_party and not args['row' .. v] then
			row
				:tag('td')
					:wikitext(args['party' .. v])
		end
		if has_votes then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(fmt(args['votes' .. v]))
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(pct(args['votes' .. v], valid[1]))
		end
		if args['votes' .. v .. '_2'] then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(fmt(args['votes' .. v .. '_2']))
		end
		if args['votes' .. v .. '_2'] and not has_nopercentage then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(pct(args['votes' .. v .. '_2'], valid[2]))
		end
		if args['votes' .. v .. '_3'] then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(fmt(args['votes' .. v .. '_3']))
		end
		if args['votes' .. v .. '_3'] and not has_nopercentage then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(pct(args['votes' .. v .. '_3'], valid[3]))
		end
		if args['votes' .. v .. '_4'] then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(fmt(args['votes' .. v .. '_4']))
		end
		if args['votes' .. v .. '_4'] and not has_nopercentage then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(pct(args['votes' .. v .. '_4'], valid[4]))
		end
		if args['votes' .. v .. '_5'] then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(fmt(args['votes' .. v .. '_5']))
		end
		if args['votes' .. v .. '_5'] and not has_nopercentage then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(pct(args['votes' .. v .. '_5'], valid[5]))
		end
		if args['votes' .. v .. '_6'] then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(fmt(args['votes' .. v .. '_6']))
		end
		if args['votes' .. v .. '_6'] and not has_nopercentage then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(pct(args['votes' .. v .. '_6'], valid[6]))
		end
		if args['votes' .. v .. '_7'] then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(fmt(args['votes' .. v .. '_7']))
		end
		if args['votes' .. v .. '_7'] and not has_nopercentage then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(pct(args['votes' .. v .. '_7'], valid[7]))
		end
		if args['votes' .. v .. '_8'] then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(fmt(args['votes' .. v .. '_8']))
		end
		if args['votes' .. v .. '_8'] and not has_nopercentage then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(pct(args['votes' .. v .. '_8'], valid[8]))
		end
		if args['votes' .. v .. '_9'] then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(fmt(args['votes' .. v .. '_9']))
		end
		if args['votes' .. v .. '_9'] and not has_nopercentage then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(pct(args['votes' .. v .. '_9'], valid[9]))
		end
		if args['votes' .. v .. '_10'] then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(fmt(args['votes' .. v .. '_10']))
		end
		if args['votes' .. v .. '_10'] and not has_nopercentage then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(pct(args['votes' .. v .. '_10'], valid[10]))
		end
		if args['votes' .. v .. '_11'] then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(fmt(args['votes' .. v .. '_11']))
		end
		if args['votes' .. v .. '_11'] and not has_nopercentage then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(pct(args['votes' .. v .. '_11'], valid[11]))
		end
		if args['votes' .. v .. '_12'] then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(fmt(args['votes' .. v .. '_12']))
		end
		if args['votes' .. v .. '_12'] and not has_nopercentage then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(pct(args['votes' .. v .. '_12'], valid[12]))
		end
		if args['votes' .. v .. '_13'] then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(fmt(args['votes' .. v .. '_13']))
		end
		if args['votes' .. v .. '_13'] and not has_nopercentage then
			row:tag('td')
				:css('text-align', 'right')
				:wikitext(pct(args['votes' .. v .. '_13'], valid[13]))
		end
	end

	-- separating line
	if args['valid'] or args['invalidblank'] or args['invalid'] or args['totalvotes'] or args['electorate'] or args['turnout'] or args['source'] then
	row = root
		:tag('tr')
			:addClass('sortbottom')
	row
		:tag('td')
			:css('background', '#eaecf0')
			:attr('colspan', cols)
	end
	-- valid votes

	local cs = 3 - (has_party and 0 or 2)

	if args['invalidblank'] or args['invalid'] then
	row = root
		:tag('tr')
			:addClass('sortbottom')
			:css('text-align', 'right')
	row
		:tag('th')
			:wikitext('Valid votes')
			:attr('scope', 'row')
			:attr('colspan', cs)
			:css('text-align', 'left')
			:css('font-weight', 'normal')
			:css('background', 'inherit')
		:tag('td')
			:wikitext(fmt(ovalid[1]))
		:tag('td')
			:wikitext(pct(ovalid[1], ovalid[1] + invalidblank[1] + invalid[1] + blank[1]))
	end
	-- invalid votes
	if args['invalidblank'] then
	row = root:tag('tr')
			:addClass('sortbottom')
			:css('text-align', 'right')
	row
		:tag('th')
			:wikitext('Invalid/blank votes')
			:wikitext(args.invalidnote)
			:attr('scope', 'row')
			:attr('colspan', cs)
			:css('text-align', 'left')
			:css('font-weight', 'normal')
			:css('background', 'inherit')
		:tag('td')
			:wikitext(fmt(invalidblank[1]))
		:tag('td')
			:wikitext(pct(invalidblank[1], ovalid[1] + invalidblank[1]))
	end
	if args['invalid'] then
	row = root:tag('tr')
			:addClass('sortbottom')
			:css('text-align', 'right')
	row
		:tag('th')
			:wikitext('Invalid votes')
			:wikitext(args.invalidnote)
			:attr('scope', 'row')
			:attr('colspan', cs)
			:css('text-align', 'left')
			:css('font-weight', 'normal')
			:css('background', 'inherit')
		:tag('td')
			:wikitext(fmt(invalid[1]))
		:tag('td')
			:wikitext(pct(invalid[1], ovalid[1] + invalid[1] + blank[1]))
	end
	-- blank votes
	if args['blank'] then
	row = root:tag('tr')
			:addClass('sortbottom')
			:css('text-align', 'right')
	row
		:tag('th')
			:wikitext('Blank votes')
			:attr('scope', 'row')
			:attr('colspan', cs)
			:css('text-align', 'left')
			:css('font-weight', 'normal')
			:css('background', 'inherit')
	row
		:tag('td')
			:wikitext(fmt(blank[1]))
		:tag('td')
			:wikitext(pct(blank[1], ovalid[1] + invalid[1] + blank[1]))
	end
	-- total
	if args['invalidblank'] or args['invalid'] or args['totalvotes'] then
	row = root:tag('tr')
			:addClass('sortbottom')
			:css('font-weight', 'bold')
			:css('text-align', 'right')
	row
		:tag('th')
			:wikitext(args.tvtitle or 'Total votes')
			:attr('scope', 'row')
			:attr('colspan', cs)
			:css('text-align', 'left')
			:css('background', 'inherit')
			:css('color', 'inherit')
	if not args['totalvotes'] and args['invalid'] or not args['totalvotes'] and args['invalidblank'] then
	row
		:tag('td')
			:wikitext(fmt(ovalid[1] + invalidblank[1] + invalid[1] + blank[1]))
		:tag('td')
			:wikitext(pct(1, 1))
	elseif args['totalvotes'] then
	row
		:tag('td')
			:wikitext(fmt(args.totalvotes))
		:tag('td')
			:wikitext('–')
	end
	end
	-- registered
	if args['electorate'] or args['turnout'] then
	row = root:tag('tr')
			:addClass('sortbottom')
			:css('text-align', 'right')
	row
		:tag('th')
			:wikitext('Registered voters/turnout')
			:attr('scope', 'row')
			:attr('colspan', cs)
			:css('text-align', 'left')
			:css('font-weight', 'normal')
			:css('color', 'inherit')
			:css('background', 'inherit')
	row
		:tag('td')
			:wikitext(fmt(electorate[1]))
	if args['invalidblank'] and args['electorate'] and not args['totalvotes'] or args['invalid'] and args['electorate'] and not args['totalvotes'] then
		row
			:tag('td')
				:wikitext(args.turnout or pct(ovalid[1] + invalidblank[1] + invalid[1] + blank[1], electorate[1]))
	elseif args['totalvotes'] and args['electorate'] then
		row
			:tag('td')
				:wikitext(args.turnout or pct(totalvotes[1], electorate[1]))
	elseif args['electorate'] then
		row
			:tag('td')
				:wikitext(args.turnout or '–')
	else
		row
			:tag('td')
				:wikitext(args.turnout)
	end
	if args['majority'] then
	if args['invalid'] or args['electorate'] then
	row = root
		:tag('tr')
			:addClass('sortbottom')
	row
		:tag('td')
			:css('background', '#eaecf0')
			:attr('colspan', cols)
	end
	row = root
		:tag('tr')
			:addClass('sortbottom')
			:css('text-align', 'right')
	row
		:tag('th')
			:wikitext('Majority')
			:attr('scope', 'row')
			:attr('colspan', cs)
			:css('text-align', 'left')
			:css('font-weight', 'normal')
			:css('background', 'inherit')
		:tag('td')
			:wikitext(fmt(majority[k]))
		:tag('td')
			:wikitext(fmt(majoritypct[k]))
	end
	end
	if args['result'] then
		row = root:tag('tr')
			:addClass('sortbottom')
		-- determine the color
		local color = get_color(args['resultcolour'] or nil, args['result'])
		if args['resultsw'] then
			row
				:tag('td')
					:css('background-color', color)
			row
				:tag('td')
					:attr('colspan', 2)
					:wikitext(args['result'])
			row
				:tag('td')
					:attr('colspan', 2)
					:css('text-align', 'right')
					:wikitext('Swing')
			row
				:tag('td')
					:css('text-align', 'right')
					:wikitext(args['resultsw'])
		else
			row
				:tag('td')
					:css('background-color', color)
			row
				:tag('td')
					:attr('colspan', cols - 1)
					:wikitext(args['result'])
		end
	end
	if args['source'] then
	row = root:tag('tr')
			:addClass('sortbottom')
			:css('text-align', 'right')
	row:tag('td')
		:wikitext('Source: ', args.source)
		:attr('colspan', cols)
		:css('text-align', 'left')
	end
	if args['embedded'] then
		root:wikitext(args['embedded'])
	end
	return tostring(root) .. tracking
end

return p