Module:Build bracket

From Atlas Altera

This module is intended to be used to create and edit intricate sports brackets that cannot be made by Module:RoundN or Module:Team bracket. For example, additional headers (for double-elimination brackets; 3rd-, 5th-, 7th-place matches; etc), singular omitted matches (i.e., having a horizonal line instead of a match), and N-way brackets (N teams per match). The syntax is slightly more complicated than the aforementioned brackets, but simpler than using the standard wikitable code.

Usage

{{#invoke:Build bracket|main
| rounds =

| col1-headers = 
| col1-matches = 

| col2-headers = 
| col2-matches = 

...

| col1-col2-paths = 
| col2-col3-paths = 

...
}}

Parameters

Parameter Description Default
rounds number of rounds (columns). 1
rows manually set the number of rows. Automatic
teams-per-match enter the number of teams in each match. Use colm-teams-per-match to set individual columns 2
colm-headers (optional) enter the row numbers where headers are desired in column m. Separate entries with ,. Half integer values are allowed. Automatic
colm-matches enter the row numbers where a match is desired in column m. Matches take up two rows by default. Separate entries with ,. Half integer values are allowed.
RDmh-hide set to yes to hide the (alpha) hth header and all matches beneath it in column m unless any of those entries are non empty. Useful for consolation matches.
colm-colm+1-paths enter the starting and ending row numbers, separated by -, from columns m and m+1 where a path is desired. Separate entries with ,. Half integer values are allowed.
colm-colm+1-cross enter the row number where paths intersect from column m to m+1.
RDm-altname Alternate name for RDm (e.g., if |RD1-altname=first, then first-team1 can be used instead of RD1-team1). Use RDmh-altname for cells under header mh.
text-altname Alternate name for RDm-textk (e.g., if |text-altname=details, then RDm-details1 can be used instead of RDm-text1).
maxround final round to display. This parameter should be omitted unless it is less than the default value set by rounds.
minround first round to display. 1
autocol set to yes to automatically set set maximum round to display based on entries. no
col-spacing the amount of space between rounds. Enter as a plain number (e.g., 10 for 10px). 5
nowrap set to yes to prevent text from wrapping. no
seed-width the width of the cells for seeds. Plain numbers are assumed to be in px units (e.g., 25 for 25px 2em for 2em) 25
team-width the width of the cells for team names. Plain numbers are assumed to be in px units (e.g., 200 for 200px or 15em for 15em) 150
score-width the width of the cells for scores. Plain numbers are assumed to be in px units (e.g., 25 or 25px 2em for 2em) 25
seeds set to no to omit seeds in in all matches. set to yes to show seed cells to show for all matches.
legs the number of legs for all rounds. Use RDm-legs to individually set columns. Use RDm-legsk to individually set teams. 1
autolegs set to yes to automatically generate score cells per team. If legs or RDm-legs is used, autolegs will be set to no . no
byes set to yes to hide any team cells that are empty. Use RDm-byes for all matches under column m. Use RDmh-byes for matches under header h only in column m. no
show-bye-paths set to yes to replace any team cells that that are hidden byes with a path. no
aggregate set to yes to add an aggregate score box to each match. Only matches with two or more legs will show the aggregate score box. no
boldwinner set to yes to automatically bold the seed/team/score with the higher score in each match. no
shift vertically shifts all of the entries by the number entered. Use RDm-shift for individual in columns. 0
RDm, RDmh The header text of the (alpha hth) header in column m (e.g., RD1 or RD1a for the first header and RD1b for the second header in column 1).
RDm-seedk The seed of the kth team in column m. Alternatively, use RDmh-seedk for the kth team under header mh.
RDm-teamk The name of the kth team in column m. Alternatively, use RDmh-teamk for the kth team under header mh.
RDm-scorek The score of the kth team in column m. Alternatively, use RDmh-scorek for the kth team under header mh. Append the suffix -l for the lth leg or -agg for the aggregate score.
RDm-textk The text above the kth match in column m. Alternatively, use RDmh-textk for the kth match under header mh.
RDm-groupk The text for the kth group in column m. Group text will appear to the left of whenever two paths meet.
RD-shade the background color (in hex format, e.g. #ABCDEF) of all headers. Use RDm-shade or RDmh-shade for individual headers. #F2F2F2
RDm-RD(m+1)-path set to no or 0 to omit the paths from round m to round m+1. Note: Does not currently work for paths under subheaders. yes
paramstyle[a] set to numbered change the parameter name style of RDm-textk, RDm-seedk, RDm-teamk, and RDm-scorek to a numbered notation (|1=,|2=...). Set |seeds=yes add seeds. indexed
  1. May not be compatible with certain other features.

Parameter hierarchy

  • Whenever there are multiple headers in a single column, more than one parameter may be assigned to a cell value. For example, in the following bracket, both |RD1-team3= and |RD1b-team1= can be used to assign the third team in the first column. By default, entries with subheader prefixes will override those without. In the below example, RD1b-team1 will override any value that has been set by RD1-team3.
Upper round
Lower round
RD1-team3 or RD1b-team1
  • Parameters used in articles take precedence over parameters used in the template itself. For example, suppose ArticleX used the template NTeamBracket, and suppose NTeamBracket had the parameter |RD1-seed1=1 set. If ArticleX implemented {{NTeamBracket|RD1-seed1=2}}, then the first team in round 1 would have a seed of 2.

Path codes

Path codes are entered in the form a-b, where a is associated match in the first column, and b is associated match in the second column. Path codes can be grouped; for example, (a,b)-c is equivalent to a-c, b-c. To add color, append :color to the end of a path, e.g. 3-5:red. Only one extra color can be used in a bracket. Template:Wikitable

Examples

Note: These are only examples to illustrate parameters. Standard 4-team, 8-team, etc. brackets are better handled by Module:Team bracket.

Standard 4-team bracket

{{#invoke:Build bracket|main
| rounds=2

| col1-headers = 1
| col2-headers = 1

| col1-matches = 3,7
| col2-matches = 5

| col1-col2-paths = (3,7)-5

<!-- Defaults -->
| RD2 = Grand Final

| RD1-seed1 = 1
| RD1-seed3 = 2
}}
SemifinalsGrand Final
1
2

3-way bracket

{{#invoke:Build bracket|main
| rounds=2
| teams-per-match = 3

| col1-headers = 1
| col2-headers = 1

| col1-matches = 3,7,11
| col2-matches = 7

| col1-col2-paths = (3,7,11)-7
}}
SemifinalsFinal

Double-elimination bracket

{{#invoke:Build bracket|main
| rounds=4

| col1-headers = 1,7
| col2-headers = 1,7
| col3-headers = 7
| col4-headers = 1

| col1-matches = 4,11
| col2-matches = 3,10
| col3-matches = 9
| col4-matches = 6

| col1-col2-paths = 4-3, 11-10
| col2-col3-paths = 3-3, 10-9
| col3-col4-paths = (3,9)-6

<!-- Defaults -->
| RD1 = Upper round 1
| RD2 = Upper final
| RD3b = Lower final
}}
Upper round 1Upper finalFinal
Lower round 1Lower round 2Lower final

Crossing paths

{{#invoke:Build bracket|main
| rounds=2

| col1-matches = 3,7
| col2-matches = 3,7

| col1-col2-paths = 3-7, 7-3
| col1-col2-cross = 5
}}
SemifinalsFinal

No seeds

{{#invoke:Build bracket|main
| rounds=2
| seeds=no

| col1-matches = 3,7
| col2-matches = 5

| col1-col2-paths = (3,7)-5
}}
SemifinalsFinal

Text

{{#invoke:Build bracket|main
| rounds=2
| col1-matches = 3,6
| col2-matches = 4.5
| col1-col2-paths = (3,6)-4.5

| RD1-text1 = Text 1
| RD1-text2 = Text 2
| RD2-text1 = Text 3
}}
SemifinalsFinal
Text 1
Text 3
Text 2

Groups

{{#invoke:Build bracket|main
| rounds=3
| col1-matches = 3,6,9,12
| col2-matches = 4.5,10.5
| col3-matches = 7.5

| col1-col2-paths = (3,6)-4.5, (9,12)-10.5
| col2-col3-paths = (4.5,10.5)-7.5

| RD1-group1 = Group 1
| RD1-group2 = Group 2
| RD2-group1 = Group 3
}}
QuarterfinalsSemifinalsFinal
Group 1
Group 3
Group 2

Legs

{{#invoke:Build bracket|main
| rounds=3
| legs = 2
| RD1-legs = 3

| col1-matches = 3,6,9,12
| col2-matches = 4.5,10.5
| col3-matches = 7.5

| col1-col2-paths = (3,6)-4.5, (9,12)-10.5
| col2-col3-paths = (4.5,10.5)-7.5
}}
QuarterfinalsSemifinalsFinal

Aggregate

{{#invoke:Build bracket|main
| rounds=3
| legs=2
| aggregate=y

| col1-matches = 3,6,9,12
| col2-matches = 4.5,10.5
| col3-matches = 7.5

| col1-col2-paths = (3,6)-4.5, (9,12)-10.5
| col2-col3-paths = (4.5,10.5)-7.5
}}
QuarterfinalsSemifinalsFinal

Byes

{{#invoke:Build bracket|main
| rounds=3
| RD1-byes = y

| col1-matches = 3,6,9,12
| col2-matches = 4.5,10.5
| col3-matches = 7.5

| col1-col2-paths = (3,6)-4.5, (9,12)-10.5
| col2-col3-paths = (4.5,10.5)-7.5

| RD1-team1 = Team 1
| RD1-team2 = Team 2
}}
QuarterfinalsSemifinalsFinal
Team 1
Team 2

Numbered parameters

{{#invoke:Build bracket|main
| rounds=2
| col1-matches = 3,7
| col2-matches = 5
| col1-col2-paths = (3,7)-5

| paramstyle = numbered
| seeds = yes

| Text 1 | 1 | Team 1 | 5 | 4 | Team 2 | 11
| Text 2 | 2 | Team 3 | 6 | 3 | Team 4 | 3

| Text 3 | 4 | Team 2 | 2 | 2 | Team 3 | 1 
}}
SemifinalsFinal
Text 1
1 Team 1 5
4 Team 2 11 Text 3
4 Team 2 2
Text 2 2 Team 3 1
2 Team 3 6
3 Team 4 3

Bold winner

{{#invoke:Build bracket|main
| rounds=2
| legs = 3
| boldwinner=y
| col1-matches = 3,7
| col2-matches = 5
| col1-col2-paths = (3,7)-5

| RD1-seed1 = 1 | RD1-team1 = Team 1 | RD1-score1-1 = 5  | RD1-score1-2 = 12 | RD1-score1-3 = 15
| RD1-seed2 = 4 | RD1-team2 = Team 2 | RD1-score2-1 = 11 | RD1-score2-2 = 10 | RD1-score2-3 = 4

| RD1-seed3 = 2 | RD1-team3 = Team 3 | RD1-score3-1 = 6  | RD1-score3-2 = 13 | RD1-score3-3 = {{ndash}}
| RD1-seed4 = 3 | RD1-team4 = Team 4 | RD1-score4-1 = 3  | RD1-score4-2 = 2  | RD1-score4-3 = {{ndash}}

| RD2-seed1 = 4 | RD2-team1 = Team 2 | RD2-score1-1 = 2  | RD2-score1-2 = 2  | RD2-score1-3 = 5
| RD2-seed2 = 2 | RD2-team2 = Team 3 | RD2-score2-1 = 1  | RD2-score2-2 = 7  | RD2-score2-3 = 2
}}
SemifinalsFinal
1Team 151215
4Team 211104
4Team 2225
2Team 3172
2Team 3613Template:Ndash
3Team 432Template:Ndash

See also


local p = {}
local entries = {}
local pathEntries = {}
local pathcolor
local shift = {}
local hascross = {}
local teams_per_match = {}
local rlegs = {}
local maxlegs = {}
local autolegs
local byes = {}
local hide = {}
local matchgroup = {}
local autocol
local seeds
local forceseeds
local nowrap
local boldwinner
local aggregate
local paramstyle
local masterindex

local function isempty(s)
	return s==nil or s==''
end

local function notempty(s)
	return s~=nil and s~=''
end

local function bargs(s)
	return pargs[s] or fargs[s]
end

local function toChar(num)
	return string.char(string.byte("a")+num-1)
end

local function split(str,delim,tonum)
	result = {};
	local a = "[^"..table.concat(delim).."]+"
		for w in str:gmatch(a) do
			if tonum==true then
				table.insert(result, tonumber(w));
			else
				table.insert(result, w);
			end
		end
	return result;
end

local function getWidth(ctype, default)
	local result = bargs(ctype..'-width')
	if isempty(result) then return default end
	if tonumber(result)~=nil then return result..'px' end
	return result
end

local function matchGroups()
	for j=minc,c do
		matchgroup[j]={}
		for i=1,r do
			if entries[j][i]~= nil and entries[j][i]['ctype']=='team' then
				matchgroup[j][i]=math.ceil(entries[j][i]['index']/teams_per_match[j])
				entries[j][i]['group'] = math.ceil(entries[j][i]['index']/teams_per_match[j])
			end
		end
	end
end

local function boldWinner()
	local function boldScore(j,i,l)
		if entries[j][i]~= nil and entries[j][i]['ctype']=='team' then
			local myscore = entries[j][i]['score'][l]
			if myscore == "" or myscore:find("%D") then return 'normal'
				else myscore=tonumber(myscore) end
			local compscore = {}
			for k,v in pairs(matchgroup[j]) do
				if matchgroup[j][i]==v and k~=i then
					if entries[j][k]['score'][l]==nil or entries[j][k]['score'][l] == "" or entries[j][k]['score'][l]:find("%D") then return 'normal'
						else table.insert(compscore,tonumber(entries[j][k]['score'][l])) end
				end
			end
			for k,v in pairs(compscore) do
				if myscore<=v then return 'normal' end
			end
			if l~='agg' then
				entries[j][i]['wins'] = entries[j][i]['wins']+1
			else
				entries[j][i]['aggwins'] = 1
			end
			return 'bold'
		end
	end
	local function boldEntry(j,i,agg)
		local wins
		if agg~=true then
			wins = 'wins'
		else
			wins = 'aggwins'
		end
		local myteam = entries[j][i][wins]
		local compteam = {}
		for k,v in pairs(matchgroup[j]) do
			if matchgroup[j][i]==v and k~=i then
				table.insert(compteam,tonumber(entries[j][k][wins]))
			end
		end
		for k,v in pairs(compteam) do
			if myteam<=v then return 'normal' end
		end
		return 'bold'
	end
	for j=minc,c do
		for i=1,r do
			if entries[j][i]~= nil and entries[j][i]['ctype']=='team' then
				entries[j][i]['wins'] = 0
				entries[j][i]['aggwins'] = 0
			end
		end
		for i=1,r do
			if entries[j][i]~= nil and entries[j][i]['ctype']=='team' then
				local legs = rlegs[j]
				if notempty(entries[j][i]['legs']) then
					legs = tonumber(entries[j][i]['legs'])
				end
				if autolegs then
					local l=1
					repeat l=l+1
					until isempty(entries[j][i]['score'][l])
					legs = l-1
				end	
				for l=1,legs do
					entries[j][i]['score']['weight'][l] = boldScore(j,i,l)
				end
				if aggregate and legs>1 then
					entries[j][i]['score']['weight']['agg'] = boldScore(j,i,'agg')
				end
			end
		end
		for i=1,r do
			if entries[j][i]~= nil and entries[j][i]['ctype']=='team' then
				local agg
				local legs = rlegs[j]
				if notempty(entries[j][i]['legs']) then
					legs = tonumber(entries[j][i]['legs'])
				end
				if autolegs then
					local l=1
					repeat l=l+1
					until isempty(entries[j][i]['score'][l])
					legs = l-1
				end
				if aggregate and legs>1 then agg=true end
				entries[j][i]['weight'] = boldEntry(j,i,agg)
			end
		end
	end
end

local function isBlankEntry(col,row,ctype)
	if isempty(entries[col][row]) then return true end
	if isempty(entries[col][row]['team']) and isempty(entries[col][row]['text']) then return true end
	return false
end

local function showSeeds(j,i)
	local showseed=false
	if forceseeds or notempty(entries[j][i]['seed']) then
		showseed=true
	else
		for k=1,teams_per_match[j]-1 do
			if notempty(entries[j][i+2*k]) and entries[j][i]['group']==entries[j][i+2*k]['group'] and notempty(entries[j][i+2*k]['seed']) then
				showseed=true
			end
			if notempty(entries[j][i-2*k]) and entries[j][i]['group']==entries[j][i-2*k]['group'] and notempty(entries[j][i-2*k]['seed']) then
				showseed=true
			end
		end
	end
	return showseed
end


local function blankCell(tbl,j,i,rowspan,colspan,text,align)
	local cell = tbl:tag('td')
	if colspan~=1 then
		cell:attr('colspan',colspan)
	end
	if rowspan~=1 then
		cell:attr('rowspan',rowspan)
	end
	if notempty(align) then
		cell:css('text-align',align)
	end
	if notempty(text) then
		if nowrap then
			cell:css('white-space', 'nowrap')
		end
		cell:wikitext(text)
	end
	return cell
end

local function headerCell(tbl,j,i,colspan)
	local cell = tbl:tag('td')
					:attr('rowspan',2)
					:css('text-align','center')
					:css('border','1px solid #aaa')
					:css('background-color',entries[j][i]['shade'])
					:wikitext(entries[j][i]['header'])
	if colspan~=1 then
		cell:attr('colspan',colspan)
	end
	if nowrap then
		cell:css('white-space', 'nowrap')
	end
	if entries[j][i]['position']=='top' and entries[j][i-2]~=nil and entries[j][i-2]['ctype']~='blank' and entries[j][i-2]['ctype']~='text' and entries[j][i-2]['ctype']~='group' and (not byes[j][entries[j][i]['headerindex']] or not isBlankEntry(j,i-2)) then
		cell:css('border-top','2px solid #aaa')
	end
	return cell
end

local function teamCell(tbl,k,j,i,l,colspan)
	local bg = '#F2F2F2'
	local cell = tbl:tag('td')
					:attr('rowspan',2)
					:css('border','1px solid #aaa')
	if colspan~=1 and colspan~=nil then
		cell:attr('colspan',colspan)
	end
	if k=='seed' or k=='score' then
		cell:css('text-align','center')
	end
	if k=='seed' or k=='score' or nowrap then
		cell:css('white-space', 'nowrap')
	end
	if k=='seed' then
		cell:css('border-right','2px solid #aaa')
	else
		bg='#F9F9F9'
	end
	if k=='team' then 
		cell:css('padding-left','0.3em') 
	end
	if l=='agg' then
		cell:css('border-left','2px solid #aaa')
	end	
	if (l==nil and entries[j][i]['weight']=='bold') or entries[j][i]['score']['weight'][l]=='bold' then
		cell:css('font-weight','bold')
	end
	if entries[j][i]['position']=='top' and entries[j][i-2]~=nil and entries[j][i-2]['ctype']~='blank' and entries[j][i-2]['ctype']~='text' and entries[j][i-2]['ctype']~='group' and (not byes[j][entries[j][i]['headerindex']] or not isBlankEntry(j,i-2)) then
		cell:css('border-top','2px solid #aaa')
	end
	cell:css('background-color',bg)
	if l==nil then
		cell:wikitext(entries[j][i][k])
	else
		cell:wikitext(tostring(entries[j][i][k][l]))
	end
	return cell
end

local function insertEntry(tbl,j,i)
	local entry_colspan=maxlegs[j]+2
	if not seeds then entry_colspan=entry_colspan-1	end
	if (aggregate and maxlegs[j]>1) or maxlegs[j]==0 then
		entry_colspan=entry_colspan+1
	end
	
	if entries[j][i]~=nil and entries[j][i]['ctype']=='blank' then
		return
	end
	
	if entries[j][i]==nil then
		if entries[j][i-1]~=nil or i==1 then
			local rowspan = 0
			local row = i
			repeat
				rowspan=rowspan+1
				row=row+1
			until entries[j][row]~=nil or row>r
			return blankCell(tbl,j,i,rowspan,entry_colspan)
		else
			return
		end
	end

	if entries[j][i]['ctype']=='header' then
		if byes[j][entries[j][i]['headerindex']] then
			local emptyround = true
			local row = i+1
			repeat
				if not isBlankEntry(j,row) then
					emptyround = false
				end
				row = row+1
			until (entries[j][row]~=nil and entries[j][row]['ctype']=='header') or row>r
			if emptyround == true then
				return blankCell(tbl,j,i,2,entry_colspan)
			end
		end
		
		if hide[j][entries[j][i]['headerindex']] then
			return blankCell(tbl,j,i,2,entry_colspan)
		end
		
		if isempty(entries[j][i]['header']) then
			if entries[j][i]['headerindex']==1 then
				if     j==c   then entries[j][i]['header'] = 'Final'
				elseif j==c-1 then entries[j][i]['header'] = 'Semifinals'
				elseif j==c-2 then entries[j][i]['header'] = 'Quarterfinals'
				else			   entries[j][i]['header'] = 'Round '..j
				end
			else
				entries[j][i]['header'] = 'Lower round '..j
			end
		end
		
		return headerCell(tbl,j,i,entry_colspan)
	end
	
	if entries[j][i]['ctype']=='team' then
		if byes[j][entries[j][i]['headerindex']] and isBlankEntry(j,i) then
			return blankCell(tbl,j,i,2,entry_colspan)
		end
		if hide[j][entries[j][i]['headerindex']] then
			return blankCell(tbl,j,i,2,entry_colspan)
		end
		
		local legs = rlegs[j]
		local team_colspan
		
		if notempty(entries[j][i]['legs']) then
			legs = tonumber(entries[j][i]['legs'])
		end
		if autolegs then
			local l=1
			repeat l=l+1
			until isempty(entries[j][i]['score'][l])
			legs = l-1
		end	
		team_colspan = maxlegs[j]-legs+1
		if aggregate and legs==1 and maxlegs[j]>1 then
			team_colspan=team_colspan+1
		end
		if maxlegs[j]==0 then 
			team_colspan=team_colspan+1
		end
		
		if seeds then
			if showSeeds(j,i)==true then
				teamCell(tbl,'seed',j,i)
			else
				team_colspan=team_colspan+1
			end
		end
		teamCell(tbl,'team',j,i,nil,team_colspan)
		for l=1,legs do
			teamCell(tbl,'score',j,i,l)
		end
		if aggregate and legs>1 then
			teamCell(tbl,'score',j,i,'agg')
		end
	end
	
	if entries[j][i]['ctype']=='text' then
		blankCell(tbl,j,i,2,entry_colspan,entries[j][i]['text'])
	end
	
	if entries[j][i]['ctype']=='group' then
		local colspan=0
		for m=j,entries[j][i]['colspan']+j-1 do
			colspan=colspan+maxlegs[m]+2
			if not seeds then colspan=colspan-1 end
			if (aggregate and maxlegs[m]>1) or maxlegs[m]==0 then
				colspan=colspan+1
			end
		end
		colspan = colspan+2*(entries[j][i]['colspan']-1)
		blankCell(tbl,j,i,2,colspan,entries[j][i]['group'],'center')
	end
	
	if entries[j][i]['ctype']=='line' then
		tbl:tag('td')
			:attr('rowspan',2)
			:attr('colspan',entry_colspan)
			:css('border-bottom','3px solid black')
			:wikitext(entries[j][i]['text'])
	end
end

local function isRoundHidden(j,i,headerindex)
	if notempty(entries[j][i]['pheader']) then
		hide[j][entries[j][i]['headerindex']] = false
	end
	local row = i+1
	repeat
		if not isBlankEntry(j,row) then
			hide[j][entries[j][i]['headerindex']] = false
		end
		row = row+1
	until (entries[j][row]~=nil and entries[j][row]['ctype']=='header') or row>r
end

local function paramNames(cname,j,i,l)
	local rname = {
			{'RD'..j, bargs('RD'..j..'-altname') or 'RD'..j},
			{'RD'..j..toChar(entries[j][i]['headerindex']),bargs('RD'..j..toChar(entries[j][i]['headerindex'])..'-altname') or 'RD'..j..toChar(entries[j][i]['headerindex'])}
			}
	local name = {cname, bargs(cname..'-altname') or cname}
	local index = {entries[j][i]['index'], entries[j][i]['altindex']}
	local result = {}
	if cname=='header' then
		if entries[j][i]['headerindex']==1 then 
			for k=1,2 do
				table.insert(result,bargs(rname[1][3-k]) or '')
				table.insert(result,bargs(rname[2][3-k]) or '')
			end
		else 
			for k=1,2 do
				table.insert(result,bargs(rname[2][3-k]) or '')
			end
		end
	elseif cname=='pheader' then
		if entries[j][i]['headerindex']==1 then 
			for k=1,2 do
				table.insert(result,pargs[rname[1][3-k]] or '')
				table.insert(result,pargs[rname[2][3-k]] or '')
			end
		else 
			for k=1,2 do
				table.insert(result,pargs[rname[2][3-k]] or '')
			end
		end
	elseif cname=='score' then
		for m=1,2 do for k=1,2 do
			if l==1 then
				table.insert(result,bargs(rname[3-m][3-k]..'-'..name[1]..index[3-m]) or bargs(rname[3-m][3-k]..'-'..name[1]..'0'..index[3-m]) or '')
			end
			table.insert(result,bargs(rname[3-m][3-k]..'-'..name[1]..index[3-m]..'-'..l) or bargs(rname[3-m][3-k]..'-'..name[1]..'0'..index[3-m]..'-'..l) or '')
		end	end
	elseif cname=='shade' then
		for k=1,2 do
			if entries[j][i]['headerindex']==1 then
				table.insert(result,bargs(rname[1][3-k]..'-'..name[1]) or '')
			else
				table.insert(result,bargs(rname[2][3-k]..'-'..name[1]) or '')
			end
		end
		table.insert(result,bargs('RD-shade'))
		table.insert(result,'#F2F2F2')
	elseif cname=='text' then
		for n=1,2 do for m=1,2 do for k=1,2 do
			table.insert(result,bargs(rname[3-m][3-k]..'-'..name[3-n]..index[3-m]) or bargs(rname[3-m][3-k]..'-'..name[3-n]..'0'..index[3-m]) or '')
		end end	end
	else
		for m=1,2 do for k=1,2 do
			table.insert(result,bargs(rname[3-m][3-k]..'-'..name[1]..index[3-m]) or bargs(rname[3-m][3-k]..'-'..name[1]..'0'..index[3-m]) or '')
		end	end
	end
	for k=1,#result do
		if notempty(result[k]) then
			return result[k]
		end
	end
	return ''
end

local function indexedParams(j)
	for i=1,r do
		if entries[j][i]~=nil then
			if entries[j][i]['ctype']=='team' then
				local legs = rlegs[j]
				if forceseeds then
					entries[j][i]['seed'] = bargs(masterindex) or ''
					masterindex = masterindex+1
				end
				entries[j][i]['team'] = bargs(tostring(masterindex)) or ''
				masterindex = masterindex+1
				entries[j][i]['legs'] = paramNames('legs',j,i)
				entries[j][i]['score'] = {}
				entries[j][i]['weight'] = 'normal'
				entries[j][i]['score']['weight'] = {}
				if notempty(entries[j][i]['legs']) then
					legs = tonumber(entries[j][i]['legs'])
				end
				for l=1,legs do
					entries[j][i]['score'][l] = bargs(tostring(masterindex)) or ''
					masterindex = masterindex+1
					entries[j][i]['score']['weight'][l] = 'normal'
				end
				if aggregate and legs>1 then
					entries[j][i]['score']['agg'] = bargs(masterindex) or ''
					masterindex = masterindex+1
					entries[j][i]['score']['weight']['agg'] = 'normal'
				end
			end
			if entries[j][i]['ctype']=='header' then
				entries[j][i]['header'] = paramNames('header',j,i)
				entries[j][i]['pheader'] = paramNames('pheader',j,i)
				entries[j][i]['shade'] = paramNames('shade',j,i)
			end
			if entries[j][i]['ctype']=='text' then
				entries[j][i]['text'] = bargs(tostring(masterindex)) or ''
				masterindex = masterindex+1
			end
			if entries[j][i]['ctype']=='group' then
				entries[j][i]['group'] = bargs(tostring(masterindex)) or ''
				masterindex = masterindex+1
			end
			if entries[j][i]['ctype'] == 'line' and entries[j][i]['hastext']==true then
				entries[j][i]['text'] = bargs(masterindex) or ''
				masterindex = masterindex+1
			end
		end
	end
end

local function assignParams()
	masterindex = 1
	local maxcol = 1
	local byerows = 1
	local hiderows = 1
	for j=minc,c do
		rlegs[j] = tonumber(bargs('RD'..j..'-legs')) or tonumber(bargs('legs')) or 1
		if notempty(bargs('RD'..j..'-legs')) or bargs('legs') then autolegs = false end
		if paramstyle == 'numbered' then
			indexedParams(j)
		else
			for i=1,r do
				if entries[j][i]~=nil then
					if entries[j][i]['ctype']=='team' then
						local legs = rlegs[j]
						entries[j][i]['seed'] = paramNames('seed',j,i)
						entries[j][i]['team'] = paramNames('team',j,i)
						entries[j][i]['legs'] = paramNames('legs',j,i)
						entries[j][i]['score'] = {}
						entries[j][i]['weight'] = 'normal'
						entries[j][i]['score']['weight'] = {}
						if notempty(entries[j][i]['legs']) then
							legs = tonumber(entries[j][i]['legs'])
						end
						if autolegs then
							local l=1
							repeat
								entries[j][i]['score'][l] = paramNames('score',j,i,l)
								entries[j][i]['score']['weight'][l] = 'normal'
								l=l+1
							until isempty(paramNames('score',j,i,l))
							legs = l-1
						else
							for l=1,legs do
								entries[j][i]['score'][l] = paramNames('score',j,i,l)
								entries[j][i]['score']['weight'][l] = 'normal'
							end
						end
						if aggregate and legs>1 then
							entries[j][i]['score']['agg'] = paramNames('score',j,i,'agg')
							entries[j][i]['score']['weight']['agg'] = 'normal'
						end
					end
					if entries[j][i]['ctype']=='header' then
						entries[j][i]['header'] = paramNames('header',j,i)
						entries[j][i]['pheader'] = paramNames('pheader',j,i)
						entries[j][i]['shade'] = paramNames('shade',j,i)
					end
					if entries[j][i]['ctype']=='text' then
						entries[j][i]['text'] = paramNames('text',j,i)
					end
					if entries[j][i]['ctype']=='group' then
						entries[j][i]['group'] = paramNames('group',j,i)
					end
					if entries[j][i]['ctype'] == 'line' and entries[j][i]['hastext']==true then
						entries[j][i]['text'] = paramNames('text',j,i)
					end
				end
				if autocol and not isBlankEntry(j,i) then
					maxcol = math.max(maxcol,j)
				end
			end
		end
		for i=1,r do
			if entries[j][i]~=nil and entries[j][i]['ctype']=='header' then 
				isRoundHidden(j,i) 
			end
			if entries[j][i]~=nil and not hide[j][entries[j][i]['headerindex']] then
				if not byes[j][entries[j][i]['headerindex']] or (byes[j][entries[j][i]['headerindex']] and not isBlankEntry(j,i)) then
					byerows = math.max(byerows,i)
				end
			end
		end
	end
	for j=minc,c do
		for k=1,headerindex[j] do
			if byes[j][k] or hide[j][k] then
				r=byerows+1
			end
		end
	end
	if autocol then
		c = maxcol
	end
end

local function getHide(j,headerindex)
	hide[j] = {}
	for k=1,headerindex[j] do
		if bargs('RD'..j..toChar(k)..'-hide')=='yes' or bargs('RD'..j..toChar(k)..'-hide')=='y' then
			hide[j][k]=true
		end
	end
end

local function getByes(j,headerindex)
	byes[j] = {}
	for k=1,headerindex[j] do
		if bargs('byes')=='yes' or bargs('byes')=='y' then
			byes[j][k]=true else byes[j][k]=false
		end
		if bargs('RD'..j..'-byes')=='yes' or bargs('RD'..j..'-byes')=='y' then
			byes[j][k]=true
		elseif bargs('RD'..j..'-byes')=='no' or bargs('RD'..j..'-byes')=='n' then
			byes[j][k]=false
		end
		if bargs('RD'..j..toChar(k)..'-byes')=='yes' or bargs('RD'..j..toChar(k)..'-byes')=='y' then
			byes[j][k]=true
		elseif bargs('RD'..j..'-byes')=='no' or bargs('RD'..j..'-byes')=='n' then
			byes[j][k]=false
		end
	end
end

local function getAltIndices()
	local teamindex=1
	local textindex=1
	local groupindex=1
	for j=minc,c do
		headerindex[j]=0
		for i=1,r do
			if entries[j][i]==nil and i==1 then
				headerindex[j]=headerindex[j]+1
			end
			if entries[j][i]~=nil then
				if entries[j][i]['ctype'] == 'header' then
					entries[j][i]['altindex'] = headerindex[j]
					teamindex=1
					textindex=1
					headerindex[j]=headerindex[j]+1
				elseif entries[j][i]['ctype'] == 'team' then
					entries[j][i]['altindex'] = teamindex
					teamindex=teamindex+1
				elseif entries[j][i]['ctype'] == 'text' then
					entries[j][i]['altindex'] = textindex
					textindex=textindex+1
				elseif entries[j][i]['ctype'] == 'group' then
					entries[j][i]['altindex'] = groupindex
					groupindex=groupindex+1
				elseif entries[j][i]['ctype'] == 'line' and entries[j][i]['hastext']==true then
					entries[j][i]['altindex'] = textindex
					textindex=textindex+1
				end
				entries[j][i]['headerindex'] = headerindex[j]
			end
		end
		getByes(j,headerindex)
		getHide(j,headerindex)
	end
end

local function pathCell(tbl,j,i,k,a,b,c,bg,rowspan)
	if not hascross[j] and k==2 then return end
	if pathcolor==nil then pathcolor='black' end
	local cell=tbl:tag('td')
	if rowspan~=1 then
		cell:attr('rowspan',rowspan)
	end
	if notempty(bg[k]) then
		cell:css('background',bg[k])
	end
	if a[k][1]~=0 or a[k][2]~=0 or a[k][3]~=0 or a[k][4]~=0 then
		cell:css('border','solid black')
			:css('border-width',a[k][1]..'px '..a[k][2]..'px '..a[k][3]..'px '..a[k][4]..'px')
	end
	if c[k][2]~=0 then
		cell:css('border-right',c[k][2]..'px solid '..pathcolor)
	end
	if b[k][2]~=0 then
		cell:css('box-shadow', '0px '..b[k][2]..'px 0px '..pathcolor)
	end
	if c[k][4]~=0 then
		cell:css('border-left',c[k][4]..'px solid '..pathcolor)
	end
	return cell
end

local function insertPath(tbl,j,i)
	local function createCross(angle,color,percent)
		local result = 'linear-gradient('..angle..', transparent calc('..percent..'% - 1px),'..color..' calc('..percent..'% - 1px),'..color..' calc('..percent..'% + 1px), transparent calc('..percent..'% + 1px))'
		return result
	end
	local colspan = 2
	if hascross[j] then colspan = 3 end
	
	if pathEntries['black'][j][i]=='blank' then return end
	
	if isempty(pathEntries['black'][j][i]) and isempty(pathEntries['color'][j][i]) then
		if (pathEntries['black'][j][i-1]~='blank' and notempty(pathEntries['black'][j][i-1])  and (pathEntries['black'][j][i-1]['cross'][1] == 1 or pathEntries['black'][j][i-1]['cross'][2] == 1)) or (notempty(pathEntries['color'][j][i-1]) and (pathEntries['color'][j][i-1]['cross'][1] == 1 or pathEntries['color'][j][i-1]['cross'][2] == 1)) then
			return
		else
			local cell = tbl:tag('td')
			for k=1,colspan-1 do
				cell:tag('td')
			end
			return cell
		end
	end
	
	for key,_ in pairs(pathEntries) do
		if notempty(pathEntries[key][j]) and notempty(pathEntries[key][j][i-1]) and pathEntries[key][j][i-1]~='blank' then
			if pathEntries[key][j][i-1]['cross'][1]==1 or pathEntries[key][j][i-1]['cross'][2]==1 then return end
		end
	end
	
	local a = {}
	local b = {}
	local c = {}
	local bg = {}
	local cross = {}
	local rowspan = 1
	
	for k=1,3 do
		a[k]={0,0,0,0}
		b[k]={0,0}
		c[k]={0,0,0,0}
		bg[k] = ''
		cross[k] = {}
		for n=1,2 do
			cross[k][n] = ''
		end
	end
	
	for key,_ in pairs(pathEntries) do
		local color
		if key=='black' then color='black' else color=pathcolor end
		if notempty(pathEntries[key][j]) and notempty(pathEntries[key][j][i]) then
			if key=='black' then
				a[1][3] = 3*pathEntries['black'][j][i]['out'][1]
				a[2][3] = 3*pathEntries['black'][j][i]['mid'][1]
				a[3][3] = 3*pathEntries['black'][j][i]['in'][1]
				a[1][2] = 2*pathEntries['black'][j][i]['out'][2]
				a[3][4] = 2*pathEntries['black'][j][i]['in'][2]
			else
				if pathEntries['color'][j][i]['out'][3]=='below' then
					b[1][2] = 4*pathEntries['color'][j][i]['out'][1] 
				end
				if pathEntries['color'][j][i]['mid'][3]=='below' then
					b[2][2] = 4*pathEntries['color'][j][i]['mid'][1]
				end
				if pathEntries['color'][j][i]['in'][3]=='below' then
					b[3][2] = 4*pathEntries['color'][j][i]['in'][1]
				end
				c[1][2] = 2*pathEntries['color'][j][i]['out'][2]
				c[3][4] = 2*pathEntries['color'][j][i]['in'][2]
			end
			if pathEntries[key][j][i]['cross'][1]==1 or pathEntries[key][j][i]['cross'][2]==1 then
				rowspan = 2
				if pathEntries[key][j][i]['cross'][1]==1 then
					cross[1][1] = createCross('65.5deg',color,100)
					cross[2][1] = createCross('to top right',color,50)
					cross[3][1] = createCross('245.5deg',color,100)
				end
				if pathEntries[key][j][i]['cross'][2]==1 then
					cross[1][2] = createCross('114.4deg',color,100)
					cross[2][2] = createCross('to bottom right',color,50)
					cross[3][2] = createCross('294.4deg',color,100)
				end
			end
		end
	end
	if notempty(pathEntries['color'][j]) and notempty(pathEntries['color'][j][i-1]) then
		if pathEntries['color'][j][i]['out'][3]=='above' then
			b[1][2] = -4
		end
		if pathEntries['color'][j][i]['mid'][3]=='above' then
			b[2][2] = -4
		end
		if pathEntries['color'][j][i]['in'][3]=='above' then
			b[3][2] = -4
		end
	end
	if notempty(cross[2][1]) and notempty(cross[2][2]) then
		for k=1,3 do cross[k][1] = cross[k][1]..',' end
	end
	for k=1,3 do
		bg[k] = cross[k][1]..cross[k][2]
	end
	
	for k=1,3 do
		pathCell(tbl,j,i,k,a,b,c,bg,rowspan)
	end
end

local function getPaths()
	local paths = {}
	pathEntries['black'] = {}
	pathEntries['color'] = {}
	for j=minc,c-1 do
		pathEntries['black'][j] = {}
		pathEntries['color'][j] = {}
		for i=1,r do
			pathEntries['black'][j][i] = {['out']={0,0,nil},['mid']={0,0,nil},['in']={0,0,nil},['cross']={0,0,nil}}
			pathEntries['color'][j][i] = {['out']={0,0,nil},['mid']={0,0,nil},['in']={0,0,nil},['cross']={0,0,nil}}
		end
		paths[j] = {}
		hascross[j] = false
		local crossloc = split((fargs['col'..j..'-col'..(j+1)..'-cross'] or ''):gsub("%s+", ""),{","},true)
		local str = fargs['col'..j..'-col'..(j+1)..'-paths'] or ''
		for val in str:gsub("%s+","")
					:gsub(",",", ")
					:gsub("%S+","\0%0\0")
					:gsub("%b()", function(s) return s:gsub("%z","") end)
					:gmatch("%z(.-)%z") do
			local result = split(val:gsub("%s+",""):gsub("%)",""):gsub("%(",""),{"-"})
			for k,_ in pairs(result) do
				result[k] = split(result[k],{","})
			end
			if notempty(result[2]) then
				for m=1,#result[2] do
					result[3] = {}
					result[2][m] = split(result[2][m],{":"})
					result[3][m] = result[2][m][2]
					result[2][m] = result[2][m][1]
				end
				for n=1,#result[1] do
					for m=1,#result[2] do
						table.insert(paths[j],{tonumber(result[1][n]),tonumber(result[2][m]),['color']=result[3][m]})
					end
				end
			end
		end
		if shift[j]~=0 and notempty(crossloc[1]) then
			for n=1,#crossloc do
				crossloc[n] = crossloc[n]+shift[j]
			end
		end
		for k,v in ipairs(paths[j]) do
			local color
			local hidepath = false
			if shift[j]~=0 then
				paths[j][k][1] = paths[j][k][1]+shift[j]
			end
			if shift[j+1]~=0 then
				paths[j][k][2] = paths[j][k][2]+shift[j+1]
			end
			local start = 2*paths[j][k][1]+(teams_per_match[j]-2)
			local mid = {}
			if notempty(crossloc[1]) then
				for n=1,#crossloc do
					mid[n] = 2*crossloc[n]+(teams_per_match[j]-2)
				end
			else
				mid[1]=0
			end
			local stop = 2*paths[j][k][2]+(teams_per_match[j+1]-2)
			if paths[j][k]['color']~=nil then 
				pathcolor = paths[j][k]['color']
				color = 'color'
			else
				color = 'black'
			end
			if notempty(entries[j][start-1]) and (byes[j][entries[j][start-1]['headerindex']] and isBlankEntry(j,start-1) and isBlankEntry(j,start+1) or hide[j][entries[j][start-1]['headerindex']]) then
				if bargs('show-bye-paths')~='y' and bargs('show-bye-paths')~='yes' then
					hidepath=true
				end
			end
			if notempty(entries[j+1][stop-1]) and (byes[j+1][entries[j+1][stop-1]['headerindex']] and isBlankEntry(j+1,stop-1) and isBlankEntry(j+1,stop+1) or hide[j+1][entries[j+1][stop-1]['headerindex']])then
				if bargs('show-bye-paths')~='y' and bargs('show-bye-paths')~='yes' then
					hidepath=true
				end
			end
			if bargs('RD'..j..'-RD'..(j+1)..'-path')=='n' or bargs('RD'..j..'-RD'..(j+1)..'-path')=='no' or bargs('RD'..j..'-RD'..(j+1)..'-path')=='0' then
				if notempty(entries[j][start-1]) and entries[j][start-1]['headerindex']==1 then
					hidepath=true
				end
			end
			
			local cross = 0
			for n=1,#mid do
				if (start<stop and mid[n]<stop and mid[n]>start) or (start>stop and mid[n]>stop and mid[n]<start) then
					hascross[j]=true
					cross = mid[n]
				end
			end
			if not hidepath then
				if start==stop then
					if start>r then break end
					start = math.min(start,r)
					pathEntries[color][j][start]['out'][1] = 1
					pathEntries[color][j][start]['in'][1] = 1
					if cross==0 then
						pathEntries[color][j][start]['mid'][1] = 1
					end
				elseif start<stop then
					if stop>r then break end
					pathEntries[color][j][start]['out'][1] = 1
					pathEntries[color][j][stop]['in'][1] = 1
					pathEntries[color][j][stop]['in'][2] = 1
					if color~='black' then
						pathEntries[color][j][start]['out'][3] = 'below'
						pathEntries[color][j][stop+1]['in'][3] = 'above'
					end
					if cross==0 then
						pathEntries[color][j][start]['mid'][1] = 1
						pathEntries[color][j][start]['mid'][3] = 'below'
						for i=start+1,stop-1 do pathEntries[color][j][i]['in'][2] = 1 end
					else
						pathEntries[color][j][cross]['cross'][1] = 1
						for i=start+1,cross-1 do pathEntries[color][j][i]['out'][2] = 1 end
						for i=cross+2,stop-1 do pathEntries[color][j][i]['in'][2] = 1 end
					end
				elseif start>stop then
					if start>r then break end
					pathEntries[color][j][stop]['in'][1] = 1
					if cross==0 then
						for i=stop+1,start-1 do pathEntries[color][j][i]['in'][2] = 1 end
						pathEntries[color][j][start]['out'][1] = 1
						pathEntries[color][j][start]['mid'][1] = 1
						pathEntries[color][j][start]['in'][2] = 1
						if color~='black' then
							pathEntries[color][j][start+1]['out'][3] = 'above'
							pathEntries[color][j][start+1]['mid'][3] = 'above'
							pathEntries[color][j][stop]['in'][3] = 'below'
						end
					else
						pathEntries[color][j][cross]['cross'][2] = 1
						for i=stop+1,cross-1 do pathEntries[color][j][i]['in'][2] = 1 end
						for i=cross+2,start-1 do pathEntries[color][j][i]['out'][2] = 1 end
						pathEntries[color][j][start]['out'][1] = 1
						pathEntries[color][j][start]['out'][2] = 1
						if color~='black' then
							pathEntries[color][j][start+1]['out'][3] = 'above'
							pathEntries[color][j][stop]['in'][3] = 'below'
						end
					end
				end
			end
		end
	end
	for j=minc,c-1 do
		for i=1,r do
			local empty = true
			for key,_ in pairs(pathEntries) do
				for k,v in pairs(pathEntries[key][j][i]) do
					if v[1]~=0 or v[2]~=0 or v[3]~=nil then
						empty = false
					end
				end
				if empty then pathEntries[key][j][i] = nil end
			end
		end
	end
	for j=minc,c-1 do
		if notempty(pathEntries['black'][j]) and notempty(pathEntries['black'][j+1]) then
			for i=1,r do
				if (entries[j+1][i-1]==nil or (byes[j+1][entries[j+1][i-1]['headerindex']]) and isBlankEntry(j+1,i-1)) and notempty(pathEntries['black'][j][i]) and notempty(pathEntries['black'][j+1][i]) then
					if pathEntries['black'][j][i]['in'][1]==1 and pathEntries['black'][j+1][i]['out'][1]==1 then
						entries[j+1][i-1]={['ctype']='line'}
						entries[j+1][i]={['ctype']='blank'}
					end
				end
			end
		end
	end
end

local function getGroups()
	local function check(j,i)
		local result=false
		if entries[j][i] == nil then
			if entries[j][i+1] == nil then 
				result=true 
			elseif entries[j][i+1]['ctype']=='text' and isBlankEntry(j,i+1) then
				result=true
			end
		elseif entries[j][i]['ctype']=='text' and isBlankEntry(j,i) then
			result=true
		end
		return result
	end
	for j=minc,c-1 do
		if teams_per_match[j]==2 then
			local n=0
			for i=1,r do
				if (notempty(pathEntries['black'][j][i]) and pathEntries['black'][j][i]['in'][1] == 1) or (notempty(pathEntries['color'][j][i]) and pathEntries['color'][j][i]['in'][1] == 1) then
					n=n+1
					if check(j,i) then
						local k=minc-1
						repeat
							if entries[j-k][i+1]~=nil and entries[j-k][i+1]['ctype']=='text' and isBlankEntry(j-k,i+1) then
								entries[j-k][i+2]=nil
							end
							entries[j-k][i]={['ctype']='blank'}
							entries[j-k][i+1]={['ctype']='blank'}
							if k>0 and isempty(pathEntries['black'][j-k][i]) and isempty(pathEntries['color'][j-k][i]) then
								pathEntries['black'][j-k][i] = 'blank'
								pathEntries['black'][j-k][i+1] = 'blank'
							end
							k=k+1
						until k>j-1 or not check(j-k,i) or notempty(pathEntries['black'][j-k][i]) or notempty(pathEntries['color'][j-k][i])
						k=k-1
						entries[j-k][i]={['ctype']='group',['index']=n,['colspan']=k+1}
						entries[j-k][i+1]={['ctype']='blank'}
						entries[j-k][i]['group'] = bargs('RD'..j..'-group'..n)
					end
				end
			end
		end
	end
end

local function getCells()
	local maxrow = 1
	local colentry = {}
	local bool = true
	for j=minc,c do
		if notempty(fargs['col'..j..'-headers']) then bool=false end
		teams_per_match[j] = tonumber(fargs['RD'..j..'-teams-per-match']) or tonumber(fargs['col'..j..'-teams-per-match']) or tonumber(fargs['teams-per-match']) or 2
		maxtpm = math.max(maxtpm,teams_per_match[j])
	end
	for j=minc,c do
		entries[j] = {}
		shift[j] = tonumber(bargs('RD'..j..'-shift')) or tonumber(bargs('shift')) or 0
		colentry[j] = {
			split((fargs['col'..j..'-headers'] or ''):gsub("%s+", ""),{","},true),
			split((fargs['col'..j..'-matches'] or ''):gsub("%s+", ""),{","},true),
			split((fargs['col'..j..'-lines'] or ''):gsub("%s+", ""),{","},true),
			split((fargs['col'..j..'-text'] or ''):gsub("%s+", ""),{","},true),
		}
		if bool==true and fargs['noheaders']~='y' and fargs['noheaders']~='yes' then
			table.insert(colentry[j][1],1)
		end
	end

	for j=minc,c do
		local textindex=0
		for k,v in ipairs(colentry[j]) do
			table.sort(colentry[j][k])
			local ctype
			if k==1 then ctype='header'
			elseif k==2 then ctype='team'
			elseif k==3 then ctype='line'
			elseif k==4 then ctype='text'
			elseif k==5 then ctype='group'
			end
			for n=1,#colentry[j][k] do
				if shift[j]~=0 and colentry[j][k][n]>1 then
					colentry[j][k][n] = colentry[j][k][n]+shift[j]
				end
				local i=2*colentry[j][k][n]-1
				maxrow = math.max(i+2*teams_per_match[j]-1,maxrow)
				if ctype=='team' then
					if entries[j][i-1]==nil and entries[j][i-2]==nil then
						entries[j][i-2]={['ctype']='text',['index']=n}
						entries[j][i-1]={['ctype']='blank'}
						textindex=n
					end
					entries[j][i]={['ctype']=ctype,['index']=teams_per_match[j]*n-(teams_per_match[j]-1),['position']='top'}
					entries[j][i+1]={['ctype']='blank'}
					for m=2,teams_per_match[j] do
						entries[j][i+2*(m-1)]={['ctype']=ctype,['index']=teams_per_match[j]*n-(teams_per_match[j]-m)}
						entries[j][i+2*(m-1)+1]={['ctype']='blank'}
					end
				elseif ctype=='text' then
					entries[j][i]={['ctype']=ctype,['index']=textindex+n}
					entries[j][i+1]={['ctype']='blank'}
				elseif ctype=='line' then
					entries[j][i]={['ctype']=ctype}
					entries[j][i+1]={['ctype']='blank'}
				elseif ctype=='group' then
					entries[j][i]={['ctype']=ctype,['index']=n}
					entries[j][i+1]={['ctype']='blank'}
				else
					entries[j][i]={['ctype']=ctype,['index']=n,['position']='top'}
					entries[j][i+1]={['ctype']='blank'}
				end
			end
		end
	end
	if isempty(r) then
		r = maxrow
	end
end

function p.main(frame)
	fargs = frame.args
	pargs = frame:getParent().args;
	
	r = tonumber(fargs.rows) or ''
	c = tonumber(fargs.rounds) or 1
	maxc = tonumber(pargs.maxrounds) or tonumber(pargs.maxround) or ''
	minc = tonumber(pargs.minround) or 1
	headerindex = {}
	if notempty(maxc) then c=maxc end
	if fargs.autocol=='yes' or fargs.autocol=='y' then autocol=true end
	local colspacing = tonumber(fargs['col-spacing']) or 5
	
	maxtpm = 1
	seeds = true
	forceseeds = false
	boldwinner = bargs('boldwinner') or ''
	if bargs('seeds')=='y' or bargs('seeds')=='yes' then forceseeds=true end
	if bargs('seeds')=='n' or bargs('seeds')=='no' then seeds=false end
	if bargs('aggregate')=='y' or bargs('aggregate')=='yes' then aggregate=true end
	if bargs('autolegs')=='y' or bargs('autolegs')=='yes' then autolegs=true end
	if bargs('nowrap')=='y' or bargs('nowrap')=='yes' then nowrap=true end
	if bargs('paramstyle')=='numbered' then 
		paramstyle = 'numbered'
	else
		paramstyle = 'indexed'
	end
	
	getCells()
	getAltIndices()
	assignParams()
	matchGroups()
	if (boldwinner=='yes' or boldwinner=='y' or boldwinner=='high') then boldWinner() end
	getPaths()
	if minc==1 then
	getGroups()
	end
	
	for j=minc,c do
		maxlegs[j] = rlegs[j]
		for i=1,r do
			if notempty(entries[j][i]) then
				if notempty(entries[j][i]['legs']) then
					maxlegs[j] = math.max(rlegs[j],entries[j][i]['legs'])
				end
				if autolegs then
					local l=1
					repeat l=l+1
					until isempty(entries[j][i]['score']) or isempty(entries[j][i]['score'][l])
					maxlegs[j] = math.max(maxlegs[j],l-1)
				end
			end
		end
	end
	
	local tbl = mw.html.create('table')
			:attr('cellpadding','0')
			:attr('cellspacing','0')
			:css('font-size','90%')
			:css('border-collapse','collapse')
			:css('margin','1em 2em 1em 1em')
	
	tbl:tag('tr'):css('visibility','collapse')
	tbl:tag('td'):css('width','1px')
	for j=minc,c do
		if seeds then
			tbl:tag('td'):css('width',getWidth('seed','25px'))
		end
		tbl:tag('td'):css('width',getWidth('team','150px'))
		if maxlegs[j]==0 then
			tbl:tag('td'):css('width',getWidth('score','25px'))
			else
			for l=1,maxlegs[j] do
				tbl:tag('td'):css('width',getWidth('score','25px'))
			end
		end
		if aggregate and maxlegs[j]>1 then
			tbl:tag('td'):css('width',getWidth('score','25px'))
		end
		if j~=c then
			if hascross[j] then
				tbl:tag('td'):css('width',colspacing..'px')
				tbl:tag('td'):css('width','10px')
				tbl:tag('td'):css('width',colspacing..'px')
			else
				tbl:tag('td'):css('width',colspacing..'px')
				tbl:tag('td'):css('width',colspacing..'px')
			end
		end
	end
	
	for i=1,r do
		local row = tbl:tag('tr')
		row:tag('td'):css('height','11px')
		for j=minc,c do
			insertEntry(row,j,i)
			if j~=c then
				insertPath(row,j,i)
			end
		end
	end
			
	return tostring(tbl)
end

return p