Module:Election results-STV

From Wikipedia, the free encyclopedia
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
				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)
		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