# Module:RoundN

local p = {  
RD = {  
'காலிறுதிகள்',  
'அரையிறுதிகள்',  
'இறுதிப்போட்டி',  
'மூன்றாம் இடம்'  
},  
bgColor = {head = '#f2f2f2', 'gold', 'silver', '#C96', '#f9f9f9'},  
reuseStr = {},  
saveStr = function(self, name, ...)  
if not self.reuseStr[name] then  
self.reuseStr[name] = table.concat{...}  
end  
return self.reuseStr[name]  
end  
}  

--Provides a convenient naming shortcut up to =  
for columns = 1, 9 do  
local N = math.pow(2, columns)  
p['N' .. N] = function  
return p.main(.args, columns)  
end  
p['n' .. N] = p['N' .. N]--to make case insensitive  
end  

--saves memory and avoids errors when using a nil as a table by providing a temporary table; if using nil as false; use 'table(k)' to look up table[k]  
p.nilAsTab = {  
__index = function(t, i)  
return setmetatable({}, setmetatable(p.nilAsTab, {__index = {t = t, i = i}}))  
end,  
__newindex = function (pt, pi, v) --store new values in actual table rather than temporary  
rawset(p.nilAsTab.t, p.nilAsTab.i, {})[p.nilAsTab.i][pi] = v  
setmetatable(p.nilAsTab.t[p.nilAsTab.i], {__call = p.nilAsTab.__call})  
end,  
__call = function(t, i)  
return t and rawget(t, i)  
end  
}  
--never assign a value to these or they will stop being empty  
local infiniteEmpty = setmetatable({}, {__index = setmetatable({}, p.nilAsTab), p.nilAsTab}) -- infiniteEmpty[1][2][3]...[infinity] = {}  
local callableEmpty = setmetatable({}, p.nilAsTab)  

local rowNum, head, m, col, tab, esc = {}, {}, {num = 1, phase = 0, bold = infiniteEmpty}, {}, mw.html.create'table', {  
bs = require'Module:Escape',--backslash  
comma = {['(%([^,]*),([^%)]*%))'] = '%1|@!#|%2'},--escape commas in  
}  
local nodeFunc = {  
scanPattern = function(self, args, step)  
self.pattern = nil  
if args[step] then  
self.pattern, self.nonFunc = string.match(esc.bs:text(args[step]), '^node_function{(.-)}(.*)')  
end  
if self.pattern then  
for k, v in pairs(esc.comma) do  
self.pattern = self.pattern:gsub(k, v)  
end  
self.nonFunc = self.nonFunc and esc.bs:undo(self.nonFunc)  
self.pattern = mw.text.split(self.pattern, '%s*,%s*')  
for k, v in ipairs(self.pattern) do  
local func, arg = string.match(v, '^(%w+)%(?([^%)]*)')  
if func and self[func] and self[func].main then  
self.pattern[k] = func  
if arg then  
for x, y in pairs(esc.comma) do  
arg = esc.bs:undo(arg):gsub(y:gsub('%%%d', *), x:match('%)([^%(])%(') or x:gsub('\\', *))  
end  
self[func].arg = self[func].arg or {}  
self[func].arg[m.num] = arg  
end  
end  
end  
end  
return self.pattern  
end,  
helper = {  
topBranch = function--node is top of fork if top is 0  
return (m.num - col.top) % 2  
end,  
addText = function(text)  
if text and text ~= '' then  
tab.r:wikitext(text)  
end  
end  
},  
line = {--this node is omitted and replaced with a line  
main = function(x)  
local h = p.getNodeFunc  
if m.available then  
local text, topId, isTop, notTop = h.line.arg[m.num] or '', h.topBranch  
isTop = topId == 0  
notTop = {[isTop and 1 or 0] = p.reuseStr.solid}  
for k = 0, 1 do  
tab.r = rowNum[m.r + k * 4]:tag'td'  
:css(notTop[k] and  
{[isTop and '-top' or '-bottom'] = notTop[k]}  
or {}  
:attr{  
rowspan = ({[0] = 4, 2})[k],  
colspan = p.colspan  
}  
h.addText(text or h.nonFunc)  
text = nil  
end  
m.available = false  
else  
return nil  
end  
return x  
end  
},  
bridge = {--Draw a line to the neighboring node in the same column that is not connected to the current node  
main = function(x)  
local h = p.getNodeFunc  
h.bridge.lay[col.c][m.num - col.top + 1 + (h.topBranch == 1 and 1 or -1)] = true  
h.addText(nonFunc)  
return x  
end,  
lay = setmetatable({}, p.nilAsTab)  
},  
canvas = {--Merges all cells in node. Content will be the next parameter.  
main = function(x)  
local h = p.getNodeFunc  
if m.available then  
tab.r = rowNum[m.r]:tag'td'  
:attr{  
rowspan = 6,  
colspan = p.colspan  
}  
h.addText(h.nonFunc)  
m.available = false  
return x  
else  
return nil  
end  
end  
},  
orphan = {--sets a flag for skipMatch to be set by p._main  
main = function(x)  
p.getNodeFunc.orphan.num = m.num  
return x  
end  
},  
skipAllowed = {--table of supported node functions when node is skipped (i.e. by skipmatch)  
bridge = true,  
canvas = true  
}  
}  

setmetatable(nodeFunc.helper, {__index = nodeFunc})  
function p.getNodeFunc  
return nodeFunc.helper  
end  

function newRow(bodyRow)  
local first = p.flex_tree.merge and mw.clone(p.flex_tree.cell) or p.flex_tree.cell  
tab.r = tab:tag'tr'  
:node(first)  
if bodyRow then  
table.insert(rowNum, bodyRow, tab.r)  
if p.flex_tree.merge then  
rowNum[bodyRow].first = first  
rowNum[bodyRow].first.unchanged = true  
end  
end  
end  

function drawHead(text, row3rd)  
local td = (row3rd and rowNum[row3rd]:tag'td':attr{rowspan = 2}  
or head.row:tag'td')  
:attr{colspan = p.colspan}  
if text ~= 'omit_label' then  
td:wikitext(text):css{  
['text-align'] = '',  
= ' solid #aaa',  
background = p.bgColor.head  
}  
end  
end  

function spacer(width)  
tab.r:tag'td'  
:attr{width = width}  
:wikitext(p.no_column_head and '' or '&nbsp;')  
end  

function dpBox(v, r)  
p.dpBoxBase = p.dpBoxBase or mw.html.create'td':attr{rowspan = 2, colspan = p.colspan}  
if not v then  
p.dpBoxEmpty = p.dpBoxEmpty or mw.clone(p.dpBoxBase):wikitext(p.flex_tree.wt)  
rowNum[r]:node(p.dpBoxEmpty)  
else  
rowNum[r]:node(mw.clone(p.dpBoxBase):wikitext(v))  
end  
end  

p.scoreWasher = {  
numberFormat = '%-?%d+%.?%d*',  
main = function (self, s)  
if s then  
for _, cycle in ipairs(self.cycles) do  
s = s:gsub(unpack(cycle))  
end  
if p.scoreSumBox and self.plus then  
local t = 0  
for _, part in ipairs(mw.text.split(s, self.plus)) do  
t = t + (tonumber(part:match('%-?%d+%.?%d*')) or 0)  
end  
return t  
end  
return tonumber(s:match(self.numberFormat)) or math.huge  
end  
return 0  
end,  
spin = function(self, v)  
table.insert(self, v)  
return self  
end,  
load = function (self, cycle)  
local wash, rinse = 0, {spin = self.spin}  
for v in cycle:gfind('%(([^%(%)]-)%)') do  
if v == '_plus_' then  
self.plus = v  
rinse:spin(v)  
cycle = cycle:gsub('%(_plus_%)', '', 1)  
else  
wash = wash + 1  
rinse:spin('%'):spin(wash)  
end  
end  
table.insert(self.cycles, {esc.bs:undo(cycle, '%%'), table.concat(rinse)})  
end,  
init = function(self, setting)  
self.cycles = {original = setting}  
for cycle in (setting and esc.bs:text(setting) or '{<.->} {[^%d]*}'):gfind('{(.-)}') do  
self:load(cycle)  
end  
end,  
sum = function (clean)  
local sum = {0, 0}  
for _, box in ipairs(clean) do  
for team, score in ipairs(box) do  
sum[team] = sum[team] + score  
end  
end  
return unpack(math.max(unpack(sum)) == math.huge and {'&mdash;', '&mdash;'} or sum)  
end  
}  

function boldWin(s1, s2)  
return setmetatable(  
p.bold and s1 ~= s2 and (math[({'min', 'max'})[p.bold]](s1, s2) == s1 and {true} or {[2] = true}) or callableEmpty,  
p.nilAsTab  
end  

function maxSpan(span, start, rows)  
return math.min(span, math.max(0, rows - start + 1))  
end  

--in case of templates like RDseed need padding value  
p.teamBoxPadding = function  
return '.6ex'  
end  
p.teamBoxPadTab = {padding = '0 ' .. p.teamBoxPadding}  
p.teamBoxNormal = { = ' solid #aaa', background = p.bgColor[4]}  
function teamBox(v, r, f)  
if p.flex_tree.merge and not v and f.phase == 2 then  
for i = -2, 0 do  
if rowNum[r + i].first.unchanged then  
rowNum[r + i].first.unchanged = nil  
rowNum[r + i].first:node(p.unflex_div)  
end  
end  
tab.r:attr{rowspan = 4}:css{['vertical-align'] = ''}  
else  
if not p.bold then  
--backwards compatability (wikitemplates bold each arg individually)  
local hasBold, b = tostring(v):gsub("([^']*)'''([^']*)", '%1%%s%2')  
if b == 1 then  
v = hasBold:format('<b>')  
end  
end  
local cell  
if f[1] then  
cell = f.sumBox and f.sumBox[1] and  
{padding = f.sumBox[1]}  
or {['-'] = f.borderLeft}  
cell['text-align'] = v and f[1]  
else  
cell = p.teamBoxPadTab  
end  
tab.r = rowNum[r]:tag'td'  
:css(p.teamBoxCSS)  
:css(cell)  
:attr{rowspan = 2}  
:node(mw.html.create(f.bold and 'b'):wikitext(v or f[1] and '' or '&nbsp;'))  
end  
end  

function p._main(args)  
function args:clean(key, params)--prevent html comments from breaking named args and reduces repeat concatenation  
params = params or {}  
local clean = args[key] or params.ifNil  
if clean then  
params.append = params.append or ''  
clean = mw.text.decode(clean):gsub('<!%-.-%->', *):gsub(params.pattern or '[^%w-;%.]', *) .. params.append  
clean = clean ~= params.append and clean or params.ifNil  
end  
args[key] = params.keepOld and args[key] or clean  
return clean  
end  
p.cols = tonumber(args:clean('columns', {pattern = '%D'}))  
p.tCols = (tonumber(args:clean('final_RDs_excluded', {pattern = '%D'})) or 0) + p.cols  
local matchPer = {  
pattern = '%d*per%d+[%-x]%d+',  
vals = '(%d*)per(%d+)([%-x])(%d+)'  
}  
local skipMatch, unBold = {}, {}--(skip|manualbold)match# to boolean  
for k, _ in pairs(args) do  
local mType, mNum = string.match(k, '^(%l+)match(%d*)$')  
mType, mNum = ({skip = skipMatch, manualbold = unBold})[mType], tonumber(mNum)  
if mType then  
if mNum then  
mType[mNum] = args:clean(k) == 'yes' or args[k] == 'true'  
else  
for pattern in args:clean(k, {ifNil = ''}):gfind(matchPer.pattern) do  
local d1, period, op, d2 = pattern:match(matchPer.vals)  
d1 = tonumber(d1) or 1  
d2 = op == '-' and d2 or (d1 + period * (d2 - 1))  
for y = d1, d2, period do  
mType[y] = true  
end  
end  
for _, x in ipairs(mw.text.split(args[k]:gsub(matchPer.pattern, ''):gsub('[;%-%a][;%-%a]+', ';'):match('^;*(.-)[;%-]*$'), ';')) do  
x = mw.text.split(x, '-')  
for y = tonumber(x[1]) or 1, tonumber(x[2] or x[1]) or 0 do  
mType[y] = true  
end  
end  
end  
end  
end  
for _, v in ipairs({--more args to boolean  
'widescore',  
'template',  
'article_include',  
'color',  
'3rdplace',  
'omit_blanks',  
'scroll_head_unlock',  
'previewnumbers',  
'flex_tree',  
'no_column_head',  
'short_brackets',  
'branch_upwards'  
}) do  
if args[v] and (p[v] == nil or type(p[v]) == 'boolean') then  
p[v] = args:clean(v) == 'yes' or args[v] == 'true'  
end  
end  
p.scoreWasher:init(args['score-clean'])  
p.scoreWasher.demo = args.demoWash and tonumber(args:clean('demoWash', {pattern = '%D'}), 10)  
p.scoreSumBox = args['score-boxes'] and args['score-boxes']:match('%d ?%+ ?sum')  
p.bold = ({low = 1, high = 2})[args:clean('bold_winner')] or p.scoreSumBox and 2  
local sumBox = p.scoreSumBox and 1 or 0  
p.scoreBoxes = (tonumber(args:clean('score-boxes', {pattern = '%D'})) or 1) + sumBox  
p.scoreSumBox = p.scoreBoxes > 0 and p.scoreSumBox or nil  
local boxStyle = p.scoreBoxes > 1 and  
(p.scoreSumBox and  
setmetatable(  
,  
{__call = function(t, i) if t[i] then return nil end return 0 end}  
or setmetatable(  
{},  
{__call = function return 0 end}  
or setmetatable({}, {__call = function return nil end})  
p.colspan = p.scoreBoxes > 0 and (p.scoreBoxes + 1) or nil  
local nodeArgs = {  
score = p.scoreBoxes - sumBox,  
team = {offset = 1 + p.scoreBoxes - sumBox}  
}  
nodeArgs.all = 1 + nodeArgs.team.offset * 2  
nodeArgs.tableSum = {  
__add = function(v, t)  
if #t == 3 then  
return v + nodeArgs.all  
end  
local s = v  
for i, n in ipairs(t) do  
s = s + n  
end  
return s-- + (p.scoreSumBox and #t == 3 and -2 or 0) --merging disabled with score boxes, uncomment if enable  
end  
}  
nodeArgs.team[1] = 1--constant to be replaced later by new param  
nodeArgs.team[2] = nodeArgs.team[1] + nodeArgs.team.offset  
nodeArgs.blank = setmetatable({}, nodeArgs.tableSum)  
p.unflex_div = mw.html.create'div'  
:css{overflow = 'hidden',}  
:wikitext'&nbsp;'  
p.flex_tree = setmetatable({},{__index = {  
merge = p.flex_tree and p.scoreBoxes == 0,  
wt = p.flex_tree and '' or '&nbsp;',  
cell = mw.html.create'td'  
:node(not p.flex_tree and p.unflex_div or nil)  
}})  
if args:clean'scroll_height' then  
local fontSize, fontUnit = args.style and args.style:match('font%-size *: *(%d+)([^ ]+)')  
if fontSize then  
local units = {  
em = 1,  
ex = 2,  
['%'] = 0.01  
}  
fontSize, fontUnit = {fontSize * fontUnit}  
end  
end  
tab  
:cssText(table.concat{args.scroll_height and 'padding' or 'margin', ':', fontSize and (math.ceil(fontSize * 10) / 10) or '.9', 'em 2em 1em 1em;:0;', fontSize and '' or 'font-size:90%;', args.style})  
:attr{cellpadding = 0, cellspacing = 0}  
if not p.no_column_head then--headings row  
newRow  
head.row = tab.r  
:css{['white-space'] = args.scroll_height and 'nowrap'}  
newRow  
else  
tab.r = tab:tag'tr'  
tab.r:tag'td'  
end  
local sp = {--set column widths  
args['team-width'] or 170,  
p.widescore and 40 or 30,  
p.short_brackets and 6 or 15,  
p.short_brackets and 4 or 20  
}  
local scoreWidth = args:clean('score-width', {pattern = '[^%d;]'}) and mw.text.split(args['score-width'], ';') or {}  
scoreWidth[1] = tonumber(scoreWidth[1], 10)  
if p.scoreSumBox and #scoreWidth ~= 1 then  
local _scoreWidth = {}  
for k = 1, p.scoreBoxes - 1 do  
_scoreWidth[k] = tonumber(scoreWidth[k], 10) or math.ceil(sp[2] * 0.75)  
end  
setmetatable(scoreWidth, _scoreWidth)  
end  
if p.template or p.article_include then  
p.template = mw.title.new(args.name)  
p.templateFixedName = (p.template.namespace == 0 and not p.article_include and 'Template:' or '') .. p.template.fullText  
end  
p.template = p.template and mw.title.new(args:clean('name', {pattern = ''}))  
local head_br = {  
count = 0,  
compare = function (self, text)  
if text and args.scroll_height then  
local _, count = text:gsub('<br[ >/]', '%1')  
self.count = math.max(self.count, count)  
end  
return text  
end  
}  
p.branch_upwards = p.branch_upwards and 0  
for k = 1, p.cols do  
if k > 1 then  
spacer(sp[3])  
spacer(sp[4])  
if not p.no_column_head then  
head.row:tag'td':attr{colspan = 2}  
end  
end  
spacer(sp[1])  
for s = 1, p.scoreBoxes do  
spacer(#scoreWidth == 1 and scoreWidth[1] or scoreWidth[s] or sp[2])  
end  
if not p.no_column_head then  
head.wt = head_br:compare(args:clean('RD' .. k, {pattern = ''}))  
or p.RD[#p.RD + k - p.tCols - 1]  
or (math.pow(2, p.tCols - k + 1).. ' அணிகளின் சுற்று')  
drawHead(  
k == 1 and p.template and mw.getCurrentFrame:expandTemplate{  
title = 'tnavbar-header',  
args = {head.wt, p.templateFixedName}  
} or head.wt  
end  
end  
sp.row = tab.r  
col.tot = math.pow(2, p.tCols - 1)  
local step, bump, bumpBase, rows = 1, 0, mw.html.create'td':attr{colspan = p.colspan}, col.tot * 6--Begin body row output  
args.line_px = table.concat{args:clean('line_px') or 3, args.line_px ~= '0' and 'px' or nil}  
tab.line = {--reduces concats and 'or' statements  
{  
[true] = args.line_px,  
[false] = 0  
},  
args.line_px:rep(2):gsub('(%a)(%d)', '%1 %2', 1)  
}  
p['3rdplace'] = p.tCols == p.cols and (p['3rdplace'] or p.cols > 3 and nil == p['3rdplace'] and not p.no_column_head)  
if p['3rdplace'] then  
p.textThird = args.Consol or args['RD' .. (p.cols + 1)] or p.RD[4]  
local no3rdText = p.no_column_head or p.textThird and p.textThird:match('omit_label')  
rowNum.third = math.max(math.pow(2, p.branch_upwards and -3 or p.cols - 2) * 9 + (no3rdText and 4 or 9), no3rdText and 12 or 17, rows)  
end  
for r = 1, rowNum.third or rows do  
newRow(r)  
end  
p:saveStr('solid', tab.line[1][true], ' solid')  
p.cornerDiv = mw.html.create'div':css{height = tab.line[1][true], ['-'] = p.reuseStr.solid}  
for c = 1, p.cols do  
col.c = c  
local bumps = bump  
if c > 1 then  
col.tot = col.tot + math.pow(2, p.tCols - c)  
if p.branch_upwards then  
bumps = 0  
rowNum[1]:tag'td':attr{rowspan = 4}  
else  
rowNum[1]:node(c < p.cols and  
mw.clone(bumpBase):attr{rowspan = bump}  
or p.no_column_head and p.template and  
mw.html.create'td':wikitext(mw.getCurrentFrame:expandTemplate{  
title = 'tnavbar-header',  
args = {'', p.templateFixedName}  
})  
end  
end  
col.top = m.num  
p.span = p.tCols > c and bump * 2 or p.branch_upwards or math.max((bump - 1) / 2, 2)  
col.show3rd = p['3rdplace'] and c == p.tCols and rowNum.third  
local colorFinal, bumpMid = p.color and c == p.tCols, p.span > 0 and mw.clone(bumpBase):attr{rowspan = p.span} or nil  
for r = 1, col.show3rd or rows, 2 do  
m.r = r + bumps  
if col.show3rd or rowNum[m.r] and m.num <= col.tot then  
if m.phase == 0 then  
m.showBox = setmetatable({1, nodeArgs.team.offset, nodeArgs.team.offset}, nodeArgs.tableSum)  
if nodeFunc:scanPattern(args, step) then  
nodeFunc.called = {}  
m.available = true  
else  
m.available = nil  
end  
end  
if skipMatch[m.num] then  
if m.phase == 0 then  
if nodeFunc.pattern then  
for x, y in ipairs(nodeFunc.pattern) do  
if nodeFunc.skipAllowed[y] then  
nodeFunc.called[y] = nodeFunc[y].main(x)  
end  
end  
end  
local canvas = nodeFunc.pattern and nodeFunc.called.canvas and 6  
rowNum[m.r + (canvas or 0)]:tag'td':attr{rowspan = maxSpan((canvas and 0 or 6) + bump * 2, m.r + (canvas or 0), rows), colspan = p.colspan}  
elseif m.phase == 2 then  
if nodeFunc.pattern and (nodeFunc.called.bridge or nodeFunc.called.canvas) then  
step = step + 1  
end  
m.num = m.num + 1  
step = step + (p.omit_blanks and 0 or m.showBox)  
bumps = bumps + (col.show3rd and 0 or maxSpan(p.span, m.r, rows))  
end  
elseif m.phase == 0 then  
if nodeFunc.pattern then  
for x, y in ipairs(nodeFunc.pattern) do  
if nodeFunc[y] and nodeFunc[y].main then  
nodeFunc.called[y] = nodeFunc[y].main(x)  
end  
end  
if m.available == false then  
m.showBox = nodeArgs.blank  
step = step + 1  
end  
end  
if m.showBox[1] then  
if col.show3rd then  
col.show3rd = (m.num - col.top) * 2  
if col.show3rd == 2 then  
if p.textThird:match('omit_label') then  
p.textThird = nil  
end  
if rowNum[rows + 1] and p.cols > 1 then --if 3rd place extends below bottom cell  
rowNum[rows + 1]:tag'td':attr{  
rowspan = m.r + 9 - rows - (text and 0 or 2),  
colspan = (p.cols - 1) * 4  
}  
end  
if p.tCols == 1 then  
bumps = p.textThird and 3 or 0  
elseif p.branch_upwards then  
r = 7  
bumps = p.textThird and 2 or 0  
end  
m.r = r + bumps  
if p.textThird then  
drawHead(p.textThird, m.r)  
bumps = bumps + 2  
m.r = r + bumps  
end  
end  
end  
dpBox(nodeFunc.pattern and nodeFunc.nonFunc or args[step], m.r, skipMatch[m.num])  
if p.previewnumbers then  
p.namespace = p.namespace or mw.title.getCurrentTitle.namespace  
if p.namespace ~= 0 then  
tab.r:tag'div'  
:css{  
float = '',  
= ' solid red',  
padding = '0 .5ex',  
['color'] = 'red'  
}  
:wikitext(m.num)  
:attr{title = 'Number only visible outside article space (e.g. template) when |numberpreview=yes'}  
end  
end  
end  
if p.colspan then  
m.nonEmpty = {}  
for s = step + 2, step + nodeArgs.team.offset do  
local i = {s, s + nodeArgs.team.offset}  
if args[i[1]] or args[i[2]] then  
table.insert(m.nonEmpty, i)  
end  
end  
if p.bold and m.showBox[2] and m.showBox[3] and not unBold[m.num] then  
m.bold = {  
box = {},  
clean = {}  
}  
local notSummed = not p.scoreSumBox or #m.nonEmpty < 2  
for s, i in ipairs(m.nonEmpty) do  
m.bold.clean[s] = {p.scoreWasher:main(args[i[1]]), p.scoreWasher:main(args[i[2]])}  
m.bold.box[s] = notSummed and boldWin(m.bold.clean[s][1], m.bold.clean[s][2]) or callableEmpty  
end  
if p.scoreSumBox and m.nonEmpty[2] then  
local i = {-step, -step - 1}  
table.insert(m.nonEmpty, i)  
args[i[1]], args[i[2]] = p.scoreWasher.sum(m.bold.clean)  
m.bold.box[p.scoreBoxes] = boldWin(args[i[1]], args[i[2]])  
end  
getmetatable(boxStyle).__index = p.scoreSumBoxes and {[#m.nonEmpty] = boxStyle[p.scoreBoxes]}  
m.bold.win = m.bold.box[#m.nonEmpty] or callableEmpty  
else  
m.bold = infiniteEmpty  
end  
end  
else  
if m.showBox[m.phase] then  
p.teamBoxCSS = colorFinal and  
{ = p.teamBoxNormal., background = p.bgColor[m.phase + (col.show3rd or 0)]}  
or p.teamBoxNormal  
local f = {phase = m.phase, bold = m.bold.win(m.phase)}  
teamBox(args[step + nodeArgs.team[m.phase]], m.r, f)  
f[1] = ''  
if p.colspan then  
if m.nonEmpty[1] then  
local loneSum  
if #m.nonEmpty < p.scoreBoxes then  
loneSum = #m.nonEmpty == 1 and boxStyle[p.scoreBoxes]  
tab.r:attr{colspan = 1 + p.scoreBoxes - #m.nonEmpty}  
end  
for s, i in ipairs(m.nonEmpty) do  
f.borderLeft = boxStyle(s)  
f.sumBox = loneSum or boxStyle[s]  
f.bold = m.bold.box[s](m.phase)  
teamBox(args[i[m.phase]], m.r, f)  
end  
else  
for s = 1, p.scoreBoxes do  
f.borderLeft = boxStyle(s)  
teamBox(nil, m.r, f)  
end  
end  
end  
end  
if m.phase == 2 then  
col.show3rd = col.show3rd ~= 2 and col.show3rd or nil  
if p.scoreWasher.demo and p.scoreWasher.demo == m.num and mw.title.getCurrentTitle.namespace ~= 0 then  
table.insert(m.bold.clean, 1, {args[step + nodeArgs.team[1]], args[step + nodeArgs.team[2]]})  
return table.concat{  
'Score data for match specified by <code>|demoWash=</code>:  
',  
mw.dumpObject{scores = m.bold.clean, cycles = p.scoreWasher.cycles, sum = p.scoreSumBox and {m.nonEmpty[#m.nonEmpty][1], m.nonEmpty[#m.nonEmpty][1]}},  
'<table>',  
tostring(sp.row), '<tr>',  
tostring(rowNum[m.r - 4]), '<tr>',  
tostring(rowNum[m.r - 2]), '<tr>',  
tostring(rowNum[m.r]), '</table>',  
}  
end  
if nodeFunc.orphan.num == m.num then  
skipMatch[m.num] = 'orphan'  
end  
step = step + m.showBox  
m.num = m.num + 1  
if bump > 0 and rowNum[m.r + 2] and not (nodeFunc.pattern and nodeFunc.called.canvas) then  
bumps = bumps + p.span  
rowNum[m.r + 2]:node(bumpMid)  
end  
r = r + (col.show3rd or bump)  
end  
end  
m.phase = (m.phase + 1) % 3  
end  
end  
if p.cols > c then--draw lines to next round  
p.unit = bump + 3  
bump = 3 * math.pow(2, c) - 3  
bumps = p.branch_upwards and 4 or (p.unit + 1)  
rowNum[1]  
:tag'td':attr{rowspan = bumps}  
if not p.branch_upwards then  
rowNum[1]:tag'td'  
:attr{rowspan = (p.branch_upwards or bump) + 4}  
:css(nodeFunc.bridge.lay[c](0) and  
{['-'] = p.reuseStr.solid}  
or {}  
end  
col.n = 0  
for r = bumps + 1, rows, p.unit * 2 do  
tab.r = rowNum[r]:tag'td'  
local interval = ((r - bumps - 1) / (p.unit * 2)) % 4  
if interval % 2 == 0 then  
--col.t and col.t2 control whether lines are drawn  
col.t = col.t2 or skipMatch[col.tot + col.n / 2 + 1] and 3 or ((skipMatch[col.top] and 1 or 0) + (skipMatch[col.top + 1] and 2 or 0))  
col.n = col.n + 2  
col.t2 = skipMatch[col.tot + col.n / 2 + 1] and 3 or ((skipMatch[col.top + col.n] and 1 or 0) + (skipMatch[col.top + col.n + 1] and 2 or 0))  
if col.t == 0 then  
tab.r  
:attr{rowspan = maxSpan(p.unit * 2, r, rows)}  
:css(skipMatch[col.tot + col.n / 2] and {} or {  
= p.reuseStr.solid,  
['-'] = 0  
})  
else  
tab.r  
:attr{rowspan = maxSpan(p.unit, r, rows)}  
:cssText(col.t == 2 and  
p:saveStr('topRight', '-width:', tab.line[2], ' 0 0;-style:solid')  
or col.t == 1 and (nodeFunc.bridge.lay[c](col.n - 2) and  
p:saveStr('', ';-:', p.reuseStr.solid)  
or 'vertical-align:bottom'  
or nil  
:node(col.t == 1 and interval > 0 and not nodeFunc.bridge.lay[c](col.n - 2) and p.cornerDiv)  
rowNum[r + (p.branch_upwards and (4 - bump) or p.unit)]:tag'td'  
:attr{rowspan = maxSpan(p.unit, r + p.unit, rows)}  
:cssText(col.t == 1 and  
p:saveStr('bttmRght', '-width:0 ', tab.line[2], ' 0;-style:solid')  
or col.t == 2 and (nodeFunc.bridge.lay[c](col.n + 2) and  
p:saveStr('', ';-:', p.reuseStr.solid)  
or 'vertical-align:top'  
or nil  
:node(col.t == 2 and interval ~= 2 and not nodeFunc.bridge.lay[c](col.n + 2) and p.cornerDiv)  
end  
col.t = {  
col.t < 3,  
rowNum[r + p.unit * 5] and col.t2 < 3 or false  
}  
rowNum[r + (p.branch_upwards or p.unit)]:tag'td'  
:attr{rowspan = maxSpan(p.unit * 4, r + (p.branch_upwards and (4 - bump) or p.unit), rows)}  
:css(interval == 0 and (col.t[1] or col.t[2]) and {  
['-width'] = table.concat{tab.line[1][col.t[1]], ' 0 ', tab.line[1][col.t[2]]},  
['-style'] = 'solid'  
} or {})  
else  
tab.r  
:attr{rowspan = maxSpan(p.unit * 2, r, rows)}  
:css(nodeFunc.bridge.lay[c](col.n) and  
{['-'] = p.reuseStr.solid}  
or {}  
end  
end  
end  
end  
local lock_height = (head_br.count or 0) + 1  
return args.scroll_height and  
mw.html.create'div'  
:cssText'-bottom: solid #eee;display:inline-block'  
:node(not (p.scroll_head_unlock or p.no_column_head) and mw.html.create'div'  
:css{  
overflow = 'hidden',  
height = lock_height * 1.4 + 1.6 .. 'em',  
['-bottom'] = 'inherit',  
['margin-'] = ''  
}  
:node(mw.clone(tab))  
:tag'div'  
:css{  
['overflow-y'] = 'scroll',  
['max-height'] = tonumber(args.scroll_height, 10) and args.scroll_height .. 'px' or args.scroll_height  
}  
:node(not (p.scroll_head_unlock or p.no_column_head) and  
tab:css{['margin-top'] = math.floor(-10 * (lock_height * 1.4 + 1.6)/(fontSize or .9)) / 10 .. 'em', ['padding-top'] = '-'}  
or tab  
:done  
or tab  
end  

--local standard = {  
'beta' = {  
bold_winner = 'high',  
omit_blanks = 'yes',  
auto_3rd = 'yes'  
}  
}--  
function p.main(, columns)  
local args = require'Module:Arguments'.getArgs(, {trim = false})  
args.columns = args.columns or columns  
return p._main(args)  
end  

function p.seed  
local parent = :getParent or  
function arg(k, alt)  
return parent.args[k] or .args[k] or alt  
end  
local padding, width = arg(2, p.teamBoxPadding), arg(3, arg('widescore') and 40 or 30)  
padding = tonumber(padding) and tonumber(padding) .. 'px' or padding  
width = tonumber(width) and tonumber(width) .. 'px' or width  
return mw.html.create'div'  
:css{  
margin = ('- %s - -%s'):format(padding, padding),  
float = '',  
['background-color'] = p.bgColor.head,  
= ' solid #aaa',  
['text-align'] = '',  
width = width  
}  
:wikitext(arg(1, '&nbsp;'))  
end  

return p