--begin navhyphen
local navh = '{|\n'..'|\n'  
local terminalcat = false --switch used to hide future cats
local terminaltxt = nil
local i = -3 --nav position
while i <= 3 do
local from = nstart + i*(t+hgap) --the logical, but not necessarily correct, 'from'
if tirregs['from'..i] then from = tonumber(tirregs['from'..i]) end --prefer irregular term table
local from2 = string.match(from, '%d?%d$')  
local to = tostring(from+t) --the logical, naive range, but
if tirregs['to'..i] then --prefer irregular term table
to = tirregs['to'..i]
elseif regularparent == false and tirregs and i > 0 then
to = tirregs['to-1'] --special treatment for parent terminal cats, since they have no natural 'to'
end
local to2 = string.match(to, '%d?%d$')
local tofinal = (to2 or '') --assume t=1 and abbreviated 'to' (the most common case)
if t > 1 or --per MOS:DATERANGE (e.g. 1999-2004)
(from2 - (to2 or from2)) > 0 --century transition exception (e.g. 1999–2000)
then
tofinal = (to or '') --default to the MOS-correct format, in case no fallbacks found
end
if to == '0-length' then
tofinal = to
end  
--check existance of 4-digit, MOS-correct range, with abbreviation fallback
if tofinal ~= '0-length' then
if t > 1 and string.len(from) == 4 then --e.g. 1999-2004
--determine which link exists (full or abbr)
local full = firstpart..lspace..from..hyph..tofinal..tspace..lastpart
if not catexists(full) then
local abbr = firstpart..lspace..from..hyph..to2..tspace..lastpart
if catexists(abbr) then
tofinal = (to2 or '') --rv to MOS-incorrect format; if full AND abbr DNE, then tofinal is still in its MOS-correct format
end
end
elseif t == 1 then --full-year consecutive ranges are also allowed
local abbr = firstpart..lspace..from..hyph..tofinal..tspace..lastpart --assume tofinal is in abbr format
if not catexists(abbr) and tofinal ~= to then
local full = firstpart..lspace..from..hyph..to..tspace..lastpart
if catexists(full) then
tofinal = (to or '') --if abbr AND full DNE, then tofinal is still in its abbr format (unless it's a century transition)
end end end end  
--populate navh
if i ~= 0 then --/ navh
local orig = firstpart..lspace..from..hyph..tofinal..tspace..lastpart
local disp = from..hyph..tofinal
if tofinal == '0-length' then
orig = firstpart..lspace..from..tspace..lastpart
disp = from
end
local catlink = catlinkfollowr(, orig, disp, true) --force terminal cat display  
if terminalcat == false then
terminaltxt = find_terminaltxt( disp ) --also sets tracking cats
terminalcat = (terminaltxt ~= nil)
end
if catlink.rtarget and avoidself then --a was followed, figure out why
--determine new term length & gap size
ttlens[ find_duration( catlink.rtarget ) ] = 1
if i > -3 then
local lastto = tirregs['to'..(i-1)]
if lastto == nil then
local lastfrom = nstart + (i-1)*(t+hgap)
lastto = lastfrom+t --use last logical 'from' to calc lastto
end
if lastto then
local gapcat = lastto..'-'..from --dummy cat to calc with
local gap = find_duration(gapcat) or -1 --in case of nil,
tgaps[ gap ] = 1 --tgaps[-1] is ignored
end
end  
--display/tracking handling
local base_regex = '%d+[–-]%d+'
local origbase = mw.ustring.gsub(orig, base_regex, '')
local rtarbase, rtarbase_success = mw.ustring.gsub(catlink.rtarget, base_regex, '')
if rtarbase_success == 0 then
local base_regex_lax = '%d%d%d%d' --in case rtarget is a year cat
rtarbase, rtarbase_success = mw.ustring.gsub(catlink.rtarget, base_regex_lax, '')
end
local terminal_regex = '%d+[–-]'..(terminaltxt or '')..'$' --more manual ORs bc Lua regex sux
if mw.ustring.match(orig, terminal_regex) then
origbase = mw.ustring.gsub(orig, terminal_regex, '')
end
if mw.ustring.match(catlink.rtarget, terminal_regex) then
--finagle/overload terminalcat type to set nmaxseas on 1st occurence only
if terminalcat == false then terminalcat = 1 end
local dummy = find_terminaltxt( catlink.rtarget ) --also sets tracking cats
rtarbase = mw.ustring.gsub(catlink.rtarget, terminal_regex, '')
end
origbase = mw.text.trim(origbase)
rtarbase = mw.text.trim(rtarbase)
if origbase ~= rtarbase then
trackcat(6, 'Navseasoncats range redirected (base change)')
elseif terminalcat == 1 then
trackcat(8, 'Navseasoncats range redirected (end)')
else --origbase == rtarbase
local all4s_regex = '%d%d%d%d[–-]%d%d%d%d'
local orig_all4s = mw.ustring.match(orig, all4s_regex)
local rtar_all4s = mw.ustring.match(catlink.rtarget, all4s_regex)
if orig_all4s and rtar_all4s then
trackcat(10, 'Navseasoncats range redirected (other)')
else
local year_regex1 = '%d%d%d%d$'
local year_regex2 = '%d%d%d%d[%s%)]'
local year_rtar = mw.ustring.match(catlink.rtarget, year_regex1) or
mw.ustring.match(catlink.rtarget, year_regex2)
if orig_all4s and year_rtar then
trackcat(7, 'Navseasoncats range redirected (var change)')
else
trackcat(9, 'Navseasoncats range redirected (MOS)')
end
end
end
end  
if terminalcat then --true or 1
if type(terminalcat) ~= 'boolean' then nmaxseas = from end --only want to do this once
terminalcat = true --done finagling/overloading
end
if (from >= 0) and (nminseas <= from) and (from <= nmaxseas) then
navh = navh..'*'..catlink.navelement..'\n'
if terminalcat then nmaxseas = nminseas_default end --prevent display of future ranges
else
local hidden = '<span>'..disp..'</span>'
navh = navh..'*'..hidden..'\n'
if listall then
tlistall[#tlistall] = tlistall[#tlistall]..' ('..hidden..')'
end
end
else -- navh
if finish == -1 then finish = 'present'
elseif finish == 0 then finish = '<span>'..start..'</span>' end
local disp = start..hyph..finish
if regularparent == 'isolated' then disp = start end
navh = navh..'*<b>'..disp..'</b>\n'
end  
i = i + 1
end  
--tracking cats & finalize
if avoidself then
local igaps = 0 --# of diff gap sizes > 0 found
local itlens = 0 --# of diff term lengths found
for s = 1, hgap_limit_reg do --must loop; #tgaps, #ttlens unreliable
igaps = igaps + (tgaps[s] or 0)
end
for s = 0, term_limit do
itlens = itlens + (ttlens[s] or 0)
end
if igaps > 0 then trackcat(11, 'Navseasoncats range gaps') end
if itlens > 1 and ttrackingcats[13] == '' then --avoid duplication in "Navseasoncats range irregular, 0-length"
trackcat(12, 'Navseasoncats range irregular')
end
end
isolatedcat
defaultgapcat(not hgap_success)
if listall then
return listalllinks
else
return navh..'|}'
end
end  
--======================================================  
local function nav_tvseason( , firstpart, tv, lastpart, maximumtv )
--Expects a PAGENAME of the form "Futurama (season 1) episodes", where
-- firstpart = Futurama (season
-- tv = 1
-- lastpart = ) episodes
-- maximumtv = 7 ('max' tv season parameter; optional; defaults to 9999)
tv = tonumber(tv)
if tv == nil then
errors = p.errorclass('Function nav_tvseason can\'t recognize the TV season number sent to its 2nd parameter.')
return p.failedcat(errors, 'T')
end  
local maxtv = tonumber(maximumtv) or 9999 --allow +/- qualifier
if maxtv < tv then maxtv = tv end --input error; maxtv should be >= parent  
--begin navtvseason
local navt = '{|\n'..'|\n'  
local i = -5 --nav position
while i <= 5 do
local t = tv + i
if i ~= 0 then --/ navt
local catlink = catlinkfollowr( , firstpart..' '..t..lastpart, t )
if (t >= 1 and t <= maxtv) then --hardcode mintv
if catlink.rtarget then --a was followed
trackcat(25, 'Navseasoncats TV season redirected')
end
navt = navt..'*'..catlink.navelement..'\n'
else
local hidden = '<span>'..'0'..'</span>' --'0' to maintain dot spacing
navt = navt..'*'..hidden..'\n'
if listall then
tlistall[#tlistall] = tlistall[#tlistall]..' ('..hidden..')'
end
end
else -- navt
navt = navt..'*<b>'..tv..'</b>\n'
end  
i = i + 1
end  
isolatedcat
if listall then
return listalllinks
else
return navt..'|}'
end
end  
--========================================================  
local function nav_decade( , firstpart, decade, lastpart, mindecade, maxdecade )
--Expects a PAGENAME of the form "Some sequential 2000 example cat", where
-- firstpart = Some sequential
-- decade = 2000
-- lastpart = example cat