Template:High-use
Template:Module rating
This module implements a generic visual representation of the bracket of a single-elimination tournament with any number of rounds. For common usage, use the {{64TeamBracket}}, {{32TeamBracket}}, {{16TeamBracket}}, {{8TeamBracket}}, {{4TeamBracket}}, {{2TeamBracket}} templates.
Usage
{{#invoke: Team bracket | main
| rounds      =
| RD1-group1  =
| RD1         =
| RD1-seed1   =
| RD1-team1   =
| RD1-score1  =
 ...
}}
Parameters
| Parameter | Description | 
| roundsTemplate:!! number of rounds.  Use1for a 2 team bracket,2for a 4 team bracket,3for an 8 team bracket, ... | 
| maxround | maximum round to display.  This parameter should be omitted unless it is less than the default value set by rounds. | 
| seed-width | the width of the cells for seeds. Plain numbers are assumed to be in px units (e.g., 25or 25px2emfor 2em orautofor automatic width sizing) | 
| team-width | the width of the cells for team names. Plain numbers are assumed to be in px units (e.g., 200for 200px or15emfor 15em orautofor automatic width sizing) | 
| score-width | the width of the cells for scores. Plain numbers are assumed to be in px units (e.g., 25or 25px2emfor 2em orautofor automatic width sizing) | 
| compact | set to yesfor compact bracket and to disable groups. | 
| seeds | set to noto omit seed cells, andyesto always show seed cells | 
| setsorlegs | the number of sets/legs in each round of matches (delimit with / for different numbers of sets or legs per round) | 
| nowrap | set to yesto prevent lines from wrapping | 
| byes | set to 1,2, ... to specify the maximum round number with byes | 
| boldwinner | set to highto automatically bold the seed/team/scores for the team with the highest score, andlowfor the lowest score | 
| hideomittedscores | set to 1to hide all omitted score cells.  To only omit score cells from the second set or leg onwards, use2 | 
| sepwidth | set to 1or2to override the default separator width | 
| headings | set to noto omit the column headings | 
| RDn | The name of round n.  Defaults are "Round of m", ..., "Quarterfinals", "Semifinals", and "Finals", where m is the number of teams in the round. | 
| RDn-groupm | The name of group m in round n. For each round, every set of four teams is classified as a group. | 
| RDn-seedm | The seed of team m in round n. For round 1, this value defaults to the conventional seed allocation for tournaments. If omitted, the cell is hidden. To hide seeds for round 1, the value must be explicitly set to be empty. m is the zero-padded position. | 
| RDn-teamm | The name of team m in round n. | 
| RDn-scorem | The score of team m in round n. | 
| RDn-scorem-s | The score of team m in round n and set s (or leg for multileg matches).  Alternatively, the last score in the round can be specified using the -aggsuffix. | 
| RD1-omit | Selectively omit teams from the first round.  For example, use 1 / 2 / 5 / 6to omit team1, team2, team5, and team6 from the first round. | 
| RD-shade | Background color for the RDnheadings | 
| RDn-shadem-s | Background coloring for team m in round n and set s (or leg for multileg matches). | 
| RDn-RDn+1-path | Set to 0to omit the path between round n and round n+1. | 
| float | Float the bracket to the leftorrightorcenterorcentreof the page. | 
| clear | Set to noto prevent "clearing" the left/right side of the page before floating to the left/right.  This parameter is only valid with Template:Para or Template:Para. | 
| aggregate | Set to setsorlegsto sum the sets/legs won and append to the end of the scores.  Set toscoreto sum the scores from each set/leg and append to the end of the scores.  Set toyoryesto enable the-aggsuffix, but without any auto computation. Only works when there are two or more legs/sets in the round.  Any automatically computed value can be overridden by setting the value manually with the-aggsuffix for the score. | 
Examples
No seeds
{{#invoke: Team bracket | main
| rounds    = 2
| seeds     = no
}}
Compact
{{#invoke: Team bracket | main
| rounds    = 2
| compact   = yes
}}
Third place
{{#invoke: Team bracket | main
| rounds    = 2
| seeds     = no
| RD2b      = Third place
}}
|  | Semifinals |  |  | Finals |  | 
|  |  |  |  |  |  |  |  | 
|  |  |  |  |  | 
|  | 
|  |  |  |  | 
|  |  |  |  |  | 
|  |  |  | 
|  |  |  |  |  |  | 
|  |  |  |  | 
|  | 
|  |  |  |  |  | Third place | 
|  | 
|  | 
|  |  |  |  | 
|  | 
|  |  |  |  | 
Groups
{{#invoke: Team bracket | main
| autoseeds  = y
| rounds     = 3
| RD1-group1 = Pacific
| RD1-group2 = Mountain
| RD2-group1 = West
}}
|  | Quarterfinals |  |  | Semifinals |  |  | Finals |  | 
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | 
|  | 1 |  |  |  |  |  | 
|  | 
|  | 8 |  |  |  | 
|  |  |  |  |  | 
|  | Pacific |  | 
|  |  |  |  |  |  | 
|  | 5 |  |  |  | 
|  |  | 
|  | 4 |  |  |  | 
|  |  |  |  |  | 
|  | West |  | 
|  |  |  |  |  |  | 
|  | 3 |  |  |  |  | 
|  |  | 
|  | 6 |  |  |  | 
|  |  |  |  |  | 
|  | Mountain |  | 
|  |  |  |  |  |  | 
|  | 7 |  |  |  | 
|  |  | 
|  | 2 |  |  |  | 
Sets
{{#invoke: Team bracket | main
| autoseeds  = y
| rounds     = 3
| sets       = 3 / 5 / 5
}}
|  | Quarterfinals |  |  | Semifinals |  |  | Finals |  | 
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | 
|  | 1 |  |  |  |  |  |  |  | 
|  | 
|  | 8 |  |  |  |  |  | 
|  |  |  |  |  |  |  |  |  | 
|  |  |  | 
|  |  |  |  |  |  |  |  |  |  | 
|  | 5 |  |  |  |  |  | 
|  |  | 
|  | 4 |  |  |  |  |  | 
|  |  |  |  |  |  |  |  |  | 
|  |  |  | 
|  |  |  |  |  |  |  |  |  |  | 
|  | 3 |  |  |  |  |  |  | 
|  |  | 
|  | 6 |  |  |  |  |  | 
|  |  |  |  |  |  |  |  |  | 
|  |  |  | 
|  |  |  |  |  |  |  |  |  |  | 
|  | 7 |  |  |  |  |  | 
|  |  | 
|  | 2 |  |  |  |  |  | 
Aggregate
{{#invoke: Team bracket | main
| autoseeds  = y
| rounds     = 3
| legs       = 2
| aggregate  = y
}}
|  | Quarterfinals |  |  | Semifinals |  |  | Finals |  | 
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | 
|  | 1 |  |  |  |  |  |  |  | 
|  | 
|  | 8 |  |  |  |  |  | 
|  |  |  |  |  |  |  | 
|  |  |  | 
|  |  |  |  |  |  |  |  | 
|  | 5 |  |  |  |  |  | 
|  |  | 
|  | 4 |  |  |  |  |  | 
|  |  |  |  |  |  |  | 
|  |  |  | 
|  |  |  |  |  |  |  |  | 
|  | 3 |  |  |  |  |  |  | 
|  |  | 
|  | 6 |  |  |  |  |  | 
|  |  |  |  |  |  |  | 
|  |  |  | 
|  |  |  |  |  |  |  |  | 
|  | 7 |  |  |  |  |  | 
|  |  | 
|  | 2 |  |  |  |  |  | 
Bold winner with byes and hide omitted scores
{{#invoke: Team bracket | main
|rounds=3|byes=1|legs=3/5/5|sepwidth=1|boldwinner=high|hideomittedscores = 1
|RD1-seed3=4|RD1-team3=[[BC Vienna|Hallmann Vienna]]|RD1-score3-1=80|RD1-score3-2=66|RD1-score3-3=64
|RD1-seed4=5|RD1-team4=[[WBC Wels|WBC Raiffeisen Wels]]|RD1-score4-1=64|RD1-score4-2=81|RD1-score4-3=69
|RD1-seed7=3|RD1-team7=[[Kapfenberg Bulls|ece Bulls Kapfenberg]]|RD1-score7-1=97|RD1-score7-2=95
|RD1-seed8=6|RD1-team8=[[Arkadia Traiskirchen Lions]]|RD1-score8-1=80|RD1-score8-2=82
<!--SF-->
|RD2-seed1=1|RD2-team1=[[Oberwart Gunners|Redwell Gunners Oberwart]]|RD2-score1-1=75|RD2-score1-2=89|RD2-score1-3=57|RD2-score1-4=79|RD2-score1-5=77
|RD2-seed2=5|RD2-team2=[[WBC Wels|WBC Raiffeisen Wels]]|RD2-score2-1=84|RD2-score2-2=83|RD2-score2-3=63|RD2-score2-4=62|RD2-score2-5=67
|RD2-seed3=2|RD2-team3=[[Swans Gmunden]]|RD2-score3-1=73|RD2-score3-2=79|RD2-score3-3=68|RD2-score3-4=59
|RD2-seed4=3|RD2-team4=[[Kapfenberg Bulls|ece Bulls Kapfenberg]]|RD2-score4-1=92|RD2-score4-2=65|RD2-score4-3=81|RD2-score4-4=61
<!--F-->
|RD3-seed1=1|RD3-team1=[[Oberwart Gunners|Redwell Gunners Oberwart]]|RD3-score1-1=61|RD3-score1-2=56|RD3-score1-3=55|RD3-score1-4=72|RD3-score1-5=64
|RD3-seed2=3|RD3-team2=[[Kapfenberg Bulls|ece Bulls Kapfenberg]]|RD3-score2-1=57|RD3-score2-2=66|RD3-score2-3=56|RD3-score2-4=73|RD3-score2-5=73
}}
See also
 
--
-- This module implements many bracket templates
--
local p = {}
local args = {}
local rows = {}
local mask = {}
local rounds
local maxround
local legs = {}
local compact
local byes
local hideSeeds
local showSeeds
local hideHeadings
local showThird
local offsetThird
local compactFinal
local sepwidth
local aggsep
local aggregate
local boldwinner
local hideomittedscores
local RD1seedmap = {}
local tcats = ''
local function isnotblank(s)
	return s and s ~= ''
end
local function isblank(s)
	return (not s) or (s == '')
end
local function sumScores(s1, s2)
	s1 = mw.ustring.gsub(s1 or '', '^[\'%s]*([%d%.]*).-$', '%1')
	s2 = mw.ustring.gsub(s2 or '', '^[\'%s]*([%d%.]*).-$', '%1')
	if s1 ~= '' and s2 ~= '' then
		return tonumber(s1) + tonumber(s2)
	end
	return s1
end
local function scoreCompare(s1,s2,highwin)
	local ps1 = mw.ustring.gsub(s1 or '', '^[\'%s]*([%d%.]*)[\'%s]*%([\'%s]*([%d%.]*)[\'%s]*%).-$', '%2')
	local ps2 = mw.ustring.gsub(s2 or '', '^[\'%s]*([%d%.]*)[\'%s]*%([\'%s]*([%d%.]*)[\'%s]*%).-$', '%2')
	s1 = mw.ustring.gsub(s1 or '', '^[\'%s]*([%d%.]*).-$', '%1')
	s2 = mw.ustring.gsub(s2 or '', '^[\'%s]*([%d%.]*).-$', '%1')
	
	if s1 ~= '' and s2 ~= '' then
		s1 = tonumber(s1)
		s2 = tonumber(s2)
		if s1 and s2 then
			if (s1 == s2) then
				ps1 = tonumber(ps1)
				ps2 = tonumber(ps2)
				if ps1 and ps2 then
					s1 = ps1
					s2 = ps2
				end
			end
			if highwin then
				return ((s1 > s2) and 1) or ((s1 < s2) and 2) or 0
			else
				return ((s2 > s1) and 1) or ((s2 < s1) and 2) or 0
			end
		end
	end
	return 0
end
local function parseArgs(frame)
	local fargs = frame.args
	local pargs = frame:getParent().args;
	local r = tonumber(fargs.rounds or '') or tonumber(pargs.rounds or '') or 2
	local teams = math.pow(2, r)
	local rdstr = 'RD' .. tostring(r)
	local rdbstr = 'RD' .. tostring(r) .. 'b'
	local rdp1str = 'RD' .. tostring(r+1)
	for i=1,2 do
		local targs = (i == 1) and pargs or fargs
		for k,v in pairs(targs) do
			if type(k) == 'string' then
				if k:find('^[R3][Dr][d1-9]b?%-[a-z][a-z]*00*') then
					k = mw.ustring.gsub(k, '^([R3][Dr][d1-9]b?%-[a-z][a-z]*)00*', '%1')
					if (teams < 10) then 
						tcats = tcats .. '[[Category:Pages using a team bracket with deprecated syntax|P]]'
					end
				end
				if k:find('^' .. rdp1str) then
					k = mw.ustring.gsub(k, '^' .. rdp1str, '3rd')
					tcats = tcats .. '[[Category:Pages using a team bracket with deprecated syntax|3]]'
				elseif k:find('^' .. rdbstr) then
					k = mw.ustring.gsub(k, '^' .. rdbstr, '3rd')
				elseif k:find('^' .. rdstr .. '%-[a-z][a-z]*3') then
					k = mw.ustring.gsub(k, '^' .. rdstr .. '(%-[a-z][a-z]*)3', '3rd%11')
				elseif k:find('^' .. rdstr .. '%-[a-z][a-z]*4') then
					k = mw.ustring.gsub(k, '^' .. rdstr .. '(%-[a-z][a-z]*)4', '3rd%12')
				elseif  k:find('^Consol') then
					k = mw.ustring.gsub(k, '^Consol', '3rd')
					tcats = tcats .. '[[Category:Pages using a team bracket with deprecated syntax|3]]'
				elseif k:find('^group[0-9]') then
					tcats = tcats .. '[[Category:Pages using a team bracket with deprecated syntax|G]]'
				end
			end
			args[k] = v
		end
	end
	if (args['byes'] and (args['byes'] == 'yes' or args['byes'] == 'y')) then
		tcats = tcats .. '[[Category:Pages using a team bracket with deprecated syntax|B]]'
	end
end
local function parseSeedmap(s)
	s = mw.text.split((s or '0') .. '/', '[%s]*/[%s]*')
	local teams = math.pow(2, rounds)
	for r=1,teams do
		RD1seedmap[r] = 1
	end
	for r=1,#s do
		if tonumber(s[r] or 'x') then
			RD1seedmap[tonumber(s[r])] = 0
		end
	end
	local c = 1
	for r=1,teams do
		if RD1seedmap[r] > 0 then
			RD1seedmap[r] = c
			c = c + 1
		end
	end
end
local function parseLegs(s)
	s = mw.text.split((s or '1') .. '/', '[%s]*/[%s]*')
	if aggregate == 'n' or aggregate == 'no' or aggregate == '0' then
		aggregate = ''
	end
	local n = showThird and (rounds + 1) or (rounds)
	local lastlegs = nil
	for r=1,n do
		if s[r] ~= nil and s[r] ~= '' and tonumber(s[r]) then
			legs[r] = tonumber(s[r])
		elseif lastlegs then
			legs[r] = lastlegs
		else
			legs[r] = 1
		end
		lastlegs = legs[r]
		if legs[r] > 1 and aggregate ~= '' then
			legs[r] = legs[r] + 1
		end
	end
end
local function getSeeds()
	local seeds = {1, 2}
	local count = 2
	local before = false
	for r = 2, rounds do
		local max = math.pow(2, r)
		for i = 1, count do
			local pos = i * 2
			if before then pos = pos - 1 end
			table.insert(seeds, pos, max - seeds[i * 2 - 1] + 1)
			before = not before
		end
		count = count * 2
	end
	return seeds
end
local function addTableRow(tbl)
	return tbl:tag('tr')
end
local function addBlank(i, css, rowspan, colspan)
	local row = rows[i]
	rowspan = rowspan or 1
	local jmax = i + rowspan - 1
	for j = i, jmax do
		if rows[j] == nil then
			rowspan = rowspan - 1
		elseif row == nil then
			row = rows[j]
		end
	end
	local cell = row and row:tag('td') or mw.html.create('td')
	if rowspan and rowspan > 1 then
		cell:attr('rowspan', rowspan)
	end
	if colspan and colspan > 1 then
		cell:attr('colspan', colspan)
	end
	if css then
		cell:css(css)
	end
	return cell
end
local function addBorders(cell, topcell, seedorteam, extrasep)
	if sepwidth > 1 then topcell = true end
	if seedorteam then
		cell:css('border', '1px solid #aaa')
			:css('border-top-width', topcell and '1px' or '0')
	else
		cell:css('border-color', '#aaa')
			:css('border-style', 'solid')
			:css('border-top-width', topcell and '1px' or '0')
			:css('border-left-width', (extrasep and '1px') or ((sepwidth > 1) and '1px') or '0')
			:css('border-right-width', '1px')
			:css('border-bottom-width', '1px')
	end
end
local function addHeading(row, r, text, pad)
	pad = (pad == nil or pad < 0) and 0 or pad
	row:tag('td')
		:attr('colspan', tonumber(hideSeeds and '1' or '2') + legs[r] + pad)
		:css('text-align', 'center')
		:css('border', '1px solid #aaa')
		:css('background-color', args['RD-shade'] or '#f2f2f2')
		:wikitext(text)
		:newline()
end
local function getWidth(param, default)
	local arg = args[param .. '-width']
	if isblank(arg) then
		arg = default
	end
	if tonumber(arg) ~= nil then
		arg = arg .. 'px'
	end
	return arg
end
local function getTeamArgName(round, type, team)
	if round > rounds then
		return string.format('3rd-%s%d', type, team)
	else
		if (round == 1) then
			team = RD1seedmap[team]
			if team == 0 then
				return 'NIL'
			end
		end
		return string.format('RD%d-%s%d', round, type, team)
	end
end
local function getShadeArg(round, team, s)
	local argname = getTeamArgName(round, 'shade', team) .. (s and ('-' .. s) or '')
	local value = args[argname]
	if isblank(value) then
		return '#f9f9f9'
	end
	return value
end
local function getScoreArg(round, team, s)
	local argname = getTeamArgName(round, 'score', team) .. (s and ('-' .. s) or '')
	local value = args[argname]
	return value
end
local function getTeamArg(round, type, team)
	local argname = getTeamArgName(round, type, team)
	local value = args[argname]
	if isblank(value) then
		return ''
	end
	if mw.ustring.find(value, '[%s]*<[%s/]*[Bb][Rr][%s/]*>[%s ]*&[Nn][Bb][Ss][Pp];[%s]*') then
		tcats = tcats .. '[[Category:Pages using a team bracket with nbsp]]'
	end
	return mw.ustring.gsub(value, '[%s]*<[%s/]*[Bb][Rr][%s/]*>[%s ]*&[Nn][Bb][Ss][Pp];[%s]*', '<br/>')
end
local function isHidden(r, team)
	return isblank( getTeamArg(r, 'team', team) )
end
local function getRoundName(round)
	local name = args['RD' .. round]
	if isnotblank(name) then
		return name
	end
	local roundFromLast = rounds - round + 1
	if roundFromLast == 1 then
		return "Finals"
	elseif roundFromLast == 2 then
		return "Semifinals"
	elseif roundFromLast == 3 then
		return "Quarterfinals"
	else
		return "Round of " .. math.pow(2, roundFromLast)
	end
end
local function addPath(index, round, top, left, w)
	local prop = top and 'border-bottom-width' or 'border-top-width'
	if left and round == 1 then
		if compact then
			addBlank(index)
		else
			addBlank(index, {['height'] = '7px'})
			addBlank(index+1, {['height'] = '7px'})
		end
		return nil
	else
		local cell = addBlank(index, 
			{['border-width'] = '0',
			['border-style'] = 'solid',
			['border-color'] = 'black'}, (not compact) and 2 or 1)
		if left or round < maxround and not left then
			cell:css(prop, w or '2px')
		end
		return cell
	end
end
local function renderTeam(row, round, team, top, otherbye, pad)
	pad = (pad == nil or pad < 0) and 0 or pad
	tcs = pad + 1
	local seedCell
	local seedArg = getTeamArg(round, 'seed', team)
	-- seed value for the paired team
	local otherteam = team % 2 == 0 and team-1 or team+1
	local pairSeedArg = otherbye and '' 
		or getTeamArg(round, 'seed', otherteam)
	-- show seed if seed is defined for either or both
	local showSeed = showSeeds
		or isnotblank(seedArg)
		or isnotblank(pairSeedArg)
	if showSeed and (not hideSeeds) then
		seedCell = row:tag('td')
			:css('text-align', 'center')
			:css('background-color', '#f2f2f2')
			:attr('rowspan', (not compact) and '2' or nil)
			:wikitext(seedArg)
			:newline()
		addBorders(seedCell, top or otherbye, true, false)
	end
	local teamArg = getTeamArg(round, 'team', team)
	if isblank(teamArg) then
		teamArg = ' '
	end
	
	if not showSeed and (not hideSeeds) then
		tcs = tcs + 1
	end
	local teamCell = row:tag('td')
		:css('background-color', '#f9f9f9')
		:css('padding', '0 2px')
		:attr('rowspan', (not compact) and '2' or nil)
		:attr('colspan', (tcs > 1) and tcs or nil)
		:wikitext(teamArg)
		:newline()
	addBorders(teamCell, top or otherbye, true, false)
	local scoreCells = {}
	local wins, otherwins = 0, 0
	local sumscore, othersumscore = 0, 0
	local teamcolspan = tcs
	local hassum = false
	for s = 1, legs[round] do
		local fw = nil
		local agg = legs[round] > 1 and s == legs[round] and true or false
		local score1 = (agg and getScoreArg(round, team, 'agg') or nil) or 
			getScoreArg(round, team, s) or ((legs[round] == 1) and getScoreArg(round, team)) or nil
		local score2 = (agg and getScoreArg(round, otherteam, 'agg') or nil) or 
			getScoreArg(round, otherteam, s) or ((legs[round] == 1) and getScoreArg(round, otherteam)) or nil
		local showscore = true
		if agg and aggregate ~= '' and score1 == nil and hassum then
			score1 = (aggregate == 'score')	and sumscore 
				or ((aggregate == 'legs' or aggregate == 'sets') and wins)
				or nil
		end
		if agg and aggregate ~= '' and score2 == nil and hassum then
			score2 = (aggregate == 'score')	and othersumscore
				or ((aggregate == 'legs' or aggregate == 'sets') and otherwins)
				or nil
		end
		if score1 == nil and score2 == nil then
			if hideomittedscores > 0 and s >= hideomittedscores then
				teamcolspan = teamcolspan + 1
				showscore = false
			end
		else
			hassum = true
		end
		if showscore then
			local winner = scoreCompare(score1, score2, boldwinner ~= 'low')
			sumscore = sumScores(sumscore, score1)
			othersumscore = sumScores(othersumscore, score2)
			if winner == 1 then
				if boldwinner ~= '' or (agg and (aggregate == 'score' or aggregate == 'legs' or aggregate == 'sets')) then 
					if agg and (aggregate == 'legs' or aggregate == 'sets') and (wins <= (legs[round] - 1)/2) then
					else
						fw = 'bold'
					end
				end
				if not agg then wins = wins + 1 end
			elseif winner == 2 then
				if not agg then otherwins = otherwins + 1 end
			end
			scoreCells[s] = row:tag('td')
				:css('text-align', 'center')
				:css('background-color', getShadeArg(round, team, s))
				:css('font-weight', fw)
				:attr('rowspan', (not compact) and '2' or nil)
				:wikitext(score1)
				:newline()
			addBorders(scoreCells[s], top or otherbye, false, s > 1 and s == legs[round] and aggsep or nil)
		end
	end
	if teamcolspan > 1 then
		teamCell:attr('colspan', teamcolspan)
	end
	if boldwinner ~= '' and wins > otherwins then
		if (aggregate == 'legs' or aggregate == 'sets') and (wins <= (legs[round] - 1)/2) then
		else
			if seedCell then
				seedCell:css('font-weight', 'bold')
			end
			if teamCell then
				teamCell:css('font-weight', 'bold')
			end
		end
	end
end
local function renderRound(count, r)
	local teams = math.pow(2, rounds - r + 1)
	local step = count / teams
	local topTeam = true -- is top row in match-up
	local topPair = true -- is top match-up in pair of match-ups
	local team = 1
	local group = 1
	for i = 1, count, step do
		local offset, height, blank
		local hideteam = false
		local otherhideteam = false
		local hideleftpath = false
		local hiderightpath = false
		if r <= byes then
			hideteam = isHidden(r, team)
			otherhideteam = isHidden(r, team % 2 == 0 and team-1 or team+1)
		end
		if (r == 1) and (RD1seedmap[team] <= 0) then
				hideteam = true
		end
		if (r > 1) and (r <= (byes + 1)) then
			hideleftpath = isHidden(r-1, 2*team-1) and isHidden(r-1, 2*team)
		end
		if (r == 2) and (RD1seedmap[2*team-1] <= 0 and RD1seedmap[2*team] <= 0) then
			hideleftpath = true
		end
		if compactFinal and (r == rounds) then
			hideleftpath = true
		end
		if (tonumber(args['RD' .. (r-1) .. '-RD' .. (r) .. '-path']) or 2) == 0 then
			hideleftpath = true
		end
		if (tonumber(args['RD' .. (r) .. '-RD' .. (r + 1) .. '-path']) or 2) == 0 then
			hiderightpath = true
		end
		-- empty space above or below
		if compact then
			offset = topTeam and i or i + 1
			height = step - 1
		-- leave room for groups for teams other than first and last
		elseif team == 1 or team == teams then
			offset = topTeam and i or i + 2
			height = step - 2
		else
			offset = topTeam and i + 1 or i + 2
			height = step - 3
		end
		if showThird and (r == rounds) and (not topTeam) then
			height = offset - offsetThird
		end
		if compactFinal and (r == (maxround - 1)) then
			if team == 2 then
				height = height - 3
			end
			if team == 3 then
				height = height - 1
				offset = offset + 1
				addBlank(offset-3, nil, 1, tonumber(hideSeeds and '2' or '3') + legs[r])
				addBlank(offset-4)
				addHeading(rows[offset-4], r + 1, getRoundName(r+1), legs[r] - legs[r+1])
				local b = addBlank(offset-4, {
					['border-color'] = 'black',
					['border-style']= 'solid',
					['border-width']= '0'}, 2)
				b:css('border-right-width', '2px')
			end
		end
		if height > 0 then
			local pad = 0
			local betweenTeams = (topTeam == false and topPair == true) or (topTeam == true and topPair == false)
			if compactFinal and (r == maxround - 1) then
				betweenTeams = false
			end
			if compactFinal and (r == maxround - 1) and legs[r+1] > legs[r] then
				pad = legs[r+1] - legs[r]
			end
			if compact and betweenTeams then
				addBlank(offset, nil, height, 1)
				if topPair then
					blank = addBlank(offset, nil, 2*height, tonumber(hideSeeds and '1' or '2') + legs[r] + pad)
					if args['RD' .. r .. '-group' .. group] then
						blank:wikitext(args['RD' .. r .. '-group' .. group])
						blank:css('text-align', 'center')
					end
					group = group + 1
				end
				blank = addBlank(offset, 
				{['border-width'] = '0',
				['border-style'] = 'solid',
				['border-color'] = 'black'},
				height, 1)
			else
				blank = addBlank(offset, 
				{['border-width'] = '0',
				['border-style'] = 'solid',
				['border-color'] = 'black'},
				height, tonumber(hideSeeds and '3' or '4') + legs[r] + pad)
			end
		end
		-- add bracket
		local j = topTeam and i + step - (compact and 1 or 2) or i
		-- add left path
		addPath(j, r, topTeam, true, hideleftpath and '0' or '2px')
		if hideteam then
			addBlank(j, nil, (not compact) and 2 or nil, tonumber(hideSeeds and '1' or '2') + legs[r])
		elseif rows[j] then
			if compactFinal and (r == maxround) then
				renderTeam(rows[j], r, team, topTeam, otherhideteam, legs[r-1] - legs[r])
			elseif compactFinal and (r == maxround - 1) then
				renderTeam(rows[j], r, team, topTeam, otherhideteam, legs[r+1] - legs[r])
			else
				renderTeam(rows[j], r, team, topTeam, otherhideteam)
			end
		end
		local rightPath = addPath(j, r, topTeam, false, (hiderightpath or hideteam) and '0' or '2px')
		if not topTeam then topPair = not topPair end
		if not topPair and r < maxround and (not (hiderightpath or hideteam)) then
			if blank then blank:css('border-right-width', '2px') end
			rightPath:css('border-right-width', '2px')
		end
		if compactFinal and (r == maxround) then
			local prop = (team == 1) and 'border-bottom-width' or 'border-top-width'
			rightPath:css('border-right-width', '2px')
				:css(prop, '2px')
		end
		team = team + 1
		topTeam = not topTeam
	end
end
local function renderGroups(count, round)
	local roundFromLast = rounds - round + 1
	local groups = math.pow(2, roundFromLast - 2)
	local step = count / groups
	local group = 1
	local offset = 0
	local team = 0
	local wdef = (tonumber(args['RD' .. (round) .. '-RD' .. (round + 1) .. '-path']) or 2) .. 'px'
	local w = wdef
	for r = 1,round do
		offset = offset + (hideSeeds and 3 or 4) + legs[r]
	end
	for i = step / 2, count, step do
		local name = 'RD' .. round .. '-group' .. group
		addBlank(i, {['height'] = '7px'})
		addBlank(i+1, {['height'] = '7px'})
		addBlank(i, {['text-align'] = 'center'}, 2, offset-2)
			:wikitext(args[name])
			:newline()
		if (round <= byes) then
			team = i/(step/2)
			w = isHidden(round, 2*team-1) and isHidden(round, 2*team) and '0' or wdef
		end
		if (round < maxround) then
			addBlank(i, {
				['border-color'] = 'black',
				['border-style'] = 'solid', 
				['border-width'] = '0 ' .. w .. ' 0 0'})
		else
			addBlank(i)
		end
		if (round <= byes) then
			team = team + 1
			w = isHidden(round, 2*team-1) and isHidden(round, 2*team) and '0' or wdef
		end
		if (round < maxround) then
			addBlank(i+1, {
				['border-color'] = 'black',
				['border-style'] = 'solid', 
				['border-width'] = '0 ' .. w .. ' 0 0'})
		else
			addBlank(i+1)
		end
		group = group + 1
	end
end
local function getThirdOffset()
	local offset = (compact and 1 or 3) * (math.pow(2, rounds) - math.pow(2, rounds-3)) - (compact and 2 or 4)
	if rounds < 4 then
		offset = compact and 8 or 17
		if rounds < 3 then
			offset = compact and 6 or 10
			if rounds < 2 then
				offset = compact and 4 or 7
			end
		end
	end
	return offset
end
local function renderThird(count)
	local k = offsetThird
	local row = rows[k]
	local blank
	if rounds < 2 then
		blank = addBlank(k-1, {['height'] = '7px'})
	end
	blank = addBlank(k, rounds < 2 and {['height'] = '7px'} or nil)
	addHeading(row, rounds + 1, args['3rd'] or 'Third place')
	if rounds < 2 then
		for i = 1,(compact and 1 or 2) do
			blank = addBlank(k+i, {['height'] = '7px'})
		end
	end
	k = k + (compact and 2 or 3)
	for i = 1,2 do
		row = rows[k]
		blank = addBlank(k, rounds < 2 and {['height'] = '7px'} or nil)
		if row then
			renderTeam(row, rounds + 1, i, i == 1, false)
		end
		if rounds < 2 and not compact then
			blank = addBlank(k+1, {['height'] = '7px'})
		end
		k = k + (compact and 1 or 2)
	end
end
local function maskRows(tbl, count, offsetcount)
	local rmin = 1
	local rmax = count
	for i = rmin, rmax do
		mask[i] = false
	end
	if showThird then
		for i = offsetThird,(offsetThird+ (compact and 3 or 5)) do
			rmax = (i > rmax) and i or rmax
			mask[i] = true
		end
	end
	for r = 1, maxround do
		local teams = math.pow(2, rounds - r + 1)
		local step = count / teams
		local topTeam = true -- is top row in match-up
		local team = 1
		for i = 1, count, step do
			local offset, height, blank
			local hideteam = false
			if r <= byes then
				hideteam = isHidden(r, team)
			end
			if (r == 1) and (RD1seedmap[team] <= 0) then
				hideteam = true
			end
			if not hideteam then
				local j = topTeam and i + step - (compact and 1 or 2) or i
				mask[j] = true
			end
			team = team + 1
			topTeam = not topTeam
		end
	end
	
	for r = 1, maxround do
		local roundFromLast = rounds - r + 1
		local groups = math.pow(2, roundFromLast - 2)
		local step = count / groups
		local group = 1
		for i = step / 2, count, step do
			if args['RD' .. r .. '-group' .. group] then
				mask[i] = true
				mask[i+1] = true
			end
			group = group + 1
		end
	end
	local mmin, mmax = rmax, rmin
	for i = rmin, rmax do
		if mask[i] == true then
			mmin = (i < mmin) and i or mmin
			mmax = (i > mmax) and i or mmax
		end
	end
	for i = mmin, mmax do
		rows[i] = addTableRow(tbl)
	end
end
local function renderTree(tbl)
	-- create 3 or 1 rows for every team
	local count = math.pow(2, rounds) * (compact and 1 or 3)
	local offsetcount = 2 * (compact and 1 or 3) + (compact and 2 or 3)
	offsetThird = getThirdOffset()
	maskRows(tbl, count, offsetcount)
	if showThird then
		for i = (count+1), (offsetcount + offsetThird) do
			if (rounds > 1) then
				local blank = addBlank(i, nil, 1, tonumber(hideSeeds and '3' or '4') + legs[1])
				if compact and (rounds > 2) then
					blank = addBlank(i, nil, 1, tonumber(hideSeeds and '3' or '4') + legs[1])
				end
			end
		end
	end
	if not compact then
		-- fill rows with groups
		for r = 1, rounds - 1 do
			renderGroups(count, r)
		end
	end
	-- fill rows with bracket
	for r = 1, maxround do
		renderRound(count, r)
	end
	if showThird then
		renderThird(count, compact)
	end
end
local function renderHeadings(tbl)
	local titleRow = addTableRow((not hideHeadings) and tbl or mw.html.create('table'))
	local widthRow = addTableRow(tbl)
	for r = 1, (compactFinal and (maxround-1) or maxround) do
		titleRow:tag('td')
		widthRow:tag('td'):css('width', r > 1 and '5px' or '1px')
		if compactFinal and r == (maxround-1) then
			addHeading(titleRow, r, getRoundName(r), legs[r+1] - legs[r])
		else
			addHeading(titleRow, r, getRoundName(r) )
		end
		local seedCell
		if (not hideSeeds) then
			seedCell = widthRow:tag('td'):css('width', getWidth('seed', '25px'))
		end
		local teamCell = widthRow:tag('td'):css('width', getWidth('team', '150px'))
		local scoreCells = {}
		local legsr = legs[r]
		if compactFinal and r == (maxround-1) then
			legsr = legs[r+1] > legs[r] and legs[r+1] or legs[r]
		end
		for s = 1, legsr do
			scoreCells[s] = widthRow:tag('td'):css('width', getWidth('score', '25px'))
		end
		titleRow:tag('td')
		widthRow:tag('td'):css('width', r < rounds and '5px' or '1px')
		if compact then
			teamCell:css('height', '7px')
		else
			if seedCell then
				seedCell:wikitext(' ')
			end
			teamCell:wikitext(' ')
			for s = 1, legs[r] do
				scoreCells[s]:wikitext(' ')
			end
		end
	end
end
function p.main(frame)
	parseArgs(frame)
	rounds = tonumber(args.rounds) or 2
	maxround = tonumber(args.maxround) or rounds
	local teams = math.pow(2, rounds)
	compact = (args['compact'] and (args['compact'] == 'yes' or args['compact'] == 'y'))
	compactFinal = ((rounds > 4) and compact and args['compact-final'] and (args['compact-final'] == 'yes' or args['compact-final'] == 'y'))
	sepwidth = tonumber(args['sepwidth'] or ((args.sets or args.legs) and 1) or (compact and 1) or 2) or 1
	aggregate = (args['aggregate'] or ''):lower()
	aggsep = args['aggsep'] or args['aggregate'] or nil
	boldwinner = args['boldwinner'] or args['bold_winner'] or ''
	local autoSeeds = (args['autoseeds'] and (args['autoseeds'] == 'yes' or args['autoseeds'] == 'y'))
	hideSeeds = (args['seeds'] and (args['seeds'] == 'no' or args['seeds'] == 'n'))
	showSeeds = (args['seeds'] and (args['seeds'] == 'yes' or args['seeds'] == 'y'))
	byes = (args['byes'] and (args['byes'] == 'yes' or args['byes'] == 'y') and 1) or (tonumber(args['byes'] or '0') or 0)
	hideomittedscores = (args['hideomittedscores'] and (args['hideomittedscores'] == 'yes' or args['hideomittedscores'] == 'y') and 1) or (tonumber(args['hideomittedscores'] or '0') or 0)
	hideHeadings = (args['headings'] and (args['headings'] == 'no' or args['headings'] == 'n'))
	showThird = isnotblank(args['3rd']) or isnotblank(args['3rd-team1']) or isnotblank(args['3rd-team2'])
	local align = (args['float'] or args['align'] or ''):lower()
	local clear = args['clear'] or 'none'
	parseSeedmap(args['RD1-omit'])
	parseLegs(args.sets or args.legs)
	
	if autoSeeds then
		-- set default seeds for round 1
		local seeds = getSeeds()
		for i = 1, table.getn(seeds) do
			local argname = getTeamArgName(1, 'seed', i)
			if not args[argname] then
				args[argname] = seeds[i]
			end
		end
	end
	-- create the table
	local tbl = mw.html.create('table')
		:css('border-style', 'none')
		:css('font-size', '90%')
		:css('border-collapse', 'separate')
		:css('border-spacing', '0')
		:attr('cellpadding', '0')
	if (args['nowrap'] and (args['nowrap'] == 'yes' or args['nowrap'] == 'y')) then
		tbl:css('white-space', 'nowrap')
	end
	
	if align == 'right' then
		tbl:css('float', 'right')
		if clear ~= 'none' and clear ~= 'no' and clear ~= 'n' then
			tbl:css('clear', 'right')
		end
		tbl:css('margin', '1em 0 1em 2em')
	elseif align == 'left' then
		tbl:css('float', 'left')
		if clear ~= 'none' and clear ~= 'no' and clear ~= 'n' then
			tbl:css('clear', 'left')
		end
		tbl:css('margin', '1em 2em 1em 0')
	elseif align == 'center' or align == 'centre' then
		tbl:css('margin', '1em auto')
	else
		tbl:css('margin', '1em 2em 1em 1em')
	end
	renderHeadings(tbl)
	renderTree(tbl)
	return tostring(tbl) .. tcats
end
function p.teamBracket(frame)
	return p.main(frame)
end
return p