if pn and pn ~= '' then
pagename = pn
end  
local cpagename = '  
local d_season = mw.ustring.match(cpagename, ':(%d+s).+%(%d+[–-]%d+%)') --i.e. "1760s in the Province of Quebec (1763–1791)"  
local y_season = mw.ustring.match(cpagename, ':(%d+) .+%(%d+[–-]%d+%)') --i.e. "1763 establishments in the Province of Quebec (1763–1791)"  
local e_season = mw.ustring.match(cpagename, '%s(%d+[–-])$') or --irreg; ending unknown, e.g. "Members of the Scottish Parliament 2021–"
mw.ustring.match(cpagename, '%s(%d+[–-]present)$') or--e.g. "UK MPs 2019–present"
mw.ustring.match(cpagename, '%s(%d+[–-]தற்போது)$') --e.g. "UK MPs 2019–தற்போது"  
local season = mw.ustring.match(cpagename, '[:%s%(](%d+[–-]%d+)[%)%s]') or --split in 2 b/c you can't frontier '$'/eos?
mw.ustring.match(cpagename, '[:%s](%d+[–-]%d+)$')  
local tvseason = mw.ustring.match(cpagename, 'season (%d+)') or
mw.ustring.match(cpagename, 'series (%d+)') or
mw.ustring.match(cpagename, 'பருவம் (%d+)') or
mw.ustring.match(cpagename, 'தொடர் (%d+)')  
local nordinal = mw.ustring.match(cpagename, '[:%s](%d+[snrt][tdh])[-%s]') or
mw.ustring.match(cpagename, '[:%s](%d+[snrt][tdh])$') or
mw.ustring.match(cpagename, '[:%s](%d+)[-ஆம்]') or
mw.ustring.match(cpagename, '[:%s](%d+ ஆம்)$') or
mw.ustring.match(cpagename, '[:%s](%d+-ஆவது)$') or
mw.ustring.match(cpagename, '[:%s](%d+ ஆவது)$') or
mw.ustring.match(cpagename, '[:%s](%d+வது)$')  
local decade = mw.ustring.match(cpagename, '[:%s](%d+s)[%s-]') or
mw.ustring.match(cpagename, '[:%s](%d+s)$') or
mw.ustring.match(cpagename, '[:%s](%d+கள்)[%s]') or
mw.ustring.match(cpagename, '[:%s](%d+கள்)[%s-]') or
mw.ustring.match(cpagename, '[:%s](%d+கள்)$')  
local decade_ta1 = mw.ustring.match(cpagename, '[:%s](%d+களில்)[%s]') or
mw.ustring.match(cpagename, '[:%s](%d+களில்)[%s-]') or
mw.ustring.match(cpagename, '[:%s](%d+களில்)$')  
local year = mw.ustring.match(cpagename, '[:%s](%d%d%d%d)%s') or --prioritize 4-digit years
mw.ustring.match(cpagename, '[:%s](%d%d%d%d)$') or
mw.ustring.match(cpagename, '[:%s](%d+)%s') or
mw.ustring.match(cpagename, '[:%s](%d+)$') or
--expand/combine exceptions below as needed
mw.ustring.match(cpagename, '[:%s](%d+)[இல்]') or
mw.ustring.match(cpagename, '[:%s](%d+)[-இல்]') or
mw.ustring.match(cpagename, '[:%s](%d+)-related') or
mw.ustring.match(cpagename, '[:%s](%d+)-cylinder') or
mw.ustring.match(cpagename, '[:%-VW](%d+)%s') --e.g. "Straight-8 engines"  
local roman = mw.ustring.match(cpagename, '%s([IVXLCDM]+)%s')  
local found = d_season or y_season or e_season or season or tvseason or
nordinal or decade or decade_ta1 or year or roman  
if found then
if string.match(found, '%d%d%d%d%d') == nil then
--return in order of decreasing complexity/least chance for duplication
if nordinal and season --i.e. "18th-century establishments in the Province of Quebec (1763–1791)"
then return { ['vtype'] = 'nordinal', ['v'] = nordinal } end
if d_season then return { ['vtype'] = 'decade', ['v'] = d_season } end
if y_season then return { ['vtype'] = 'year', ['v'] = y_season } end
if e_season then return { ['vtype'] = 'ending', ['v'] = e_season } end
if season then return { ['vtype'] = 'season', ['v'] = season } end
if tvseason then return { ['vtype'] = 'tvseason', ['v'] = tvseason } end
if nordinal then return { ['vtype'] = 'nordinal', ['v'] = nordinal } end
if decade then return { ['vtype'] = 'decade', ['v'] = decade } end
if decade_ta1 then return { ['vtype'] = 'decade_ta1', ['v'] = decade_ta1 } end
if year then return { ['vtype'] = 'year', ['v'] = year } end
if roman then return { ['vtype'] = 'roman', ['v'] = roman } end
end
else
--try wordinals ('zeroth' to 'ninety-ninth' only)
local eng2ord = require('Module:ConvertNumeric').english_to_ordinal
local split = mw.text.split(pagename, ' ')
for i=1, #split do
if eng2ord(split[i]) > -1 then
return { ['vtype'] = 'wordinal', ['v'] = split[i] }
end
end  
--try English numerics ('one'/'single' to 'ninety-nine' only)
local eng2num = require('Module:ConvertNumeric').english_to_numeral
local split = mw.text.split(pagename, '[%s%-]') --e.g. "Nine-cylinder engines"
for i=1, #split do
if eng2num(split[i]) > -1 then
return { ['vtype'] = 'enumeric', ['v'] = split[i] }
end
end
end  
errors = p.errorclass('Function find_var can\'t find the variable text in category "'..pagename..'".')
return { ['vtype'] = 'error', ['v'] = p.failedcat(errors, 'V') }
end  
--==========================================================================
-- Main
--==========================================================================  
function p.navseasoncats
--arg checks & handling
local args = :getParent.args
checkforunknownparams(args) --for template args
checkforunknownparams(.args) --for #invoke'd args
local cat = args['cat'] --'testcase' alias for catspace
local list = args['list-all-links'] --debugging utility to output all links & followed #Rs
local follow = args['follow-redirects'] --default 'yes'
local testcase = args['testcase']
local testcasegap = args['testcasegap']
local minimum = args['min']
local maximum = args['max']
local skip_gaps = args['skip-gaps']  
--apply args
local pagename = testcase or cat or currtitle.text
local testcaseindent = ''
if testcasecolon == ':' then testcaseindent = '\n::' end
if follow and follow == 'no' then followRs = false end
if list and list == 'yes' then listall = true end
if skip_gaps and skip_gaps == 'yes' then
skipgaps = true
trackcat(26, 'Navseasoncats using skip-gaps parameter')
end  
--ns checks
if currtitle.nsText == 'Category' then
if cat and cat ~= '' then
trackcat(1, 'Navseasoncats using cat parameter')
end
if testcase and testcase ~= '' then
trackcat(2, 'Navseasoncats using testcase parameter')
end
elseif currtitle.nsText == '' then
trackcat(30, 'Navseasoncats in mainspace')
end  
--find the variable parts of pagename
local findvar = find_var(pagename)
if findvar.vtype == 'error' then --basic format error checking in find_var
return findvar.v..table.concat(ttrackingcats)
end
local start = string.match(findvar.v, '^%d+')  
--the rest is static
local findvar_escaped = string.gsub( findvar.v, '%-', '%%%-')
local firstpart, lastpart = string.match(pagename, '^(.-)'..findvar_escaped..'(.*)$')
if findvar.vtype == 'tvseason' then --double check for cases like '30 Rock (season 3) episodes'
firstpart, lastpart = string.match(pagename, '^(.-season )'..findvar_escaped..'(.*)$')
if firstpart == nil then
firstpart, lastpart = string.match(pagename, '^(.-series )'..findvar_escaped..'(.*)$')
end
end
firstpart = mw.text.trim(firstpart or '')
lastpart = mw.text.trim(lastpart or '')  
--call the appropriate nav function, in order of decreasing popularity
if findvar.vtype == 'year' then --e.g. "500", "2001"; nav_year..nav_decade; ~75% of cats
local nav1 = nav_year( , firstpart, start, lastpart, minimum, maximum )..testcaseindent..table.concat(ttrackingcats)  
local dec = math.floor(findvar.v/10)
local decadecat = nil
local firstpart_dec = firstpart
if firstpart_dec ~= '' then
firstpart_dec = firstpart_dec..' the'
elseif firstpart_dec == 'AD' and dec <= 1 then
firstpart_dec = ''
if dec == 0 then dec = '' end
end
local decade = dec..'0கள் '
decadecat = mw.text.trim( firstpart_dec..' '..decade..lastpart )
local exists = catexists(decadecat)
if exists then
navborder = false
trackcat(28, 'Navseasoncats year and decade')
local nav2 = nav_decade( , firstpart_dec, decade, lastpart, minimum, maximum )..testcaseindent..table.concat(ttrackingcats)
return nav1nav2( nav1, nav2 )
elseif ttrackingcats[16] ~= '' then --nav_year isolated; check nav_hyphen (e.g. UK MPs 1974, Moldovan MPs 2009, etc.)
local hyphen = '–'
local finish = start
local nav2 = nav_hyphen( , start, hyphen, finish, firstpart, lastpart, minimum, maximum, testcasegap )..testcaseindent..table.concat(ttrackingcats)
if ttrackingcats[16] ~= '' then return nav1 --still isolated; rv to nav_year
else return nav2 end
else --regular nav_year
return nav1
end