<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://nssportwiki.com/index.php?action=history&amp;feed=atom&amp;title=Module%3ABuild_bracket%2FParams</id>
	<title>Module:Build bracket/Params - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://nssportwiki.com/index.php?action=history&amp;feed=atom&amp;title=Module%3ABuild_bracket%2FParams"/>
	<link rel="alternate" type="text/html" href="https://nssportwiki.com/index.php?title=Module:Build_bracket/Params&amp;action=history"/>
	<updated>2026-08-15T12:25:38Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.40.1</generator>
	<entry>
		<id>https://nssportwiki.com/index.php?title=Module:Build_bracket/Params&amp;diff=76410&amp;oldid=prev</id>
		<title>Osarius: 1 revision imported</title>
		<link rel="alternate" type="text/html" href="https://nssportwiki.com/index.php?title=Module:Build_bracket/Params&amp;diff=76410&amp;oldid=prev"/>
		<updated>2026-07-24T10:50:38Z</updated>

		<summary type="html">&lt;p&gt;1 revision imported&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en-GB&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 10:50, 24 July 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;en-GB&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(No difference)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>Osarius</name></author>
	</entry>
	<entry>
		<id>https://nssportwiki.com/index.php?title=Module:Build_bracket/Params&amp;diff=76409&amp;oldid=prev</id>
		<title>wikipedia&gt;Pbrks: fix hide issues</title>
		<link rel="alternate" type="text/html" href="https://nssportwiki.com/index.php?title=Module:Build_bracket/Params&amp;diff=76409&amp;oldid=prev"/>
		<updated>2025-08-26T02:14:53Z</updated>

		<summary type="html">&lt;p&gt;fix hide issues&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local Params = {}&lt;br /&gt;
&lt;br /&gt;
-- =========================&lt;br /&gt;
-- 1) MODULE BINDINGS&lt;br /&gt;
-- =========================&lt;br /&gt;
-- Upvalues bound per call&lt;br /&gt;
local state, config, Helpers, StateChecks&lt;br /&gt;
&lt;br /&gt;
-- Stdlib aliases&lt;br /&gt;
local str_format = string.format&lt;br /&gt;
local t_insert = table.insert&lt;br /&gt;
local t_sort = table.sort&lt;br /&gt;
&lt;br /&gt;
-- Locals filled on bind (with safe fallbacks)&lt;br /&gt;
local isempty, notempty, bargs, getPArg, getFArg, toChar, split&lt;br /&gt;
&lt;br /&gt;
local function _toCharFallback(n)&lt;br /&gt;
    n = tonumber(n or 0) or 0&lt;br /&gt;
    if n &amp;gt;= 1 and n &amp;lt;= 26 then&lt;br /&gt;
        return string.char(96 + n) -- &amp;#039;a&amp;#039;..&amp;#039;z&amp;#039;&lt;br /&gt;
    end&lt;br /&gt;
    return tostring(n)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function bind(_state, _config, _Helpers, _StateChecks)&lt;br /&gt;
    state, config, Helpers, StateChecks = _state, _config, _Helpers, _StateChecks&lt;br /&gt;
    isempty = Helpers and Helpers.isempty or function(v)&lt;br /&gt;
            return v == nil or v == &amp;quot;&amp;quot;&lt;br /&gt;
        end&lt;br /&gt;
    notempty = Helpers and Helpers.notempty or function(v)&lt;br /&gt;
            return v ~= nil and v ~= &amp;quot;&amp;quot;&lt;br /&gt;
        end&lt;br /&gt;
    bargs = Helpers and Helpers.bargs&lt;br /&gt;
    getPArg = Helpers and Helpers.getPArg&lt;br /&gt;
    getFArg = Helpers and Helpers.getFArg&lt;br /&gt;
    toChar = (Helpers and Helpers.toChar) or _toCharFallback&lt;br /&gt;
    split = Helpers and Helpers.split&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Try both RDj[a]-X and RDj[A]-X; falls back to &amp;quot;&amp;quot; if not present&lt;br /&gt;
local function readPerHeaderArg(j, k, suffix)&lt;br /&gt;
    local ch = toChar(k) -- e.g. &amp;#039;a&amp;#039; with Helpers.toChar&lt;br /&gt;
    local key1 = &amp;quot;RD&amp;quot; .. j .. ch .. suffix&lt;br /&gt;
    local v = bargs(key1)&lt;br /&gt;
    if v ~= nil and v ~= &amp;quot;&amp;quot; then&lt;br /&gt;
        return v&lt;br /&gt;
    end&lt;br /&gt;
    local key2 = &amp;quot;RD&amp;quot; .. j .. string.upper(ch) .. suffix&lt;br /&gt;
    v = bargs(key2)&lt;br /&gt;
    if v ~= nil and v ~= &amp;quot;&amp;quot; then&lt;br /&gt;
        return v&lt;br /&gt;
    end&lt;br /&gt;
    return &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- =========================&lt;br /&gt;
-- 2) ARG HELPERS&lt;br /&gt;
-- =========================&lt;br /&gt;
-- Trim + split a comma list frame arg (returns {} on blank)&lt;br /&gt;
local function readCsvArg(name)&lt;br /&gt;
    local raw = (getFArg(name) or &amp;quot;&amp;quot;):gsub(&amp;quot;%s+&amp;quot;, &amp;quot;&amp;quot;)&lt;br /&gt;
    return split(raw, {&amp;quot;,&amp;quot;}, true)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- ========================================&lt;br /&gt;
-- 3) BUILD SKELETON (formerly getCells)&lt;br /&gt;
-- ========================================&lt;br /&gt;
local function buildSkeleton()&lt;br /&gt;
    local DEFAULT_TPM = 2&lt;br /&gt;
    local maxrow = 1&lt;br /&gt;
    local colentry = {}&lt;br /&gt;
    local hasNoHeaders = true&lt;br /&gt;
&lt;br /&gt;
    -- ensure containers&lt;br /&gt;
    state.entries = state.entries or {}&lt;br /&gt;
    state.shift = state.shift or {}&lt;br /&gt;
    state.teamsPerMatch = state.teamsPerMatch or {}&lt;br /&gt;
    state.maxtpm = state.maxtpm or 0&lt;br /&gt;
&lt;br /&gt;
    local Cmin, Cmax = config.minc, config.c&lt;br /&gt;
&lt;br /&gt;
    -- Phase 1: Determine header presence and teamsPerMatch&lt;br /&gt;
    for j = Cmin, Cmax do&lt;br /&gt;
        if notempty(getFArg(&amp;quot;col&amp;quot; .. j .. &amp;quot;-headers&amp;quot;)) then&lt;br /&gt;
            hasNoHeaders = false&lt;br /&gt;
        end&lt;br /&gt;
        local tpm =&lt;br /&gt;
            tonumber(getFArg(&amp;quot;RD&amp;quot; .. j .. &amp;quot;-teams-per-match&amp;quot;)) or tonumber(getFArg(&amp;quot;col&amp;quot; .. j .. &amp;quot;-teams-per-match&amp;quot;)) or&lt;br /&gt;
            tonumber(getFArg(&amp;quot;teams-per-match&amp;quot;)) or&lt;br /&gt;
            DEFAULT_TPM&lt;br /&gt;
        state.teamsPerMatch[j] = tpm&lt;br /&gt;
        if tpm &amp;gt; state.maxtpm then&lt;br /&gt;
            state.maxtpm = tpm&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Phase 2: Build colentry for each column&lt;br /&gt;
    for j = Cmin, Cmax do&lt;br /&gt;
        state.entries[j] = {}&lt;br /&gt;
        state.shift[j] = tonumber(bargs(&amp;quot;RD&amp;quot; .. j .. &amp;quot;-shift&amp;quot;)) or tonumber(bargs(&amp;quot;shift&amp;quot;)) or 0&lt;br /&gt;
&lt;br /&gt;
        colentry[j] = {&lt;br /&gt;
            readCsvArg(&amp;quot;col&amp;quot; .. j .. &amp;quot;-headers&amp;quot;),&lt;br /&gt;
            readCsvArg(&amp;quot;col&amp;quot; .. j .. &amp;quot;-matches&amp;quot;),&lt;br /&gt;
            readCsvArg(&amp;quot;col&amp;quot; .. j .. &amp;quot;-lines&amp;quot;),&lt;br /&gt;
            readCsvArg(&amp;quot;col&amp;quot; .. j .. &amp;quot;-text&amp;quot;),&lt;br /&gt;
            readCsvArg(&amp;quot;col&amp;quot; .. j .. &amp;quot;-groups&amp;quot;) -- reserved for user-specified groups&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        -- inject a default header if none were specified anywhere (unless noheaders=y/yes)&lt;br /&gt;
        local noheaders = (getFArg(&amp;quot;noheaders&amp;quot;) or &amp;quot;&amp;quot;):lower()&lt;br /&gt;
        if hasNoHeaders and (noheaders ~= &amp;quot;y&amp;quot; and noheaders ~= &amp;quot;yes&amp;quot;) then&lt;br /&gt;
            t_insert(colentry[j][1], 1)&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Ctype mapping for colentry positions&lt;br /&gt;
    local CTYPE_MAP = {&amp;quot;header&amp;quot;, &amp;quot;team&amp;quot;, &amp;quot;line&amp;quot;, &amp;quot;text&amp;quot;, &amp;quot;group&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
    -- Helpers to populate entries (preserve legacy shapes)&lt;br /&gt;
    local function populateTeam(j, rowIndex, n)&lt;br /&gt;
        local TPM = state.teamsPerMatch[j]&lt;br /&gt;
        -- scaffold a text row above when needed (legacy behavior)&lt;br /&gt;
        if state.entries[j][rowIndex - 1] == nil and state.entries[j][rowIndex - 2] == nil then&lt;br /&gt;
            state.entries[j][rowIndex - 2] = {ctype = &amp;quot;text&amp;quot;, index = n}&lt;br /&gt;
            state.entries[j][rowIndex - 1] = {ctype = &amp;quot;blank&amp;quot;}&lt;br /&gt;
        end&lt;br /&gt;
        -- first team (top)&lt;br /&gt;
        state.entries[j][rowIndex] = {ctype = &amp;quot;team&amp;quot;, index = TPM * n - (TPM - 1), position = &amp;quot;top&amp;quot;}&lt;br /&gt;
        state.entries[j][rowIndex + 1] = {ctype = &amp;quot;blank&amp;quot;}&lt;br /&gt;
        -- remaining teams in the match (every 2 rows)&lt;br /&gt;
        for m = 2, TPM do&lt;br /&gt;
            local idx = TPM * n - (TPM - m)&lt;br /&gt;
            local r = rowIndex + 2 * (m - 1)&lt;br /&gt;
            state.entries[j][r] = {ctype = &amp;quot;team&amp;quot;, index = idx}&lt;br /&gt;
            state.entries[j][r + 1] = {ctype = &amp;quot;blank&amp;quot;}&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local function populateText(j, rowIndex, index)&lt;br /&gt;
        state.entries[j][rowIndex] = {ctype = &amp;quot;text&amp;quot;, index = index}&lt;br /&gt;
        state.entries[j][rowIndex + 1] = {ctype = &amp;quot;blank&amp;quot;}&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local function populateLine(j, rowIndex)&lt;br /&gt;
        -- first segment draws its bottom edge&lt;br /&gt;
        state.entries[j][rowIndex] = {ctype = &amp;quot;line&amp;quot;, border = &amp;quot;bottom&amp;quot;}&lt;br /&gt;
        state.entries[j][rowIndex + 1] = {ctype = &amp;quot;blank&amp;quot;}&lt;br /&gt;
        -- second segment draws its top edge&lt;br /&gt;
        state.entries[j][rowIndex + 2] = {ctype = &amp;quot;line&amp;quot;, border = &amp;quot;top&amp;quot;}&lt;br /&gt;
        state.entries[j][rowIndex + 3] = {ctype = &amp;quot;blank&amp;quot;}&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local function populateGroup(j, rowIndex, n)&lt;br /&gt;
        state.entries[j][rowIndex] = {ctype = &amp;quot;group&amp;quot;, index = n}&lt;br /&gt;
        state.entries[j][rowIndex + 1] = {ctype = &amp;quot;blank&amp;quot;}&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local function populateDefault(j, rowIndex, n)&lt;br /&gt;
        state.entries[j][rowIndex] = {ctype = &amp;quot;header&amp;quot;, index = n, position = &amp;quot;top&amp;quot;}&lt;br /&gt;
        state.entries[j][rowIndex + 1] = {ctype = &amp;quot;blank&amp;quot;}&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Phase 3: Populate entries for each column&lt;br /&gt;
    for j = Cmin, Cmax do&lt;br /&gt;
        local textindex = 0&lt;br /&gt;
        local TPM = state.teamsPerMatch[j]&lt;br /&gt;
        local shiftJ = state.shift[j]&lt;br /&gt;
&lt;br /&gt;
        for k, positions in ipairs(colentry[j]) do&lt;br /&gt;
            t_sort(positions)&lt;br /&gt;
            local ctype = CTYPE_MAP[k]&lt;br /&gt;
&lt;br /&gt;
            for n = 1, #positions do&lt;br /&gt;
                if shiftJ ~= 0 and positions[n] &amp;gt; 1 then&lt;br /&gt;
                    positions[n] = positions[n] + shiftJ&lt;br /&gt;
                end&lt;br /&gt;
                local rowIndex = 2 * positions[n] - 1&lt;br /&gt;
                local lastRow = rowIndex + 2 * TPM - 1&lt;br /&gt;
                if lastRow &amp;gt; maxrow then&lt;br /&gt;
                    maxrow = lastRow&lt;br /&gt;
                end&lt;br /&gt;
&lt;br /&gt;
                if ctype == &amp;quot;team&amp;quot; then&lt;br /&gt;
                    populateTeam(j, rowIndex, n)&lt;br /&gt;
                    textindex = n&lt;br /&gt;
                elseif ctype == &amp;quot;text&amp;quot; then&lt;br /&gt;
                    populateText(j, rowIndex, textindex + n)&lt;br /&gt;
                elseif ctype == &amp;quot;line&amp;quot; then&lt;br /&gt;
                    populateLine(j, rowIndex)&lt;br /&gt;
                elseif ctype == &amp;quot;group&amp;quot; then&lt;br /&gt;
                    populateGroup(j, rowIndex, n)&lt;br /&gt;
                else&lt;br /&gt;
                    populateDefault(j, rowIndex, n)&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if isempty(config.r) then&lt;br /&gt;
        config.r = maxrow&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- ========================================&lt;br /&gt;
-- 4) NAME RESOLUTION HELPERS&lt;br /&gt;
-- ========================================&lt;br /&gt;
local function paramNames(cname, j, i, l)&lt;br /&gt;
    local function getArg(key)&lt;br /&gt;
        return bargs(key) or &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
    local function getP(key)&lt;br /&gt;
        return getPArg(key) or &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local e = state.entries[j][i]&lt;br /&gt;
    local RD = &amp;quot;RD&amp;quot; .. j&lt;br /&gt;
    local hidx = e.headerindex&lt;br /&gt;
    local hchar = toChar(hidx)&lt;br /&gt;
    local RDh = RD .. hchar&lt;br /&gt;
&lt;br /&gt;
    local SYNONYMS = {legs = {&amp;quot;legs&amp;quot;, &amp;quot;sets&amp;quot;}}&lt;br /&gt;
&lt;br /&gt;
    -- Try a list of names against base+index(+suffix); returns first non-empty&lt;br /&gt;
    local function tryAny(base, names, idx, suffix)&lt;br /&gt;
        suffix = suffix or &amp;quot;&amp;quot;&lt;br /&gt;
        for _, nm in ipairs(names) do&lt;br /&gt;
            local a = bargs(base .. &amp;quot;-&amp;quot; .. nm .. idx .. suffix) or &amp;quot;&amp;quot;&lt;br /&gt;
            if isempty(a) then&lt;br /&gt;
                a = bargs(base .. &amp;quot;-&amp;quot; .. nm .. string.format(&amp;quot;%02d&amp;quot;, idx) .. suffix) or &amp;quot;&amp;quot;&lt;br /&gt;
            end&lt;br /&gt;
            if notempty(a) then&lt;br /&gt;
                return a&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
        return &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local function tryBoth(base, name, idx, suffix)&lt;br /&gt;
        suffix = suffix or &amp;quot;&amp;quot;&lt;br /&gt;
        local a = getArg(base .. &amp;quot;-&amp;quot; .. name .. idx .. suffix)&lt;br /&gt;
        if isempty(a) then&lt;br /&gt;
            a = getArg(base .. &amp;quot;-&amp;quot; .. name .. str_format(&amp;quot;%02d&amp;quot;, idx) .. suffix)&lt;br /&gt;
        end&lt;br /&gt;
        return a&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Round names (prefer altname when present)&lt;br /&gt;
    local RDlabel = getArg(RD .. &amp;quot;-altname&amp;quot;) or RD&lt;br /&gt;
    local RDhlabel = getArg(RDh .. &amp;quot;-altname&amp;quot;) or RDh&lt;br /&gt;
&lt;br /&gt;
    local rname = {{RD, RDlabel}, {RDh, RDhlabel}}&lt;br /&gt;
    local name = {cname, getArg(cname .. &amp;quot;-altname&amp;quot;) or cname}&lt;br /&gt;
    local nameKeys = SYNONYMS[cname] or {name[1]}&lt;br /&gt;
    local index = {e.index, e.altindex}&lt;br /&gt;
    local result = {}&lt;br /&gt;
&lt;br /&gt;
    if cname == &amp;quot;header&amp;quot; then&lt;br /&gt;
        if hidx == 1 then&lt;br /&gt;
            for _, base in ipairs({rname[1], rname[2]}) do&lt;br /&gt;
                for k = 2, 1, -1 do&lt;br /&gt;
                    result[#result + 1] = getArg(base[k])&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        else&lt;br /&gt;
            for k = 2, 1, -1 do&lt;br /&gt;
                result[#result + 1] = getArg(rname[2][k])&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    elseif cname == &amp;quot;pheader&amp;quot; then&lt;br /&gt;
        if hidx == 1 then&lt;br /&gt;
            for _, base in ipairs({rname[1], rname[2]}) do&lt;br /&gt;
                for k = 2, 1, -1 do&lt;br /&gt;
                    result[#result + 1] = getP(base[k])&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        else&lt;br /&gt;
            for k = 2, 1, -1 do&lt;br /&gt;
                result[#result + 1] = getP(rname[2][k])&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    elseif cname == &amp;quot;score&amp;quot; then&lt;br /&gt;
        local bases = {rname[2][2], rname[2][1], rname[1][2], rname[1][1]}&lt;br /&gt;
        local idxs = {index[2], index[2], index[1], index[1]}&lt;br /&gt;
        for n = 1, 4 do&lt;br /&gt;
            if l == 1 then&lt;br /&gt;
                result[#result + 1] = tryAny(bases[n], nameKeys, idxs[n])&lt;br /&gt;
            end&lt;br /&gt;
            result[#result + 1] = tryAny(bases[n], nameKeys, idxs[n], &amp;quot;-&amp;quot; .. l)&lt;br /&gt;
        end&lt;br /&gt;
    elseif cname == &amp;quot;shade&amp;quot; then&lt;br /&gt;
        for k = 2, 1, -1 do&lt;br /&gt;
            local base = (hidx == 1) and rname[1][k] or rname[2][k]&lt;br /&gt;
            result[#result + 1] = getArg(base .. &amp;quot;-&amp;quot; .. name[1])&lt;br /&gt;
        end&lt;br /&gt;
        result[#result + 1] = getArg(&amp;quot;RD-shade&amp;quot;)&lt;br /&gt;
        result[#result + 1] = (config.COLORS and config.COLORS.cell_bg_dark) or &amp;quot;#eaecf0&amp;quot;&lt;br /&gt;
    elseif cname == &amp;quot;text&amp;quot; then&lt;br /&gt;
        local bases = {rname[2][2], rname[2][1], rname[1][2], rname[1][1]}&lt;br /&gt;
        local idxs = {index[2], index[2], index[1], index[1]}&lt;br /&gt;
        local names = {name[2], name[1]}&lt;br /&gt;
        for ni = 1, 2 do&lt;br /&gt;
            for n = 1, 4 do&lt;br /&gt;
                result[#result + 1] = tryBoth(bases[n], names[ni], idxs[n])&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    else&lt;br /&gt;
        local bases = {rname[2][2], rname[2][1], rname[1][2], rname[1][1]}&lt;br /&gt;
        local idxs = {index[2], index[2], index[1], index[1]}&lt;br /&gt;
        for n = 1, 4 do&lt;br /&gt;
            result[#result + 1] = tryAny(bases[n], nameKeys, idxs[n])&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    for _, val in ipairs(result) do&lt;br /&gt;
        if notempty(val) then&lt;br /&gt;
            return val&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- ========================================&lt;br /&gt;
-- 5) NUMBERED PARAM MODE&lt;br /&gt;
-- ========================================&lt;br /&gt;
local masterindex = 1&lt;br /&gt;
&lt;br /&gt;
local function numberedParams(j)&lt;br /&gt;
    local row = state.entries[j]&lt;br /&gt;
    if not row then&lt;br /&gt;
        return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local function nextArg()&lt;br /&gt;
        local v = bargs(tostring(masterindex)) or &amp;quot;&amp;quot;&lt;br /&gt;
        masterindex = masterindex + 1&lt;br /&gt;
        return v&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local R = config.r&lt;br /&gt;
    for i = 1, R do&lt;br /&gt;
        local e = row[i]&lt;br /&gt;
        if e then&lt;br /&gt;
            local ct = e.ctype&lt;br /&gt;
            if ct == &amp;quot;team&amp;quot; then&lt;br /&gt;
                local legs = state.rlegs[j]&lt;br /&gt;
&lt;br /&gt;
                if config.forceseeds then&lt;br /&gt;
                    e.seed = nextArg()&lt;br /&gt;
                end&lt;br /&gt;
&lt;br /&gt;
                e.team = nextArg()&lt;br /&gt;
                e.legs = paramNames(&amp;quot;legs&amp;quot;, j, i)&lt;br /&gt;
                e.score = {weight = {}}&lt;br /&gt;
                e.weight = &amp;quot;normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
                if notempty(e.legs) then&lt;br /&gt;
                    legs = tonumber(e.legs) or legs&lt;br /&gt;
                end&lt;br /&gt;
&lt;br /&gt;
                for l = 1, legs do&lt;br /&gt;
                    e.score[l] = nextArg()&lt;br /&gt;
                    e.score.weight[l] = &amp;quot;normal&amp;quot;&lt;br /&gt;
                end&lt;br /&gt;
&lt;br /&gt;
                if config.aggregate and legs &amp;gt; 1 then&lt;br /&gt;
                    e.score.agg = nextArg()&lt;br /&gt;
                    e.score.weight.agg = &amp;quot;normal&amp;quot;&lt;br /&gt;
                end&lt;br /&gt;
            elseif ct == &amp;quot;header&amp;quot; then&lt;br /&gt;
                e.header = paramNames(&amp;quot;header&amp;quot;, j, i)&lt;br /&gt;
                e.pheader = paramNames(&amp;quot;pheader&amp;quot;, j, i)&lt;br /&gt;
                e.shade = paramNames(&amp;quot;shade&amp;quot;, j, i)&lt;br /&gt;
            elseif ct == &amp;quot;text&amp;quot; then&lt;br /&gt;
                e.text = nextArg()&lt;br /&gt;
            elseif ct == &amp;quot;group&amp;quot; then&lt;br /&gt;
                e.group = nextArg()&lt;br /&gt;
            elseif ct == &amp;quot;line&amp;quot; and e.hastext == true then&lt;br /&gt;
                e.text = nextArg()&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- ========================================&lt;br /&gt;
-- 6) NAMED MODE ASSIGNERS (per-ctype)&lt;br /&gt;
-- ========================================&lt;br /&gt;
local function cellHasMeaningfulContent(e)&lt;br /&gt;
    if not e then&lt;br /&gt;
        return false&lt;br /&gt;
    end&lt;br /&gt;
    if e.ctype == &amp;quot;team&amp;quot; then&lt;br /&gt;
        return notempty(e.team)&lt;br /&gt;
    end&lt;br /&gt;
    if e.ctype == &amp;quot;text&amp;quot; then&lt;br /&gt;
        return notempty(e.text)&lt;br /&gt;
    end&lt;br /&gt;
    if e.ctype == &amp;quot;group&amp;quot; then&lt;br /&gt;
        return notempty(e.group)&lt;br /&gt;
    end&lt;br /&gt;
    if e.ctype == &amp;quot;line&amp;quot; and e.hastext == true then&lt;br /&gt;
        return notempty(e.text)&lt;br /&gt;
    end&lt;br /&gt;
    return false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function enforceContentUnhide(j)&lt;br /&gt;
    if not (state.hide and state.hide[j]) then&lt;br /&gt;
        return&lt;br /&gt;
    end&lt;br /&gt;
    local explicit = (state._hideExplicit and state._hideExplicit[j]) or {}&lt;br /&gt;
    local R = config.r&lt;br /&gt;
&lt;br /&gt;
    -- If master hid a header, but we later discover content in that header,&lt;br /&gt;
    -- flip it visible unless there was an EXPLICIT per-header hide.&lt;br /&gt;
    for i = 1, R do&lt;br /&gt;
        local e = state.entries[j][i]&lt;br /&gt;
        if e and e.headerindex then&lt;br /&gt;
            local h = e.headerindex&lt;br /&gt;
            if state.hide[j][h] and cellHasMeaningfulContent(e) then&lt;br /&gt;
                state.hide[j][h] = false&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function assignTeamParams(j, i)&lt;br /&gt;
    local legs = state.rlegs[j]&lt;br /&gt;
    local e = state.entries[j][i]&lt;br /&gt;
&lt;br /&gt;
    e.seed = paramNames(&amp;quot;seed&amp;quot;, j, i)&lt;br /&gt;
    e.team = paramNames(&amp;quot;team&amp;quot;, j, i)&lt;br /&gt;
    e.legs = paramNames(&amp;quot;legs&amp;quot;, j, i)&lt;br /&gt;
    e.score = {weight = {}}&lt;br /&gt;
    e.weight = &amp;quot;normal&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    if notempty(e.legs) then&lt;br /&gt;
        legs = tonumber(e.legs) or legs&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if config.autolegs then&lt;br /&gt;
        local l = 1&lt;br /&gt;
        repeat&lt;br /&gt;
            e.score[l] = paramNames(&amp;quot;score&amp;quot;, j, i, l)&lt;br /&gt;
            e.score.weight[l] = &amp;quot;normal&amp;quot;&lt;br /&gt;
            l = l + 1&lt;br /&gt;
        until isempty(paramNames(&amp;quot;score&amp;quot;, j, i, l))&lt;br /&gt;
        legs = l - 1&lt;br /&gt;
    else&lt;br /&gt;
        for l = 1, legs do&lt;br /&gt;
            e.score[l] = paramNames(&amp;quot;score&amp;quot;, j, i, l)&lt;br /&gt;
            e.score.weight[l] = &amp;quot;normal&amp;quot;&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if config.aggregate and legs &amp;gt; 1 then&lt;br /&gt;
        e.score.agg = paramNames(&amp;quot;score&amp;quot;, j, i, &amp;quot;agg&amp;quot;)&lt;br /&gt;
        e.score.weight.agg = &amp;quot;normal&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function assignHeaderParams(j, i)&lt;br /&gt;
    local e = state.entries[j][i]&lt;br /&gt;
    e.header = paramNames(&amp;quot;header&amp;quot;, j, i)&lt;br /&gt;
    e.pheader = paramNames(&amp;quot;pheader&amp;quot;, j, i)&lt;br /&gt;
    e.shade = paramNames(&amp;quot;shade&amp;quot;, j, i)&lt;br /&gt;
&lt;br /&gt;
    -- Did shade originate from an RD*-shade param?&lt;br /&gt;
    local hchar = toChar(e.headerindex)&lt;br /&gt;
    local rdNames = {&lt;br /&gt;
        &amp;quot;RD&amp;quot; .. j .. &amp;quot;-shade&amp;quot;,&lt;br /&gt;
        &amp;quot;RD&amp;quot; .. j .. hchar .. &amp;quot;-shade&amp;quot;,&lt;br /&gt;
        &amp;quot;RD-shade&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
    e.shade_is_rd = false&lt;br /&gt;
    for _, pname in ipairs(rdNames) do&lt;br /&gt;
        local v = bargs(pname)&lt;br /&gt;
        if notempty(v) and e.shade == v then&lt;br /&gt;
            e.shade_is_rd = true&lt;br /&gt;
            break&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function assignTextParams(j, i)&lt;br /&gt;
    state.entries[j][i].text = paramNames(&amp;quot;text&amp;quot;, j, i)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function assignGroupParams(j, i)&lt;br /&gt;
    state.entries[j][i].group = paramNames(&amp;quot;group&amp;quot;, j, i)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function assignLineTextParams(j, i)&lt;br /&gt;
    state.entries[j][i].text = paramNames(&amp;quot;text&amp;quot;, j, i)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- ========================================&lt;br /&gt;
-- 7) TABLE-WIDE ASSIGNMENT PASS&lt;br /&gt;
-- ========================================&lt;br /&gt;
local function getScalarRoundParam(j, bases) -- e.g. {&amp;quot;legs&amp;quot;,&amp;quot;sets&amp;quot;}&lt;br /&gt;
    -- prefer per-round keys, then global&lt;br /&gt;
    for _, base in ipairs(bases) do&lt;br /&gt;
        local v = bargs(&amp;quot;RD&amp;quot; .. j .. &amp;quot;-&amp;quot; .. base)&lt;br /&gt;
        if notempty(v) then&lt;br /&gt;
            return v&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    for _, base in ipairs(bases) do&lt;br /&gt;
        local v = bargs(base)&lt;br /&gt;
        if notempty(v) then&lt;br /&gt;
            return v&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function assignParams()&lt;br /&gt;
    masterindex = 1&lt;br /&gt;
    local maxcol = 1&lt;br /&gt;
&lt;br /&gt;
    local Cmin, Cmax, R = config.minc, config.c, config.r&lt;br /&gt;
&lt;br /&gt;
    for j = Cmin, Cmax do&lt;br /&gt;
        -- prepare per-round containers&lt;br /&gt;
        state.hide[j] = state.hide[j] or {}&lt;br /&gt;
        state.byes[j] = state.byes[j] or {}&lt;br /&gt;
&lt;br /&gt;
        -- Set legs for this column&lt;br /&gt;
        local vlegs = getScalarRoundParam(j, {&amp;quot;legs&amp;quot;, &amp;quot;sets&amp;quot;})&lt;br /&gt;
        state.rlegs[j] = tonumber(vlegs) or 1&lt;br /&gt;
        if notempty(vlegs) then&lt;br /&gt;
            config.autolegs = false&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        -- assign params&lt;br /&gt;
        if config.paramstyle == &amp;quot;numbered&amp;quot; then&lt;br /&gt;
            numberedParams(j)&lt;br /&gt;
        else&lt;br /&gt;
            local col = state.entries[j]&lt;br /&gt;
            for i = 1, R do&lt;br /&gt;
                local cell = col[i]&lt;br /&gt;
                if cell ~= nil then&lt;br /&gt;
                    local ct = cell.ctype&lt;br /&gt;
                    if ct == &amp;quot;team&amp;quot; then&lt;br /&gt;
                        assignTeamParams(j, i)&lt;br /&gt;
                    elseif ct == &amp;quot;header&amp;quot; then&lt;br /&gt;
                        assignHeaderParams(j, i)&lt;br /&gt;
                    elseif ct == &amp;quot;text&amp;quot; then&lt;br /&gt;
                        assignTextParams(j, i)&lt;br /&gt;
                    elseif ct == &amp;quot;group&amp;quot; then&lt;br /&gt;
                        assignGroupParams(j, i)&lt;br /&gt;
                    elseif ct == &amp;quot;line&amp;quot; and cell.hastext == true then&lt;br /&gt;
                        assignLineTextParams(j, i)&lt;br /&gt;
                    end&lt;br /&gt;
                end&lt;br /&gt;
                if config.autocol and not StateChecks.isBlankEntry(j, i) and j &amp;gt; maxcol then&lt;br /&gt;
                    maxcol = j&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        enforceContentUnhide(j)&lt;br /&gt;
&lt;br /&gt;
        -- parent header text forces visible&lt;br /&gt;
        for i = 1, R do&lt;br /&gt;
            local e = state.entries[j][i]&lt;br /&gt;
            if e and e.ctype == &amp;quot;header&amp;quot; then&lt;br /&gt;
                local hidx = e.headerindex&lt;br /&gt;
                if (Helpers.notempty and Helpers.notempty(e.pheader)) then&lt;br /&gt;
                    state.hide[j][hidx] = false&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    if config.autocol then&lt;br /&gt;
        config.c = maxcol&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- ========================================&lt;br /&gt;
-- 8) STRUCTURE DISCOVERY (hide/byes/indices)&lt;br /&gt;
-- ========================================&lt;br /&gt;
local function getHide(j)&lt;br /&gt;
    state.hide[j] = {}&lt;br /&gt;
    state._hideExplicit = state._hideExplicit or {}&lt;br /&gt;
    state._hideExplicit[j] = {}&lt;br /&gt;
&lt;br /&gt;
    -- master round-level hide flag: RD{j}-hide&lt;br /&gt;
    local masterRaw = bargs(&amp;quot;RD&amp;quot; .. j .. &amp;quot;-hide&amp;quot;) or &amp;quot;&amp;quot;&lt;br /&gt;
    local masterOn = (Helpers and Helpers.yes and Helpers.yes(masterRaw)) or false&lt;br /&gt;
&lt;br /&gt;
    for k = 1, state.headerindex[j] do&lt;br /&gt;
        state.hide[j][k] = masterOn&lt;br /&gt;
&lt;br /&gt;
        -- per-header override&lt;br /&gt;
        local rh = readPerHeaderArg(j, k, &amp;quot;-hide&amp;quot;)&lt;br /&gt;
        if rh ~= &amp;quot;&amp;quot; then&lt;br /&gt;
            if Helpers and Helpers.yes and Helpers.yes(rh) then&lt;br /&gt;
                state.hide[j][k] = true&lt;br /&gt;
                state._hideExplicit[j][k] = true&lt;br /&gt;
            elseif Helpers and Helpers.no and Helpers.no(rh) then&lt;br /&gt;
                state.hide[j][k] = false&lt;br /&gt;
                state._hideExplicit[j][k] = true&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getByes(j)&lt;br /&gt;
    state.byes[j] = {}&lt;br /&gt;
    for k = 1, state.headerindex[j] do&lt;br /&gt;
        -- global byes&lt;br /&gt;
        local byes = (bargs(&amp;quot;byes&amp;quot;) or &amp;quot;&amp;quot;):lower()&lt;br /&gt;
        if (Helpers.yes and Helpers.yes(byes)) then&lt;br /&gt;
            state.byes[j][k] = true&lt;br /&gt;
        elseif tonumber(byes) then&lt;br /&gt;
            state.byes[j][k] = (j &amp;lt;= tonumber(byes))&lt;br /&gt;
        else&lt;br /&gt;
            state.byes[j][k] = false&lt;br /&gt;
        end&lt;br /&gt;
        -- per-round byes&lt;br /&gt;
        local r = (bargs(&amp;quot;RD&amp;quot; .. j .. &amp;quot;-byes&amp;quot;) or &amp;quot;&amp;quot;):lower()&lt;br /&gt;
        if (Helpers.yes and Helpers.yes(r)) then&lt;br /&gt;
            state.byes[j][k] = true&lt;br /&gt;
        elseif r == &amp;quot;no&amp;quot; or r == &amp;quot;n&amp;quot; then&lt;br /&gt;
            state.byes[j][k] = false&lt;br /&gt;
        end&lt;br /&gt;
        -- per-header byes&lt;br /&gt;
        local rh = (readPerHeaderArg(j, k, &amp;quot;-byes&amp;quot;) or &amp;quot;&amp;quot;):lower()&lt;br /&gt;
        if (Helpers.yes and Helpers.yes(rh)) then&lt;br /&gt;
            state.byes[j][k] = true&lt;br /&gt;
        elseif rh == &amp;quot;no&amp;quot; or rh == &amp;quot;n&amp;quot; then&lt;br /&gt;
            state.byes[j][k] = false&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getAltIndices()&lt;br /&gt;
    local Cmin, Cmax, R = config.minc, config.c, config.r&lt;br /&gt;
&lt;br /&gt;
    for j = Cmin, Cmax do&lt;br /&gt;
        state.headerindex[j] = 0&lt;br /&gt;
&lt;br /&gt;
        -- per-round counters&lt;br /&gt;
        local teamindex, textindex, groupindex = 1, 1, 1&lt;br /&gt;
        local row = state.entries[j]&lt;br /&gt;
&lt;br /&gt;
        -- if the very first cell is nil, bump headerindex once (legacy quirk)&lt;br /&gt;
        if row and row[1] == nil then&lt;br /&gt;
            state.headerindex[j] = state.headerindex[j] + 1&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        -- walk rows in the round&lt;br /&gt;
        for i = 1, R do&lt;br /&gt;
            local e = row and row[i] or nil&lt;br /&gt;
            if e then&lt;br /&gt;
                local ct = e.ctype&lt;br /&gt;
                if ct == &amp;quot;header&amp;quot; then&lt;br /&gt;
                    e.altindex = state.headerindex[j]&lt;br /&gt;
                    teamindex, textindex = 1, 1&lt;br /&gt;
                    state.headerindex[j] = state.headerindex[j] + 1&lt;br /&gt;
                elseif ct == &amp;quot;team&amp;quot; then&lt;br /&gt;
                    e.altindex = teamindex&lt;br /&gt;
                    teamindex = teamindex + 1&lt;br /&gt;
                elseif ct == &amp;quot;text&amp;quot; or (ct == &amp;quot;line&amp;quot; and e.hastext == true) then&lt;br /&gt;
                    e.altindex = textindex&lt;br /&gt;
                    textindex = textindex + 1&lt;br /&gt;
                elseif ct == &amp;quot;group&amp;quot; then&lt;br /&gt;
                    e.altindex = groupindex&lt;br /&gt;
                    groupindex = groupindex + 1&lt;br /&gt;
                end&lt;br /&gt;
                e.headerindex = state.headerindex[j]&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        getByes(j)&lt;br /&gt;
        getHide(j)&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- ========================================&lt;br /&gt;
-- 9) PUBLIC API&lt;br /&gt;
-- ========================================&lt;br /&gt;
function Params.buildSkeleton(_state, _config, _Helpers, _StateChecks)&lt;br /&gt;
    bind(_state, _config, _Helpers, _StateChecks)&lt;br /&gt;
    buildSkeleton()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Params.scanStructure(_state, _config, _Helpers, _StateChecks)&lt;br /&gt;
    bind(_state, _config, _Helpers, _StateChecks)&lt;br /&gt;
    getAltIndices()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Params.assign(_state, _config, _Helpers, _StateChecks)&lt;br /&gt;
    bind(_state, _config, _Helpers, _StateChecks)&lt;br /&gt;
    assignParams()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- ========================================&lt;br /&gt;
-- 10) SLICING FOR MIN ROUND (base offset)&lt;br /&gt;
-- ========================================&lt;br /&gt;
local function shiftCols(tbl, base, c)&lt;br /&gt;
    if not tbl then&lt;br /&gt;
        return {}&lt;br /&gt;
    end&lt;br /&gt;
    local out = {}&lt;br /&gt;
    for j = base + 1, c do&lt;br /&gt;
        out[j - base] = tbl[j]&lt;br /&gt;
    end&lt;br /&gt;
    return out&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Params.sliceForMinround(_state, _config)&lt;br /&gt;
    local base = _config.base or 0&lt;br /&gt;
    if base &amp;lt;= 0 then&lt;br /&gt;
        return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local oldC = _config.c&lt;br /&gt;
    local newC = oldC - base&lt;br /&gt;
    if newC &amp;lt; 1 then&lt;br /&gt;
        newC = 1&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Shift all column-indexed tables&lt;br /&gt;
    _state.entries = shiftCols(_state.entries, base, oldC)&lt;br /&gt;
    _state.headerindex = shiftCols(_state.headerindex, base, oldC)&lt;br /&gt;
    _state.rlegs = shiftCols(_state.rlegs, base, oldC)&lt;br /&gt;
    _state.maxlegs = {} -- recompute later&lt;br /&gt;
    _state.hascross = {} -- rebuild later&lt;br /&gt;
    _state.crossCell = {} -- rebuild later&lt;br /&gt;
    _state.pathCell = {} -- rebuild later&lt;br /&gt;
    _state.skipPath = {} -- rebuild later&lt;br /&gt;
    _state.hide = shiftCols(_state.hide, base, oldC)&lt;br /&gt;
    _state.byes = shiftCols(_state.byes, base, oldC)&lt;br /&gt;
    _state.teamsPerMatch = shiftCols(_state.teamsPerMatch, base, oldC)&lt;br /&gt;
    _state.matchgroup = {} -- recompute&lt;br /&gt;
&lt;br /&gt;
    -- Update view range: now we render 1..newC&lt;br /&gt;
    _config.c = newC&lt;br /&gt;
    _config.minc = 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return Params&lt;/div&gt;</summary>
		<author><name>wikipedia&gt;Pbrks</name></author>
	</entry>
</feed>