Mô đun:RoundN

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.reuseStrname then
			self.reuseStrname = table.concat{...}
		end
		return self.reuseStrname
	end
}
--Provides a convenient naming shortcut up to N512 = 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 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 tablek
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.ipi = v
		setmetatable(p.nilAsTab.tp.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}) -- infiniteEmpty123...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 argsstep then
			self.pattern, self.nonFunc = string.match(esc.bs:text(argsstep), '^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 selffunc and selffunc.main then
					self.patternk = 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
						selffunc.arg = selffunc.arg or {}
						selffunc.argm.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.argm.num or , h.topBranch()
				isTop = topId == 0
				notTop = {isTop and 1 or 0 = p.reuseStr.solid}
				for k = 0, 1 do
					tab.r = rowNumm.r + k * 4:tag'td'
						:css(notTopk and
							{isTop and 'border-top' or 'border-bottom' = notTopk}
							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.laycol.cm.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 = rowNumm.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
local 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
			rowNumbodyRow.first = first
			rowNumbodyRow.first.unchanged = true
		end
	end
end
local function drawHead(text, row3rd)
	local td = (row3rd and rowNumrow3rd: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
		}
	end
end
local function spacer(width)
	tab.r:tag'td'
		:attr{width = width}
		:wikitext(p.no_column_head and  or ' ')
end
local 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)
		rowNumr:node(p.dpBoxEmpty)
	else
		rowNumr: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
				sumteam = sumteam + score
			end
		end
		return unpack(math.max(unpack(sum)) == math.huge and {'—', '—'} 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
	)
end
local 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 = {border = '1px solid #aaa', 'background-color' = p.bgColor4, color = p.textColor4}
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 rowNumr + i.first.unchanged then
				rowNumr + i.first.unchanged = nil
				rowNumr + 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%2')
			if b == 1 then
				v = hasBold
			end
		end
		local cell
		if f1 then
			cell = f.sumBox and f.sumBox1 and
				{padding = f.sumBox1}
				or {'border-left' = f.borderLeft}
			cell'text-align' = v and f1
		else
			cell = p.teamBoxPadTab
		end
		local text = v or f1 and  or ' '
		if f.bold then
			text = mw.ustring.gsub(text, '(%(%%^%%*%%%))', '%1')
		end
		tab.r = rowNumr:tag'td'
			:css(p.teamBoxCSS)
			:css(cell)
			:attr{rowspan = 2}
			:node(mw.html.create(f.bold and 'b'):wikitext(text))
	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 = argskey 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
		argskey = params.keepOld and argskey 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
				mTypemNum = args:clean(k) == 'yes' or argsk == '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
						mTypey = true
					end
				end
				for _, x in ipairs(mw.text.split(argsk:gsub(matchPer.pattern, ):gsub(';%-%a;%-%a+', ';'):match('^;*(.-);%-*$'), ';')) do
					x = mw.text.split(x, '-')
					for y = tonumber(x1) or 1, tonumber(x2 or x1) or 0 do
						mTypey = 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 argsv and (pv == nil or type(pv) == 'boolean') then
			pv = args:clean(v) == 'yes' or argsv == '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(
				,
				{__call = function(t, i) if ti then return nil end return 0 end}
			)
			or setmetatable(
				{},
				{__call = function() return 0 end}
			)
		)
		or setmetatable({}, {__call = function() return nil end})
	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.team1 = 1--constant to be replaced later by new param
	nodeArgs.team2 = nodeArgs.team1 + nodeArgs.team.offset
	nodeArgs.blank = setmetatable({}, nodeArgs.tableSum)
	p.unflex_div = mw.html.create'div'
					:css{overflow = 'hidden', height = '1ex'}
					:wikitext' '
	p.flex_tree = setmetatable({},{__index = {
		merge = p.flex_tree and p.scoreBoxes == 0,
		wt = p.flex_tree and  or ' ',
		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 {}
	scoreWidth1 = tonumber(scoreWidth1, 10)
	if p.scoreSumBox and #scoreWidth ~= 1 then
		local _scoreWidth = {}
		for k = 1, p.scoreBoxes - 1 do
			_scoreWidthk = tonumber(scoreWidthk, 10) or math.ceil(sp2 * 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('/', '%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(sp3)
			spacer(sp4)
			if not p.no_column_head then
				head.row:tag'td':attr{colspan = 2}
			end
		end
		spacer(sp1)
		for s = 1, p.scoreBoxes do
			spacer(#scoreWidth == 1 and scoreWidth1 or scoreWidths or sp2)
		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.RD4
		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.line1true, ' solid')
	p.cornerDiv = mw.html.create'div':css{height = tab.line1true, '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
				rowNum1:tag'td':attr{rowspan = 4}
			else
			rowNum1:node(c  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 skipMatchmath.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 rowNumm.r and m.num  1 then --if 3rd place extends below bottom cell
									rowNumrows + 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 argsstep, m.r)
						if p.previewnumbers then					
							rowNumm.r.nodes#rowNumm.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 argsi1 or argsi2 then
								table.insert(m.nonEmpty, i)
							end
						end
						if p.bold and m.showBox2 and m.showBox3 and not unBoldm.num then
							m.bold = {
								box = {},
								clean = {}
							}
							local notSummed = not p.scoreSumBox or #m.nonEmpty |demoWash=:',
								mw.dumpObject{scores = m.bold.clean, cycles = p.scoreWasher.cycles, sum = p.scoreSumBox and {m.nonEmpty#m.nonEmpty1, m.nonEmpty#m.nonEmpty1}},
								,
								tostring(sp.row), ,
								tostring(rowNumm.r - 4), ,
								tostring(rowNumm.r - 2), ,
								tostring(rowNumm.r), ,
							}
						end
						if nodeFunc.orphan.num == m.num then
							skipMatchm.num = 'orphan'
						end
						step = step + m.showBox
						m.num = m.num + 1
						if bump > 0 and rowNumm.r + 2 and not (nodeFunc.pattern and nodeFunc.called.canvas) then
							bumps = bumps + p.span
							rowNumm.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)
			rowNum1
				:tag'td':attr{rowspan = bumps}
			if not p.branch_upwards then
				rowNum1:tag'td'
					:attr{rowspan = (p.branch_upwards or bump) + 4}
					:css(nodeFunc.bridge.layc(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 = rowNumr: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 skipMatchcol.tot + col.n / 2 + 1 and 3 or ((skipMatchcol.top and 1 or 0) + (skipMatchcol.top + 1 and 2 or 0))
					col.n = col.n + 2
					col.t2 = skipMatchcol.tot + col.n / 2 + 1 and 3 or ((skipMatchcol.top + col.n and 1 or 0) + (skipMatchcol.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(skipMatchcol.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.line2, ' 0 0;border-style:solid')
								or col.t == 1 and (nodeFunc.bridge.layc(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.layc(col.n - 2) and p.cornerDiv)
						rowNumr + (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.line2, ' 0;border-style:solid')
								or col.t == 2 and (nodeFunc.bridge.layc(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.layc(col.n + 2) and p.cornerDiv)
					end
					col.t = {
						col.t < 3,
						rowNumr + p.unit * 5 and col.t2 < 3 or false
					}
					rowNumr + (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.t1 or col.t2) and {
							'border-width' = table.concat{tab.line1col.t1, ' 0 ', tab.line1col.t2},
							'border-style' = 'solid'
						} or {})
				else
					tab.r
						:attr{rowspan = maxSpan(p.unit * 2, r, rows)}
						:css(nodeFunc.bridge.layc(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 tab
end
--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)
end
function p.seed(frame)
	local parent = frame:getParent() or frame
	local function arg(k, alt)
		return parent.argsk or frame.argsk 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, ' '))
end
return p