Module:Build bracket/sandbox explained

local p = local entries = local pathCell = local crossCell = local skipPath = local shift = local hascross = local teams_per_match = local rlegs = local maxlegs = local autolegslocal byes = local hide = local matchgroup = local nowraplocal autocollocal seedslocal forceseedslocal boldwinnerlocal aggregatelocal paramstylelocal 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 unboldParenthetical(text) -- Replace wikilinks with unique placeholders local counter = 0 local placeholders = text = text:gsub('%[%[(.-)%]%]', function(link) counter = counter + 1 local placeholder = '__WIKILINK__' .. counter .. '__' placeholders[placeholder] = link return placeholder end)

-- Apply

to parenthetical and bracketed text text = text:gsub('(%b)', '%1') :gsub('(%b[])', '%1')

-- Restore the original wikilinks for placeholder, link in pairs(placeholders) do text = text:gsub(placeholder, '' .. link .. '') end

return textend

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 resultend

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 endend

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 legsend

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

"" 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 local theirscore = entries[j][k]['score'][l] or theirscore = theirscore:gsub('%W',) if theirscore

"" or theirscore:find("%D") then return 'normal' else table.insert(compscore,tonumber(theirscore)) 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 boldTeam(j,i,agg) local wins local legs = teamLegs(j,i) if agg~=true then wins = 'wins' if entries[j][i][wins]>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],"nbsp") 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],"nbsp") 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]<=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>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>1 then agg=true end entries[j][i]['weight'] = boldTeam(j,i,agg) end end endend

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 falseend

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 showseedend

local function cellBorder(b) return b[1]..'px '..b[2]..'px '..b[3]..'px '..b[4]..'px'end

local function Cell(tbl,j,i,rowspan,colspan,text,align,border,border_width,bg,padding,weight,nwrap) 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(border) then cell:css('border',border) end if notempty(border_width) then cell:css('border-width',cellBorder(border_width)) end if notempty(bg) then cell:css('background-color',bg) end if notempty(align) then cell:css('text-align',align) end cell:css('padding','0em 0.3em') if weight

'bold' then cell:css('font-weight',weight) end if notempty(text) then cell:wikitext(text) end return cellend

local function teamCell(tbl,k,j,i,l,colspan) local bg = '#F2F2F2' local align local padding local weight local text local nwrap local b= if k

'seed' or k

'score' then align='center' end if k~='seed' then bg='#F9F9F9' end if k

'team' then padding='0.3em' if teamLegs(j,i)

0 then b[2]=1 end end if entries[j][i]['position']

'top' then b[1]=1 end if l

teamLegs(j,i) or l

'agg' or k

'seed' then b[2]=1 end if (l

nil and entries[j][i]['weight']

'bold') or entries[j][i]['score']['weight'][l]

'bold' then weight='bold' end if l

nil then text=unboldParenthetical(entries[j][i][k]) else text=tostring(entries[j][i][k][l]) end return Cell(tbl,j,i,2,colspan,text,align,'solid #aaa',b,bg,padding,weight,nwrap)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 Cell(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 Cell(tbl,j,i,2,entry_colspan) end end if hide[j][entries[j][i]['headerindex']] then return Cell(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 Cell(tbl,j,i,2,entry_colspan,entries[j][i]['header'],'center','1px solid #aaa',nil,entries[j][i]['shade']) end if entries[j][i]['ctype']

'team' then if (byes[j][entries[j][i]['headerindex']] and isBlankEntry(j,i)) or hide[j][entries[j][i]['headerindex']] then return Cell(tbl,j,i,2,entry_colspan) end local legs = teamLegs(j,i) local 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 Cell(tbl,j,i,2,entry_colspan,entries[j][i]['text'],nil,nil,nil,nil,'0.3em') 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) return Cell(tbl,j,i,2,colspan,entries[j][i]['group'],'center') end if entries[j][i]['ctype']

'line' then local b= b[3]=2*pathCell[j-1][i+1][3][1][3] return Cell(tbl,j,i,2,entry_colspan,entries[j][i]['text'],nil,'solid black',b) end if entries[j][i]['ctype']

'line2' then local b= b[1]=2*pathCell[j-1][i][3][1][1] return Cell(tbl,j,i,2,entry_colspan,entries[j][i]['text'],nil,'solid black',b) endend

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>rend

local function paramNames(cname,j,i,l) local rname = local name = local index = 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 endend

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 endend

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 endend

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 elseif tonumber(bargs('byes')) then if j<=tonumber(bargs('byes')) then byes[j][k]=true end 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 endend

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) endend

local function noPaths(j,i) local result = true local cols = 2 if hascross[j]

true then cols = 3 end for k=1,cols do for n=1,4 do if pathCell[j][i][k][1][n]~=0 then result = false return result end end end if hascross[j]

true and (crossCell[j][i]['left'][1]

1 or crossCell[j][i]['right'][1]

1) then result = false return result end return resultend

local function generatePathCell(tbl,j,i,k,bg,rowspan) local color = pathCell[j][i][k]['color'] if not hascross[j] and k

2 then return end local cell=tbl:tag('td') local a=pathCell[j][i] if rowspan~=1 then cell:attr('rowspan',rowspan) end if notempty(bg) and k

2 then cell:css('background',bg) :css('transform','translate(-1px)') end if a[k][1][1]~=0 or a[k][1][2]~=0 or a[k][1][3]~=0 or a[k][1][4]~=0 then cell:css('border','solid '..color) :css('border-width',2*a[k][1][1]..'px '..2*a[k][1][2]..'px '..2*a[k][1][3]..'px '..2*a[k][1][4]..'px') end return cellend

local function insertPath(tbl,j,i) if skipPath[j][i] then return end

local colspan = 2 local rowspan = 1 local angle = 58.2 local pathcolor local bg = local cross = if ir-1 or skipPath[j][a] then return false end for k=1,3 do for n=1,4 do if pathCell[j][i][k][1][n]~=pathCell[j][a][k][1][n] then return false end end end return true end if repeatedPath(i) then local row=i repeat if row~=i and repeatedPath(row) then skipPath[j][row]=true end rowspan=rowspan+1 row=row+1 until row>r or not repeatedPath(row) rowspan=rowspan-1 end end if i>1 and (crossCell[j][i-1]['left'][1]

1 or crossCell[j][i-1]['right'][1]

1) then return end if hascross[j] then colspan = 3 if crossCell[j][i]['left'][1]

1 or crossCell[j][i]['right'][1]

1 then rowspan = 2 if crossCell[j][i]['left'][1]

1 then cross[1] = 'linear-gradient(to top right, transparent calc(50% - 1px),'..crossCell[j][i]['left'][2]..' calc(50% - 1px),'..crossCell[j][i]['left'][2]..' calc(50% + 1px), transparent calc(50% + 1px))' end if crossCell[j][i]['right'][1]

1 then cross[2] = 'linear-gradient(to bottom right, transparent calc(50% - 1px),'..crossCell[j][i]['right'][2]..' calc(50% - 1px),'..crossCell[j][i]['right'][2]..' calc(50% + 1px), transparent calc(50% + 1px))' end end if notempty(cross[1]) and notempty(cross[2]) then cross[1] = cross[1]..',' end bg = cross[1]..cross[2] end for k=1,3 do generatePathCell(tbl,j,i,k,bg,rowspan) endend

local function parsePaths(j) local result= 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 array = split(val:gsub("%s+",""):gsub("%)",""):gsub("%(",""),) for k,_ in pairs(array) do array[k] = split(array[k],) end if notempty(array[2]) then for m=1,#array[2] do array[3] = array[2][m] = split(array[2][m],) array[3][m] = array[2][m][2] array[2][m] = array[2][m][1] end for n=1,#array[1] do for m=1,#array[2] do table.insert(result,) end end end end return resultend

local function isPathHidden(j,i,start,stop) local result=false 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 result=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 result=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 result=true end end return resultend

local function getPaths local paths = for j=minc,c-1 do hascross[j] = false if notempty(fargs['col'..j..'-col'..(j+1)..'-cross']) then hascross[j] = true end end for j=minc,c-1 do local straightpaths = local outpaths = local inpaths = paths[j]=parsePaths(j) pathCell[j] = crossCell[j] = skipPath[j] = for i=1,r do pathCell[j][i] = crossCell[j][i] = for k=1,3 do pathCell[j][i][k] = end skipPath[j][i] = false end local crossloc = split((fargs['col'..j..'-col'..(j+1)..'-cross'] or ):gsub("%s+", ""),,true) 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 start = 2*(paths[j][k][1]+shift[j])+(teams_per_match[j]-2) local stop = 2*(paths[j][k][2]+shift[j+1])+(teams_per_match[j+1]-2) local mid = local cross = 0 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 for n=1,#mid do if (startstart) or (start>stop and mid[n]>stop and mid[n]

stop then table.insert(straightpaths,) elseif startr then break end pathCell[j][start+1][1][1][1] = 1 pathCell[j][start+1][1]['color'] = paths[j][k]['color'] if cross

0 then if hascross[j] then pathCell[j][start+1][2][1][1] = 1 pathCell[j][start+1][2]['color'] = paths[j][k]['color'] for i=start+1,stop do pathCell[j][i][2][1][2] = 1 pathCell[j][i][2]['color'] = paths[j][k]['color'] end else for i=start+1,stop do pathCell[j][i][1][1][2] = 1 pathCell[j][i][1]['color'] = paths[j][k]['color'] end end else crossCell[j][cross]['left'] = for i=start+1,cross-1 do pathCell[j][i][1][1][2] = 1 pathCell[j][i][1]['color'] = paths[j][k]['color'] end for i=cross+2,stop do pathCell[j][i][2][1][2] = 1 pathCell[j][i][2]['color'] = paths[j][k]['color'] end end pathCell[j][stop][3][1][3] = 1 pathCell[j][stop][3]['color'] = paths[j][k]['color'] elseif start>stop then if start>r then break end pathCell[j][stop+1][3][1][1] = 1 pathCell[j][stop+1][3]['color'] = paths[j][k]['color'] if cross

0 then if hascross[j] then for i=stop+1,start do pathCell[j][i][2][1][2] = 1 pathCell[j][i][2]['color'] = paths[j][k]['color'] end pathCell[j][start][2][1][3] = 1 pathCell[j][start][2]['color'] = paths[j][k]['color'] else for i=stop+1,start do pathCell[j][i][1][1][2] = 1 pathCell[j][i][1]['color'] = paths[j][k]['color'] end end else crossCell[j][cross]['right'] = for i=stop+1,cross-1 do pathCell[j][i][2][1][2] = 1 pathCell[j][i][2]['color'] = paths[j][k]['color'] end for i=cross+2,start do pathCell[j][i][1][1][2] = 1 pathCell[j][i][1]['color'] = paths[j][k]['color'] end end pathCell[j][start][1][1][3] = 1 pathCell[j][start][1]['color'] = paths[j][k]['color'] end end end -- Thicken start

stop paths for n=1,#straightpaths do local i = straightpaths[n][1] local color = straightpaths[n][2] if i>r then break end if pathCell[j][i][1][1][3]

0 then pathCell[j][i][1][1][3] = 1 pathCell[j][i][2][1][3] = 1 pathCell[j][i][3][1][3] = 1 pathCell[j][i][1]['color'] = color pathCell[j][i][2]['color'] = color pathCell[j][i][3]['color'] = color if pathCell[j][i+1][1][1][1]

0 then pathCell[j][i+1][1][1][1] = 0.5 pathCell[j][i+1][2][1][1] = 0.5 pathCell[j][i+1][3][1][1] = 0.5 pathCell[j][i+1][1]['color'] = color pathCell[j][i+1][2]['color'] = color pathCell[j][i+1][3]['color'] = color end elseif pathCell[j][i+1][1][1][1]

0 then pathCell[j][i+1][1][1][1] = 1 pathCell[j][i+1][1]['color'] = color if hascross[j] then pathCell[j][i+1][2][1][1] = 1 pathCell[j][i+1][2]['color'] = color end pathCell[j][i+1][3][1][1] = 1 pathCell[j][i+1][3]['color'] = color end end -- Thicken/Thin out paths for n=1,#outpaths do local i = outpaths[n][1] local color = outpaths[n][2] if i

1 and pathCell[j][i+1][1][1][1]

0 then pathCell[j][i+1][1][1][1] = 0.5*pathCell[j][i][1][1][3] pathCell[j][i+1][2][1][1] = 0.5*pathCell[j][i][2][1][3] pathCell[j][i+1][1]['color'] = pathCell[j][i][1]['color'] pathCell[j][i+1][2]['color'] = pathCell[j][i][2]['color'] elseif i

0 and pathCell[j][i+1][1][1][1]

1 then pathCell[j][i][1][1][3] = pathCell[j][i+1][1][1][1] pathCell[j][i][2][1][3] = pathCell[j][i+1][2][1][1] pathCell[j][i+1][1][1][1] = 0.5*pathCell[j][i][1][1][3] pathCell[j][i+1][2][1][1] = 0.5*pathCell[j][i][2][1][3] pathCell[j][i][1]['color'] = pathCell[j][i+1][1]['color'] pathCell[j][i][2]['color'] = pathCell[j][i+1][2]['color'] end end -- Thin double-in paths for n=1,#inpaths do local i = inpaths[n][1] local color = inpaths[n][2] if i

1 and pathCell[j][i+1][3][1][1]

1 and pathCell[j][i][3]['color']

pathCell[j][i+1][3]['color'] then pathCell[j][i+1][3][1][1] = 0.5*pathCell[j][i][3][1][3] end end end for j=minc,c-1 do for i=1,r-1 do local straightpath=false if (entries[j+1][i-1]

nil or (byes[j+1][entries[j+1][i-1]['headerindex']]) and isBlankEntry(j+1,i-1)) then if (pathCell[j][i][3][1][3]~=0 and pathCell[j+1][i][1][1][3]~=0) or (pathCell[j][i+1][3][1][1]~=0 and pathCell[j+1][i+1][1][1][1]~=0) then if pathCell[j+1][i][1][1][3]

pathCell[j+1][i][3][1][3] and pathCell[j+1][i+1][1][1][1]

pathCell[j+1][i+1][3][1][1] then straightpath=true end pathCell[j+1][i][1][1][3]=pathCell[j][i][3][1][3] pathCell[j+1][i+1][1][1][1]=pathCell[j][i+1][3][1][1] pathCell[j+1][i][2][1][3]=pathCell[j][i][3][1][3] pathCell[j+1][i+1][2][1][1]=pathCell[j][i+1][3][1][1] entries[j+1][i-1]= entries[j+1][i]= if notempty(entries[j+1][i+1]) then entries[j+1][i+1]['ctype'] = 'line2' else entries[j+1][i+1]= end entries[j+1][i+2]= if straightpath then pathCell[j+1][i][3][1][3]=pathCell[j+1][i][1][1][3] pathCell[j+1][i+1][3][1][1]=pathCell[j+1][i+1][1][1][1] end end end end endend

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-1 do if pathCell[j][i][3][1][3]

1 or pathCell[j][i+1][3][1][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]= entries[j-k][i+1]= if k>0 and noPaths(j-k,i) then skipPath[j-k][i] = true skipPath[j-k][i+1] = true end k=k+1 until k>j-1 or not check(j-k,i) or not noPaths(j-k,i) k=k-1 entries[j-k][i]= entries[j-k][i+1]= entries[j-k][i]['group'] = bargs('RD'..j..'-group'..n) end end end end endend

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] = 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]= entries[j][i-1]= textindex=n end entries[j][i]= entries[j][i+1]= for m=2,teams_per_match[j] do entries[j][i+2*(m-1)]= entries[j][i+2*(m-1)+1]= end elseif ctype

'text' then entries[j][i]= entries[j][i+1]= elseif ctype

'line' then entries[j][i]= entries[j][i+1]= entries[j][i+2]= entries[j][i+3]= elseif ctype

'group' then entries[j][i]= entries[j][i+1]= else entries[j][i]= entries[j][i+1]= end end end end if isempty(r) then r = maxrow endend

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 local height = bargs('height') or 0 maxtpm = 1 seeds = true nowrap = 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('paramstyle')

'numbered' then paramstyle = 'numbered' else paramstyle = 'indexed' end if pargs.nowrap

'n' or pargs.nowrap

'no' then nowrap=false 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 div = mw.html.create('div') :css('overflow','auto') if height~=0 then div:css('height',height) end local tbl = mw.html.create('table') :attr('cellpadding','0') :attr('cellspacing','0') :css('font-size','90%') :css('border-collapse','separate') :css('margin','1em 2em 0em 1em') if nowrap then tbl:css('white-space','nowrap') end 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('agg',getWidth('score','25px'))) end if j~=c then if hascross[j] then tbl:tag('td'):css('width',colspacing+1-4 ..'px') :css('padding-left','4px') tbl:tag('td'):css('padding-left','5px') :css('width','5px') tbl:tag('td'):css('width',colspacing-1-2 ..'px') :css('padding-right','2px') else tbl:tag('td'):css('width',colspacing+1-4 ..'px') :css('padding-left','4px') tbl:tag('td'):css('width',colspacing-1-2 ..'px') :css('padding-right','2px') 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 div:wikitext(tostring(tbl)) return tostring(div)end

return p