Module:Build bracket
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(&quot;a&quot;)+num-1)
 end
 
 local function split(str,delim,tonum)
 	result = {};
 	local a = &quot;[^&quot;..table.concat(delim)..&quot;]+&quot;
 		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 teamLegs(j,i)
 	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
 	return legs
 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]:gsub('%W','')
 			if myscore == &quot;&quot; or myscore:find(&quot;%D&quot;) 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
 					local theirscore = entries[j][k]['score'][l] or ''
 					theirscore = theirscore:gsub('%W','')
 					if theirscore== &quot;&quot; or theirscore:find(&quot;%D&quot;) then return 'normal'
 						else table.insert(compscore,tonumber(theirscore)) end
 				end
 			end
 			for k,v in pairs(compscore) do
 				if myscore&lt;=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 boldTeam(j,i,agg)
 		local wins
 		local legs = teamLegs(j,i)
 		if agg~=true then
 			wins = 'wins'
 			if entries[j][i][wins]&gt;legs/2 then 
 				return 'bold' 
 			end
 			if autolegs then
 				for l=1,legs do
 					if notempty(entries[j][i]['score'][l]) and string.find(entries[j][i]['score'][l],&quot;nbsp&quot;) then 
 						return 'normal' 
 					end
 				end
 			else
 				for l=1,legs do
 					if isempty(entries[j][i]['score'][l]) or string.find(entries[j][i]['score'][l],&quot;nbsp&quot;) then 
 						return 'normal' 
 					end
 				end
 			end
 		else 
 			wins = 'aggwins'
 		end
 		
 		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 entries[j][i][wins]&lt;=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 = teamLegs(j,i)
 				for l=1,legs do
 					entries[j][i]['score']['weight'][l] = boldScore(j,i,l)
 				end
 				if aggregate and legs&gt;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 = teamLegs(j,i)
 				if aggregate and legs&gt;1 then agg=true end
 				entries[j][i]['weight'] = boldTeam(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]&gt;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&gt;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&gt;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 = teamLegs(j,i)
 		local team_colspan
 		
 		team_colspan = maxlegs[j]-legs+1
 		if aggregate and legs==1 and maxlegs[j]&gt;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&gt;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]&gt;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&gt;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&gt;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&gt;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(&quot;%s+&quot;, &quot;&quot;),{&quot;,&quot;},true)
 		local str = fargs['col'..j..'-col'..(j+1)..'-paths'] or ''
 		for val in str:gsub(&quot;%s+&quot;,&quot;&quot;)
 					:gsub(&quot;,&quot;,&quot;, &quot;)
 					:gsub(&quot;%S+&quot;,&quot;\0%0\0&quot;)
 					:gsub(&quot;%b()&quot;, function(s) return s:gsub(&quot;%z&quot;,&quot;&quot;) end)
 					:gmatch(&quot;%z(.-)%z&quot;) do
 			local result = split(val:gsub(&quot;%s+&quot;,&quot;&quot;):gsub(&quot;%)&quot;,&quot;&quot;):gsub(&quot;%(&quot;,&quot;&quot;),{&quot;-&quot;})
 			for k,_ in pairs(result) do
 				result[k] = split(result[k],{&quot;,&quot;})
 			end
 			if notempty(result[2]) then
 				for m=1,#result[2] do
 					result[3] = {}
 					result[2][m] = split(result[2][m],{&quot;:&quot;})
 					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&lt;stop and mid[n]&lt;stop and mid[n]&gt;start) or (start&gt;stop and mid[n]&gt;stop and mid[n]&lt;start) then
 					hascross[j]=true
 					cross = mid[n]
 				end
 			end
 			if not hidepath then
 				if start==stop then
 					if start&gt;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&lt;stop then
 					if stop&gt;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&gt;stop then
 					if start&gt;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&gt;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&gt;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(&quot;%s+&quot;, &quot;&quot;),{&quot;,&quot;},true),
 			split((fargs['col'..j..'-matches'] or ''):gsub(&quot;%s+&quot;, &quot;&quot;),{&quot;,&quot;},true),
 			split((fargs['col'..j..'-lines'] or ''):gsub(&quot;%s+&quot;, &quot;&quot;),{&quot;,&quot;},true),
 			split((fargs['col'..j..'-text'] or ''):gsub(&quot;%s+&quot;, &quot;&quot;),{&quot;,&quot;},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]&gt;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]&gt;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