Module:Standings

local util_args = require('Module:ArgsUtil') local util_cargo = require('Module:CargoUtil') local util_esports = require('Module:EsportsUtil') local util_footnote = require('Module:FootnoteUtil') local util_html = require('Module:HtmlUtil') local util_map = require('Module:MapUtil') local util_math = require('Module:MathUtil') local util_table = require('Module:TableUtil') local util_text = require('Module:TextUtil') local util_tournament = require('Module:TournamentUtil') local util_vars = require('Module:VarsUtil') local m_team = require('Module:Team') local Region = require('Module:Region') local i18n = require('Module:I18nUtil')

local Legend = require('Module:Legend')._main local PopupButton = require('Module:PopupButton')

local lang = mw.getLanguage('en') local sep = '%s*,%s*' local argsep = '%s*;;;%s*'

local PRELOADS = { bo1 = { columns = 'bo1', sortmethod = 'record', },	bo1points = { columns = 'bo1points', sortmethod = 'points', },	bo2 = { isbo2 = true, columns = 'bo2', sortmethod = 'bo2points' },	bo2onlypoints = { isbo2 = true, columns = 'bo2', sortmethod = 'points' },	bo2nopoints = { isbo2 = true, columns = 'bo2nopoints', sortmethod = 'recordgames' },	bo3 = { columns = 'series', sortmethod = 'record', },	bo3diff = { columns = 'bo3diff', sortmethod = 'recordwithgames' },	bo3points = { columns = 'seriespt', sortmethod = 'recordwithpoints', },	bo3gamepoints = { columns = 'bo3gamepoints', sortmethod = 'points' },	bo3hiddenpoints = { columns = 'series', sortmethod = 'recordwithpoints' },	bo3fakepoints = { columns = 'series', sortmethod = 'recordwithgames' },	bo3orderbygames = { columns = 'series', sortmethod = 'recordwithgamesnotb' },	bo5 = { columns = 'series', sortmethod = 'recordwithgames', },	bo5points = { columns = 'seriespt', sortmethod = 'recordwithpoints', },	bo5ns = { columns = 'bo5ns', sortmethod = 'recordwithgames', },	bo5nsp = { columns = 'bo5nsp', sortmethod = 'recordwithgames', },	bo5nm = { columns = 'bo5nm', sortmethod = 'record', }, }

local HEADING_DATA = { Place = { name = '', colspan = 1 }, Games = { colspan = 2, fields = { 'Games', 'GamesPct' } }, GamesBO1 = { colspan = 2, fields = { 'Series', 'SeriesPct' } }, GamesBO5 = { colspan = 2, fields = { 'Series', 'SeriesPct' } }, GamesDiff = { colspan = 3, fields = { 'Games', 'GamesPct', 'Diff' } }, Team = { colspan = 1 }, Series = { colspan = 2, fields = { 'Series', 'SeriesPct' } }, SeriesBO2 = { colspan = 1 }, Points = { colspan = 1 }, PointsTB = { colspan = 1 }, Group = { colspan = 1 }, Streak = { colspan = 1 }, }

local FIELD_CLASSES = { Place = 'standings-place', Team = 'standings-team', }

local COL_PRELOADS = { seriespt = { 'Place', 'Team', 'Series', 'Games', 'PointsTB', 'Streak' }, series = { 'Place', 'Team', 'Series', 'Games', 'Streak' }, bo1 = { 'Place', 'Team', 'GamesBO1', 'Streak' }, bo1points = { 'Place', 'Team', 'Points', 'GamesBO1', 'Streak' }, bo2 = { 'Place', 'Team', 'Points', 'SeriesBO2', 'Games', 'Streak' }, bo3diff = { 'Place', 'Team', 'Series', 'GamesDiff', 'Streak' }, bo2nopoints = { 'Place', 'Team', 'SeriesBO2', 'Games', 'Streak' }, bo3gamepoints = { 'Place', 'Team', 'Points', 'Games', 'Series', 'Streak' }, -- OPL thing bo5 = { 'Place', 'Team', 'Series', 'GamesPct', 'Streak' }, bo5points = { 'Place', 'Team', 'Points', 'GamesBO5', 'Streak' }, bo5ns = { 'Place', 'Team', 'Series', 'Games' }, bo5nsp = { 'Place', 'Team', 'Series', 'Games', 'Points' }, bo5nm = { 'Place', 'Team', 'Series' }, }

local ARG_ORDER = { 'team', 'w', 't', 'l', 'wg', 'lg', 'p', 'tied', 'Group', 'place', 'footnotes' }

local ARG_ZEROES = { w = true, t = true, l = true, wg = true, lg = true, p = true }

local kv_sep = ':;:' local arg_sep = ';:;'

--	Structure:	dataByTeams = {		team1, team2, team3		team1 = { data },		team2 = { data },	}

util_cargo.setStoreNamespace('')

local p = {} local h = {}

function p.fromCargo(frame) i18n.init('Standings') local args = util_args.merge if util_args.castAsBool(args.forFL) then i18n.print = i18n.printForInclusion end local overviewPage = util_esports.getOverviewPage(args.page) if util_args.castAsBool(args.storeargs) then h.storeArgs(args, overviewPage) end if util_args.castAsBool(args.argsfromcargo) then local exists, message = h.queryArgs(args, overviewPage) if util_args.castAsBool(args.forceargquery) and not exists then return message end end h.setPreload(args) local data = h.getData(overviewPage, args) local processed = h.processData(data, args.isbo2, args) local fields = h.pickFields(args) if h.doWeStoreResultsCargo(args) then h.storeResultsCargo(processed, args) end if h.doWeStoreStandingsCargo(args) then h.storeStandingsCargo(processed, args) end local includeButton = not util_args.castAsBool(args.nobutton) return h.makeOutput(processed, fields, args, includeButton, overviewPage) end

function p.fromArgs(frame) i18n.init('Standings') local args = util_args.merge h.setPreload(args) local data = h.getDataFromArgs(args) local processed = h.processData(data, args.isbo2, args) local fields = h.pickFields(args) if h.doWeStoreResultsCargo(args) then h.storeResultsCargo(processed, args) end if h.doWeStoreStandingsCargo(args) then h.storeStandingsCargo(processed, args) end return h.makeOutput(processed, fields, args, overviewPage) end

function h.storeArgs(args, page) local allArgs = {} local rowArgs = {} for k, v in pairs(args) do		allArgs[k] = v		if k:sub(1,3) == 'row' then rowArgs[k] = v		end end local store = { _table = 'StandingsArgs', OverviewPage = page, Args = util_cargo.concatArgsForStore(allArgs), RowArgs = util_cargo.concatArgsForStore(rowArgs), Finalorder = args.finalorder, TournamentGroup = args.onlygroup, N = util_vars.setGlobalIndex('standingsCargoN'), IsOver = util_args.castAsBool(args.isover), }	store.UniqueLine = ('%s_%s'):format(store.OverviewPage,store.N)	util_cargo.store(store) end

function h.queryArgs(args, page) local query = { tables = 'StandingsArgs', fields = {'Args','TournamentGroup'}, where = h.queryArgsWhere(args, page) }	local data = util_cargo.queryAndCast(query) if #data == 0 then return nil, 'Unable to retrieve standings data' elseif data[1].TournamentGroup and not args.onlygroup then return nil, 'Query does not currently support multiple groups' elseif #data > 1 then return nil, 'Multiple Results Found - Cannot print single standings table' end local newArgs = util_cargo.extractArgs(data[1].Args) util_table.mergeDontOverwrite(args, newArgs) return true end

function h.queryArgsWhere(args, page) local tbl = { ('OverviewPage="%s"'):format(page), util_cargo.whereFromArg('TournamentGroup="%s"', args.onlygroup) }	return util_table.concat(tbl, ' AND ') end

function h.setPreload(args) if not args.preload then return end local preload = lang:lc(args.preload) if not PRELOADS[preload] then error('Invalid preload') end args.isbo2 = util_args.castAsBool(args.isbo2) or PRELOADS[preload].isbo2 args.columns = args.columns or PRELOADS[preload].columns args.sortmethod = args.sortmethod or PRELOADS[preload].sortmethod end

-- from args function h.getDataFromArgs(args) local i = 1 local data = h.argsToTable(args) h.processArgData(data) return data end

function h.argsToTable(args) local tbl = {} for i, arg in ipairs(args) do		local thisdata = util_text.split(arg, argsep) local thisteam = m_team.teamlinkname(thisdata[1]) tbl[i] = thisteam tbl[thisteam] = {} for k, v in ipairs(thisdata) do			local key = ARG_ORDER[k] if v ~= '' then if key == 'footnotes' then tbl[thisteam][key] = util_text.split(v,'%s*;;%s*') else tbl[thisteam][key] = tonumber(v) or v				end elseif ARG_ZEROES[key] then tbl[thisteam][key] = 0 elseif key == 'footnotes' then tbl[thisteam][key] = {} end end end return tbl end

function h.processArgData(data) local curplace = 1 for i, team in ipairs(data) do		local row = data[team] if util_args.castAsBool(row.tied) then row.sort = curplace else row.sort = i			curplace = i		end row.tb = row.p	end end

-- from cargo function h.getData(overviewPage, args) local query = h.makeQuery(overviewPage, args) local result = util_cargo.queryAndCast(query) local teams = h.teamsFromList(args.teamlist) local dataByTeams = h.compileTeams(result, teams, util_args.castAsBool(args.onlylist)) if util_args.castAsBool(args.groups) or args.onlygroup then h.addGroupData(dataByTeams, overviewPage, args.onlygroup) end h.adjustProcessedFromArgs(dataByTeams, args) if args.finalorder then h.sortTeamsByArg(dataByTeams, args.finalorder, args.finalplaces) else h.sortTeamsByCargo(dataByTeams, lang:lc(args.sortmethod or 'record')) end return dataByTeams end

function h.makeQuery(page, args) local query = { tables = h.getTables, join = h.getJoin, fields = h.getCargoFields(args), where = h.makeWhere(page, args), orderBy = 'N_Page ASC, N_TabInPage ASC, N_MatchInTab ASC', groupBy = 'UniqueMatch', }	return query end

function h.getTables return { 'MatchSchedule=MS', 'TeamRedirects=TR1', 'Teams=T1', 'TeamRedirects=TR2', 'Teams=T2', 'TournamentRosters=Ros1', 'TournamentRosters=Ros2', } end

function h.getJoin return { 'MS.Team1 = TR1.AllName', 'TR1._pageName=T1._pageName', 'MS.Team2 = TR2.AllName', 'TR2._pageName=T2._pageName', 'MS.PageAndTeam1 = Ros1.PageAndTeam', 'MS.PageAndTeam2 = Ros2.PageAndTeam', } end

function h.getCargoFields(args) local tbl = { 'MS.Team1Final=Team1', 'MS.Team2Final=Team2', 'MS.Winner [number]', 'MS.Team1Score [number]', 'MS.Team2Score [number]', 'MS.Team1Points [number]', 'MS.Team2Points [number]', 'MS.Team1PointsTB [number]', 'MS.Team2PointsTB [number]', 'MS.Tab', 'COALESCE(Ros1.Region, T1.Region)=Team1Region', 'COALESCE(Ros2.Region, T2.Region)=Team2Region', 'MS.FF [number]', }	if not util_args.castAsBool(args.nofootnotes) then util_table.mergeArrays(tbl, { 'Team1Footnote', 'Team2Footnote' }) end return tbl end

function h.makeWhere(page, args) local tbl = { ('MS.OverviewPage="%s"'):format(page), -- 'Winner IS NOT NULL', args.special_where, }	if lang:lc(args.tiebreakers or '') == 'only' then tbl[#tbl+1] = '(IsTiebreaker = "1")' elseif not util_args.castAsBool(args.tiebreakers) then tbl[#tbl+1] = '(IsTiebreaker != "1" OR IsTiebreaker IS NULL)' end if args.excludetabs then for v in util_text.gsplit(args.excludetabs, sep) do			tbl[#tbl+1] = ('Tab != "%s"'):format(v) end end if args.onlytabs then local onlyrounds_tbl = {} for v in util_text.gsplit(args.onlytabs, sep) do			onlyrounds_tbl[#onlyrounds_tbl+1] = ('Tab = "%s"'):format(v) end tbl[#tbl+1] = ('(%s)'):format(util_table.concat(onlyrounds_tbl, ' OR ')) end return util_table.concat(tbl, ' AND ') end

function h.teamsFromList(teamlist) if not teamlist then return {} end local teams = util_map.split(teamlist, sep, m_team.teamlinkname) for _, team in ipairs(teams) do		h.addTeamZeros(teams, team) end return teams end

function h.compileTeams(result, teams, onlylist) local hasteams = next(teams) and true local tbl = mw.clone(teams) for _, row in ipairs(result) do		local team1 = m_team.teamlinkname(row.Team1) local team2 = m_team.teamlinkname(row.Team2) if not hasteams then h.initializeTeam(tbl, team1) h.initializeTeam(tbl, team2) h.addTeamData(tbl[team1], tbl[team2], row) elseif onlylist and tbl[team1] and tbl[team2] then h.addTeamData(tbl[team1], tbl[team2], row) elseif not onlylist then if tbl[team1] then h.addTeam1Data(tbl[team1], row) end if tbl[team2] then h.addTeam2Data(tbl[team2], row) end end end return tbl end

function h.initializeTeam(tbl, team) if team and not tbl[team] then tbl[#tbl+1] = team h.addTeamZeros(tbl, team) end return end

function h.addTeamZeros(tbl, team) tbl[team] = { w = 0, t = 0, l = 0, p = 0, tb = 0, wg = 0, lg = 0, strN = 0, footnotes = {}, }	return end

function h.addTeamData(team1, team2, row) -- here is where all incrementing happens -- if no winner is specified in the cell, unconditionally nothing will happen here -- this is important because we populate incomplete series results -- while a series is underway h.addTeam1Data(team1, row) h.addTeam2Data(team2, row) end

function h.addTeam1Data(team, row) team.region = row.Team1Region if not row.Winner then return end team.w = team.w + (row.Winner == 1 and 1 or 0) team.l = team.l + (row.Winner == 2 and 1 or 0) -- in the unique case that both teams FF, the winner will be 0 but we add a loss team.l = team.l + (row.FF == 0 and 1 or 0) team.t = team.t + (row.Winner == 0 and 1 or 0) team.p = team.p + (row.Team1Points or 0) team.wg = team.wg + (row.Team1Score or 0) team.lg = team.lg + (row.Team2Score or 0) team.tb = team.tb + (row.Team1PointsTB or 0) team.footnotes[#team.footnotes+1] = h.footnoteText(row.Tab, row.Team1Footnote) h.addStreak(team, row.Winner == 1, row.Winner == 0, row.Winner == 2) end

function h.addTeam2Data(team, row) team.region = row.Team2Region if not row.Winner then return end team.w = team.w + (row.Winner == 2 and 1 or 0) team.l = team.l + (row.Winner == 1 and 1 or 0) team.l = team.l + (row.FF == 0 and 1 or 0) team.t = team.t + (row.Winner == 0 and 1 or 0) team.p = team.p + (row.Team2Points or 0) team.wg = team.wg + (row.Team2Score or 0) team.lg = team.lg + (row.Team1Score or 0) team.tb = team.tb + (row.Team2PointsTB or 0) team.footnotes[#team.footnotes+1] = h.footnoteText(row.Tab, row.Team2Footnote) h.addStreak(team, row.Winner == 2, row.Winner == 0, row.Winner == 1) end

function h.addStreak(team, isWin, isDraw, isLoss) local result = isWin and 'W' or isDraw and 'D' or isLoss and 'L'	team.strN = result == team.strResult and team.strN + 1 or 1 team.strResult = result end

function h.footnoteText(tab, footnote) if not footnote then return nil end return ('%s: %s'):format(tab, footnote) end

-- adjust from args function h.adjustProcessedFromArgs(data, args) local arg_adjust = { footnotes = h.getAdjustmentArgData(args.footnotes), p = h.getAdjustmentArgData(args.pointadjust), tb = h.getAdjustmentArgData(args.tbpointadjust), w = h.getAdjustmentArgData(args.wadjust), l = h.getAdjustmentArgData(args.ladjust), wg = h.getAdjustmentArgData(args.wgadjust), lg = h.getAdjustmentArgData(args.lgadjust), }   for _, teamstr in ipairs(data) do        local team = data[teamstr] team.p = team.p + (tonumber(arg_adjust.p[teamstr] or 0)) team.tb = team.tb + (tonumber(arg_adjust.tb[teamstr] or 0)) team.w = team.w + (tonumber(arg_adjust.w[teamstr] or 0)) team.l = team.l + (tonumber(arg_adjust.l[teamstr] or 0)) team.wg = team.wg + (tonumber(arg_adjust.wg[teamstr] or 0)) team.lg = team.lg + (tonumber(arg_adjust.lg[teamstr] or 0)) team.footnotes = h.processFootnotes(team.footnotes, arg_adjust.footnotes[teamstr]) end end

function h.getAdjustmentArgData(arg) if not arg then return {} end local tbl = {} for val in arg:gmatch('%(%(%((.-)%)%)%)') do		k, v = val:match('(.*)===(.*)') tbl[m_team.teamlinkname(k)] = v	end return tbl end

function h.processFootnotes(from_team, from_arg) from_team[#from_team+1] = from_arg local tbl = { Team = from_team } return tbl end

-- sort function h.sortTeamsByCargo(data, sortmethod) local f = util_tournament.getSortMethod(sortmethod) util_map.dictRowsInPlace(data, f)	h.sortTeams(data) end

function h.sortTeamsByArg(data, finalorder, placesArg) local order_tbl = util_map.split(finalorder, nil, m_team.teamlinkname) local places_tbl = placesArg and util_text.split(placesArg, sep) or {} for i, v in ipairs(order_tbl) do		local team = data[v] if not team then error(('%s is not a valid team code'):format(v)) end -- not sure why i would re-sort by place if finalorder is given -- that seems 100% wrong -- but leaving that here & commented just in case theres some reason -- team.sort = places_tbl[i] and (tonumber(places_tbl[i]) * -1) or (i * -1) team.sort = i * -1 team.place = places_tbl[i] end h.sortTeams(data) end

function h.sortTeams(data) table.sort(data,		function(a,b)			if data[a].sort == data[b].sort then				return lang:lc(a) < lang:lc(b)			else				return data[a].sort > data[b].sort			end		end	) end

-- process after sort function h.addGroupData(data, page, onlygroup) local groupdata = h.groupsFromCargo(page) for i, team in ipairs(data) do		if onlygroup and groupdata[team] ~= onlygroup then data[i] = false else data[team].group = groupdata[team] end end util_table.removeFalseEntries(data) end

function h.groupsFromCargo(page) local result = util_tournament.getGroups(page) return util_cargo.makeConstDict(result, 'Team', 'GroupName') end

function h.processData(data, isbo2, args) local processed = {} local place = 1 local lastsort for k, teamstr in ipairs(data) do		local team = data[teamstr] local thissort = team.sortdisplay or team.sort if thissort ~= lastsort then place = k			lastsort = thissort end processed[#processed+1] = { Place = team.place or place, Team = h.getTeamDisplay(args, teamstr, data[teamstr]), TeamStr = teamstr, Games = ('%s - %s'):format(team.wg, team.lg), wg = team.wg, lg = team.lg, w = team.w,			l = team.l,			t = team.t, GamesPct = util_esports.winrate(team.wg, team.lg, 1) .. '%',			Points = team.p,			PointsTB = team.tb, Group = team.group, Diff = util_math.printWithSign(team.wg - team.lg), footnotes = team.footnotes, Streak = team.strResult and i18n.print('streak' .. team.strResult, team.strN), strN = team.strN, strResult = team.strResult, }		local thisline = processed[#processed] if isbo2 then thisline.SeriesBO2 = ('%s - %s - %s'):format(team.w, team.t, team.l)			thisline.SeriesBO2Store = ('%s-%s-%s'):format(team.w, team.t, team.l)		else thisline.Series = ('%s - %s'):format(team.w, team.l) thisline.SeriesPct = util_esports.winrate(team.w, team.l, 1) .. '%'		end end return processed end

function h.getTeamDisplay(args, team, teamData) local tbl = {} tbl[#tbl+1] = h.getRegionDisplay(args, teamData.region) tbl[#tbl+1] = m_team[args.teamstyle or 'rightlonglinked'](team) return util_table.concat(tbl, '') end

function h.getRegionDisplay(args, region) if util_vars.getVar('Event Region') ~= 'International' and not util_args.castAsBool(args.forceregion) then return false end return Region(region):image end

-- start output stuff function h.pickFields(args) local tbl = { headings = h.headingsFromArgs(args), fields = {} }	h.addFieldsFromHeadings(tbl.headings, tbl.fields) if util_args.castAsBool(args.groups) then table.insert(tbl.headings,2,'Group') table.insert(tbl.fields,2,'Group') end return tbl end

function h.headingsFromArgs(args) if args.columnlist then return util_text.split(args.columnlist,sep) elseif args.columns then return COL_PRELOADS[lang:lc(args.columns)] else return COL_PRELOADS.bo1 end end

function h.addFieldsFromHeadings(headings, fields) for _, v in ipairs(headings) do		if HEADING_DATA[v].fields then for _, field in ipairs(HEADING_DATA[v].fields) do				fields[#fields+1] = field end else fields[#fields+1] = v		end end end

-- print output function h.makeOutput(processed, fields, args, includeButton, page) util_footnote.init local output = mw.html.create('div'):addClass('standings-outer-div') local tbl_div = output:tag('div') local tbl = tbl_div:tag('table') :addClass('wikitable2') :addClass('standings') h.addFirstHeading(tbl, args, page, #fields.fields) h.addHeadings(tbl, fields.headings) local classes = h.getClasses(args) h.printTable(tbl, processed, fields, classes, includeButton, page) util_footnote.printTexts(output) return output end

function h.addFirstHeading(tbl, args, page, colspan) local th = tbl:tag('tr'):tag('th'):attr('colspan',colspan) args.display = h.getDisplay(args, page) if util_args.castAsBool(args.legend) then Legend(th, args) else th:wikitext(args.display or i18n.print('StandingsPlain')) end end

function h.getDisplay(args, page) if args.display then return args.display else local eventName = h.getEventName(page) if eventName then return i18n.print('Standings', eventName) end end end

function h.getEventName(page) if not page then return nil end local query = { tables = 'Tournaments', fields = 'StandardName', where = ('OverviewPage="%s"'):format(page) }	return util_cargo.getOneResult(query) end

function h.addHeadings(tbl, headings) local tr = tbl:tag('tr') for _, v in ipairs(headings) do		tr:tag('th') :attr('colspan',HEADING_DATA[v].colspan) :wikitext(i18n.print(v)) :addClass('column-label-small') end end

function h.getClasses(args) local classes = { places = args.places and util_map.split(args.places,sep, h.getClassName) or {} }	local max = #classes.places classes.rows = util_args.numberedArgsToTable(args, 'row', true, max) or {} util_map.inPlace(classes.rows, h.getClassName, max) return classes end

function h.getClassName(class) -- prepend every individual "word" in the class with 'standings-' return class:gsub('([^ ]+)','standings-%1') end

function h.printTable(tbl, processed, fields, classes, includeButton, page) for i, row in ipairs(processed) do		local tr = tbl:tag('tr') :addClass(classes.rows[i]) util_esports.addTeamHighlighter(tr, row.TeamStr) for _, v in ipairs(fields.fields) do			local td = tr:tag('td') :wikitext(row[v]) :addClass(FIELD_CLASSES[v]) if row.footnotes[v] then util_footnote.tag(td, row.footnotes[v]) end if v == 'Place' then td:addClass(classes.places[i]) elseif v == 'Team' and includeButton then PopupButton.tth(td, page, m_team.short(row.TeamStr) .. ' Schedule', row.TeamStr) end end end end

-- store cargo function h.doWeStoreResultsCargo(args) local nocargo = util_args.castAsBool(args.nocargo) local isover = util_args.castAsBool(args.isover) local useasresults = util_args.castAsBool(args.useasresults) local argsfromcargo = util_args.castAsBool(args.argsfromcargo) return not nocargo and isover and useasresults and not argsfromcargo end

function h.storeResultsCargo(data, args) local title = mw.title.getCurrentTitle.text local N = util_vars.setGlobalIndex('standingsN') for i, team in ipairs(data) do		local tbl = { _table = 'TournamentResults', Event = util_vars.getVar('Event Name'), Phase = util_args.castAsBool(args.groupasphase) and (args.onlygroup or team.Group) or args.phase, Tier = util_vars.getVar('Event Tier'), Date = args.date or util_vars.getVar('Event Date'), Place = team.Place, ['Place_Number'] = team.Place, Team = team.TeamStr, IsAchievement = true, UniqueLine = ('%s_%s_%s'):format(title, N, i), LastResult = team.SeriesBO2Store or team.Series, GroupName = team.Group, -- this should be fixed to not rely on any vardefine, need to add real group support LastOpponent_Markup = m_team.rightshort('group stage'), -- this should probably display group RosterPage = args.rosterpage or title, OverviewPage = util_esports.getOverviewPage, }		tbl.PageAndTeam = ('%s_%s'):format(tbl.RosterPage, tbl.Team) util_cargo.store(tbl) end end

function h.doWeStoreStandingsCargo(args) if util_args.castAsBool(args.nocargo) then return false end if not util_vars.getBool('hasInfobox') then return false end return true end

function h.storeStandingsCargo(processed, args) local title = mw.title.getCurrentTitle.text for i, team in ipairs(processed) do		local tbl = { _table = "Standings", OverviewPage = util_esports.getOverviewPage, Team = team.TeamStr, PageAndTeam = ('%s_%s'):format(args.rosterpage or title, team.TeamStr), N = i,			Place = team.Place, WinGames = team.wg, LossGames = team.lg, WinSeries = team.w,			LossSeries = team.l,			TieSeries = team.t,			Points = team.Points, PointsTiebreaker = team.PointsTB, Streak = team.strN, StreakDirection = team.strResult, -- Footnotes = util_table.concat(team.footnotes,'; '), }		util_cargo.store(tbl) end end

return p