Bước tới nội dung

Mô đun:RoundN

Bách khoa toàn thư mở Wikipedia

local p = {	RD = {		'Tứ kết',		'Bán kết',		'Chung kết',		'Tranh hạng ba'	},    -- The text and background colors are paired and when you set one, you should set the other (accessibility)    textColor = {head = '#202122', '#202122', '#202122', '#202122', '#202122'},	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 {{#invoke:RoundN|N512}} = {{invoke:RoundN|main|columns = 9}}for columns = 1, 9 do	local N = math.pow(2, columns)	p['N' .. N] = function(frame)		return p.main(frame.args, columns)	end	p['n' .. N] = p['N' .. N]--to make case insensitiveend--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 emptylocal 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 'border-top' or 'border-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.helperendlocal 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	endendlocal 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'] = 'center',			border = '1px solid #aaa',			['background-color'] = p.bgColor.head,			color = p.textColor.head		}	endendlocal function spacer(width)	tab.r:tag'td'		:attr{width = width}		:wikitext(p.no_column_head and '' or '&nbsp;')endlocal 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.previewnumbers and mw.clone(p.dpBoxBase) or 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))	endendp.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}local 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	)endlocal function maxSpan(span, start, rows)	return math.min(span, math.max(0, rows - start + 1))end--in case of templates like RDseed need padding valuep.teamBoxPadding = function()	return '.6ex'endp.teamBoxPadTab = {padding = '0 ' .. p.teamBoxPadding()}p.teamBoxNormal = {border = '1px solid #aaa', ['background-color'] = p.bgColor[4], color = p.textColor[4]}local 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'] = 'center'}	else		if not p.bold then		--backwards compatability (wikitemplates bold each arg individually)			local hasBold, b = tostring(v):gsub("([^']*)'''([^']*)", '%1<b>%2</b>')			if b == 1 then				v = hasBold			end		end		local cell		if f[1] then			cell = f.sumBox and f.sumBox[1] and				{padding = f.sumBox[1]}				or {['border-left'] = f.borderLeft}			cell['text-align'] = v and f[1]		else			cell = p.teamBoxPadTab		end		local text = v or f[1] and '' or '&nbsp;'		if f.bold then			text = mw.ustring.gsub(text, '(%(%[%[[^%[%]]*%]%]%))', '<span style="font-weight:normal">%1</span>')		end		tab.r = rowNum[r]:tag'td'			:css(p.teamBoxCSS)			:css(cell)			:attr{rowspan = 2}			:node(mw.html.create(f.bold and 'b'):wikitext(text))	endendfunction 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',		'color',		'color_repechage',		'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.namespace = mw.title.getCurrentTitle().namespace	p.previewnumbers = p.namespace ~= 0 and p.previewnumbers	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(				{{}, [p.scoreBoxes] = {'0 1ex'}},				{__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', height = '1ex'}					: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;border:0;', fontSize and '' or 'font-size:90%;border-collapse:separate;', 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	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 ('Round of ' .. math.pow(2, p.tCols - k + 1))			drawHead(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], ['border-right'] = 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}			)			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.color_repechage = p['color_repechage'] and ((c == p.tCols) or ((c == p.tCols-1) and skipMatch[math.pow(2, p.tCols) - 1]))		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) * (3 + p.scoreBoxes)									}								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)						if p.previewnumbers then												rowNum[m.r].nodes[#rowNum[m.r].nodes]								:tag'div'									:css{										float = 'left',										border = '1px 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					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						if col.color_repechage then							col.color_repechage = 2						end						if p.bold then							if m.bold.win(m.phase) and (colorFinal or col.color_repechage)  then								color_index = 1 + (col.show3rd or 0) + (col.color_repechage or 0)							elseif m.bold.box[#m.nonEmpty] then 								color_index = 2 + (col.show3rd or 0) + (col.color_repechage or 0)							else								color_index = 4							end							p.teamBoxCSS = (colorFinal or col.color_repechage) and								{border = p.teamBoxNormal.border, ['background-color'] = p.bgColor[color_index], color = p.textColor[color_index]}								or p.teamBoxNormal						else							p.teamBoxCSS = (colorFinal or col.color_repechage) and								{border = p.teamBoxNormal.border, ['background-color'] = p.bgColor[m.phase + (col.show3rd or 0) + (col.color_repechage or 0)], color = p.textColor[m.phase + (col.show3rd or 0) + (col.color_repechage or 0)]}								or p.teamBoxNormal						end						local f = {phase = m.phase, bold = m.bold.win(m.phase)}						teamBox(args[step + nodeArgs.team[m.phase]], m.r, f)						f[1] = 'center'						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 p.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>:<br>',								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						{['border-right'] = p.reuseStr.solid}						or {}					)			end			col.n = 0			col.t2 = nil			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 --draws the ']' when a PAIR of matches needs lines						tab.r							:attr{rowspan = maxSpan(p.unit * 2, r, rows)}							:css(skipMatch[col.tot + col.n / 2] and {} or {								border = p.reuseStr.solid,								['border-left'] = 0							})					else --draws the lines when only top OR bottom match need lines						tab.r							:attr{rowspan = maxSpan(p.unit, r, rows)}							:cssText(col.t == 2 and								p:saveStr('topRight', 'border-width:', tab.line[2], ' 0 0;border-style:solid')								or col.t == 1 and (nodeFunc.bridge.lay[c](col.n - 2) and									p:saveStr('right', ';border-right:', 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', 'border-width:0 ', tab.line[2], ' 0;border-style:solid')								or col.t == 2 and (nodeFunc.bridge.lay[c](col.n + 2) and									p:saveStr('right', ';border-right:', 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 {							['border-width'] = table.concat{tab.line[1][col.t[1]], ' 0 ', tab.line[1][col.t[2]]},							['border-style'] = 'solid'						} or {})				else					tab.r						:attr{rowspan = maxSpan(p.unit * 2, r, rows)}						:css(nodeFunc.bridge.lay[c](col.n) and							{['border-right'] = 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'border-bottom:1px 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',					['border-bottom'] = 'inherit',					['margin-right'] = '17px'				}				: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'] = '-3px'}					or tab				)			:done()		or tabend--[[local standard = {	'beta' = {		bold_winner = 'high',		omit_blanks = 'yes',		auto_3rd = 'yes'	}}--]]function p.main(frame, columns)	local args = require'Module:Arguments'.getArgs(frame, {trim = false})	args.columns = args.columns or columns	return p._main(args)endfunction p.seed(frame)	local parent = frame:getParent() or frame	local function arg(k, alt)		return parent.args[k] or frame.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 = ('-1px %s -1px -0.7ex'):format(padding, padding),			float = 'left',			['background-color'] = p.bgColor.head,			border = '1px solid #aaa',			color = p.textColor.head,			['text-align'] = 'center',			width = width		}		:wikitext(arg(1, '&nbsp;'))endreturn p