Module:Routemap
local i18n = {
 	errors = {
 		[&quot;parameter-missing&quot;] = &quot;Missing parameter!&quot;,
 		[&quot;collapsible-block-not-closed&quot;] = &quot;Collapsible section not closed properly!&quot;,
 		[&quot;collapsible-block-not-open&quot;] = &quot;Missing start-Collapsible markup!&quot;,
 		[&quot;collapsible-block-empty&quot;] = &quot;Collapsible section must not be empty!&quot;,
 		[&quot;collapsible-block-no-first-row&quot;] = &quot;Invalid first row of collapsible section!&quot;,
 		[&quot;collapsible-block-no-replacement&quot;] = &quot;Invalid collapsible replacement row!&quot;,
 		[&quot;colspan-less-rows-than-set&quot;] = &quot;Invalid colspan set!&quot;,
 	},
 	[&quot;error-categories&quot;] = {
 		default = '[[Category:Pages using Routemap with errors]]',
 		[&quot;text-images&quot;] = '[[Category:Pages using Routemap with text images]]',
 		[&quot;separate-navbar&quot;] = '[[Category:Pages using Routemap with a separate navbar template]]',
 		[&quot;missing-text-values&quot;] = '[[Category:Pages using BSto or BSsrws with missing text values]]',
 		[&quot;br-tags&quot;] = '[[Category:Pages using BSto, BSsplit, BSsrws or BScvt with br tags]]',
 		[&quot;srws&quot;] = '[[Category:Pages using BSsplit instead of BSsrws]]',
 		[&quot;rmr-error&quot;] = '[[Category:Pages with bad value for RoutemapRoute template]]'
 	},
 	text = {
 		navbar_mini = false, -- for navbar pos 2 only
 		navbar_text = 'இந்த விளக்கப்படம்:', -- for navbar pos 2 only
 		legend_text = 'Legend',
 		legend = {
 			default = '[[Template:Railway line legend',
 			track = '[[Template:Railway track legend',
 			bus = '[[Template:Bus route legend',
 			road = '[[Template:Roads legend',
 			canal = '[[Template:Waterways legend',
 			water = '[[Template:Waterways legend',
 			waterway = '[[Template:Waterways legend',
 			foot = '[[Template:Trails legend',
 			footpath = '[[Template:Trails legend',
 			walkway = '[[Template:Trails legend'
 		}
 	},
 	html = {
 		[&quot;cell-icon-fmt&quot;] = '&lt;div style=&quot;%s&quot;&gt;[[File:BSicon_%s.svg|x20px|link=%s|alt=|%s]]%s&lt;/div&gt;',
 		[&quot;cell-overlapicon-fmt&quot;] = '&lt;div class=&quot;RMic&quot; style=&quot;%s&quot;&gt;[[File:BSicon_%s.svg|x20px|link=%s|alt=|%s]]&lt;/div&gt;',
 		[&quot;cell-icon-fmt-with-overlap&quot;] = '&lt;div style=&quot;%s&quot;&gt;&lt;div class=&quot;RMov&quot;&gt;%s&lt;/div&gt;&lt;div%s&gt;[[File:BSicon_%s.svg|x20px|link=|alt=|%s]]%s&lt;/div&gt;&lt;/div&gt;',
 		[&quot;cell-text-fmt&quot;] = '&lt;div class=&quot;RMtx RM%s&quot; style=&quot;%s&quot;&gt;&lt;div%s style=&quot;%s&quot; title=&quot;%s&quot;&gt;%s%s%s%s%s%s&lt;/div&gt;&lt;/div&gt;',
 		[&quot;cell-overlaptext-fmt&quot;] = '&lt;div class=&quot;RMtx RM%s&quot; style=&quot;%s&quot;&gt;&lt;div%s style=&quot;%s&quot; title=&quot;%s&quot;&gt;%s%s%s%s%s&lt;/div&gt;&lt;/div&gt;',
 		[&quot;cell-text-fmt-with-overlap&quot;] = '&lt;div class=&quot;RM%s&quot; style=&quot;%s&quot;&gt;&lt;div class=&quot;RMov&quot;&gt;%s&lt;/div&gt;&lt;div class=&quot;RMtx RM%s&quot; style=&quot;%s&quot;&gt;&lt;div%s style=&quot;%s&quot; title=&quot;%s&quot;&gt;%s%s%s%s%s%s&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;',
 		[&quot;cell-empty-fmt&quot;] = '&lt;div class=&quot;RM%s&quot; style=&quot;%s&quot;&gt;%s&lt;/div&gt;',
 		[&quot;cell-empty-fmt-with-overlap&quot;] = '&lt;div style=&quot;%s&quot;&gt;&lt;div class=&quot;RMov&quot;&gt;%s&lt;/div&gt;&lt;div class=&quot;RMsp RM%s&quot; style=&quot;%s&quot;&gt;%s&lt;/div&gt;&lt;/div&gt;',
 
 		[&quot;cell-filler-fmt&quot;] = '&lt;div class=&quot;RMf_&quot; style=&quot;%s&quot;&gt;&lt;div class=&quot;RMfm&quot; style=&quot;background:%s&quot;&gt;&lt;/div&gt;&lt;/div&gt;',
 		[&quot;cell-filler-empty-fmt&quot;] = '&lt;div class=&quot;RMf_ RM%s&quot; style=&quot;%s&quot;&gt;&lt;/div&gt;',
 
 		[&quot;row-linfo4-fmt&quot;] = '\
 |class=&quot;RMl4&quot; style=&quot;%s&quot;|&lt;div class=&quot;RMsi&quot;&gt;%s&lt;/div&gt;',-- parameters:linfo4-width, linfo4
 		[&quot;row-linfo3-fmt&quot;] = '&lt;div class=&quot;RMsi&quot;&gt;%s&lt;/div&gt; ',
 		[&quot;row-rinfo3-fmt&quot;] = ' &lt;div class=&quot;RMsi&quot;&gt;%s&lt;/div&gt;',
 		[&quot;row-rinfo4-fmt&quot;] = '\
 |class=&quot;RMr4&quot; style=&quot;%s&quot;|&lt;div class=&quot;RMsi&quot;&gt;%s&lt;/div&gt;',-- parameters:rinfo4-width, rinfo4
 
 		[&quot;row-general-fmt&quot;] = '\
 |- %s\
 |class=&quot;RMl&quot; colspan=&quot;%s&quot; style=&quot;%s&quot;|%s\
 |%s style=&quot;%s&quot;|&lt;div class=&quot;RMsi&quot;&gt;%s&lt;/div&gt;\
 |class=&quot;RMir&quot; style=&quot;%s&quot;|%s\
 |%s style=&quot;%s&quot;|&lt;div class=&quot;RMsi&quot;&gt;%s&lt;/div&gt;\
 |class=&quot;RMr&quot; colspan=&quot;%s&quot; style=&quot;%s&quot;|%s%s',-- parameters: linfo4-fmt, colspan-left, linfo3+2-width, linfo3+2, linfo1-pad, linfo1-width, linfo1, bg, cells, rinfo1-pad, rinfo1-width, rinfo1, colspan-right, rinfo2+3-width, rinfo2+3, rinfo4-fmt
 
 		[&quot;row-collapsible-begin-fmt&quot;] = '\
 |- style=&quot;line-height:1&quot;\
 |colspan=&quot;7&quot; style=&quot;padding:0 !important;background:%s&quot;|\
 {|class=&quot;RMcollapse %s%s&quot; style=&quot;%s&quot;',-- parameters: bg, &quot;collapsible &quot;/&quot;mw-collapsible mw-&quot;, collapse-state, &quot;float:right&quot; / &quot;&quot;
 
 		[&quot;row-collapsible-end-fmt&quot;] = '\n|}',
 
 		[&quot;row-collapsible-left-button-width&quot;] = '45px',-- 50px is the minimal width for [показать] / [скрыть] button. Use 40px for [show] / [hide]
 		[&quot;row-collapsible-left-button-fmt&quot;] = '\n! style=&quot;padding-right:3px;min-width:%s;%s&quot; |',--parameters: left-button-width, linfo4-width
 		[&quot;row-collapsible-left-linfo4+3+2-fmt&quot;] = '\
 {|cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; style=&quot;line-height:1;width:100%%;padding:0 !important;margin:0 !important&quot;\
 |style=&quot;padding:0 3px 0 1px;text-align:left&quot;|&lt;div class=&quot;RMsi&quot;&gt;%s&lt;/div&gt;\
 |style=&quot;text-align:right&quot;| %s\
 |}',-- parameters: linfo4, linfo3+2
 		[&quot;row-collapsible-right-button-width&quot;] = '45px',-- 72px is the minimal width for [развернуть] / [свернуть] button at 90%. Use 58px for [expand] / [collapse]
 		[&quot;row-collapsible-right-rinfo2+3+4-fmt&quot;] = '\
 {|cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; style=&quot;line-height:1;width:100%%;padding:0 !important;margin:0 !important&quot;\
 |style=&quot;text-align:left&quot;| %s\
 |style=&quot;padding:0 1px 0 3px;text-align:right&quot;|&lt;div class=&quot;RMsi&quot;&gt;%s&lt;/div&gt;\
 |}',-- parameters: rinfo2+3, linfo4
 		[&quot;row-collapsible-right-button-fmt&quot;] = '\n| style=&quot;padding-left:3px;font-size:90%%;min-width:%s;%s&quot; |',--parameters: right-button-width, rinfo4-width
 
 		[&quot;row-collapsible-replace-begin-fmt&quot;] = '\
 |- style=&quot;line-height:1&quot;\
 |colspan=&quot;7&quot; style=&quot;padding:0 %s&quot;|&lt;div style=&quot;position:relative&quot;&gt;\
 {| class=&quot;RMreplace&quot; style=&quot;%sbackground:%s&quot;',-- parameters: &quot;right-button-width 0 0&quot; / &quot;0 0 left-button-width&quot;, &quot;right:0px&quot; / &quot;&quot;, bg
 		[&quot;row-collapsible-replace-end-fmt&quot;] = '\n|}&lt;/div&gt;',
 
 		[&quot;colspan-fmt&quot;] = '%s\n|-\n| colspan=&quot;7&quot; style=&quot;background:%s;text-align:%s;%s&quot;|\n%s',
 		[&quot;empty-row-fmt&quot;] = '\n|-\n|style=&quot;padding:0 3px 0 0;%s&quot;|\n|style=&quot;%s&quot;|\n|%s style=&quot;%s&quot;|\n|\n|%s style=&quot;%s&quot;|\n|style=&quot;%s&quot;|\n|style=&quot;padding:0 0 0 3px;%s&quot;|'
 		}
 }
 local p,q={},{}
 
 local getArgs = require('Module:Arguments').getArgs
 
 local function makeInvokeFunction(funcName)
 	-- makes a function that can be returned from #invoke, using
 	-- [[Module:Arguments]].
 	return function (frame)
 		local args = getArgs(frame, {parentOnly = true})
 		return p[funcName](args)
 	end
 end
 
 local function formaterror(key,param)
 	local result = string.format(i18n.html['colspan-fmt'], '', '', '', '', '&lt;span class=&quot;error&quot;&gt;' .. string.format(i18n.errors[key] or (tostring(key) .. ' %s'),
 		tostring(param or '')) .. '&lt;/span&gt;')
 	if mw.site.namespaces[mw.title.getCurrentTitle().namespace].isContent then result = result .. (i18n['error-categories'][key] or i18n['error-categories'].default or '') end
 	return result
 end
 
 local function RGBbyCode(code)-- RGB codes for BSicon sets at Commons:Category:Icons for railway descriptions/other colors
 	local colors = {--       Any changes should be discussed at Commons:Talk:BSicon/Colors
 		bahn     = 'BE2D2C', ex          = 'D77F7E',
 		u        = '003399', uex         = '6281C0',
 		f        = '008000', fex         = '64B164',
 		g        = '2CA05A', gex         = '7EC49A',
 		azure    = '3399FF', ex_azure    = '99CCFF',
 		black    = '000000', ex_black    = '646464',
 		blue     = '0078BE', ex_blue     = '64ACD6',
 		brown    = '8D5B2D', ex_brown    = 'B89A7F',
 		carrot   = 'ED9121', ex_carrot   = 'F1BA76', excarrot   = 'F1BA76', ex_excarrot   = 'F3D2A9',
 		cerulean = '1A8BB9', ex_cerulean = '73B7D3',
 		cyan     = '40E0D0', ex_cyan     = '8AEAE1',
 		deepsky  = '00BFFF', ex_deepsky  = '7FDFFF',
 		denim    = '00619F', ex_denim    = '649EC3',
 		fuchsia  = 'B5198D', ex_fuchsia  = 'D173B8',
 		golden   = 'D7C447', ex_golden   = 'E5DA8E',
 		green    = '2DBE2C', ex_green    = '7FD67E',
 		grey     = '999999', ex_grey     = 'C0C0C0',
 		jade     = '53B147', ex_jade     = '95CE8E',
 		lavender = '9999FF', ex_lavender = 'C0C0FF',
 		lime     = '99CC00', ex_lime     = 'D1E681',
 		maroon   = '800000', ex_maroon   = 'B16464',
 		ochre    = 'CC6600', ex_ochre    = 'DEA164',
 		olive    = '837902', ex_olive    = 'B2AC64',
 		orange   = 'FF6600', ex_orange   = 'FF9955',
 		pink     = 'F0668D', ex_pink     = 'F4A1B8',
 		purple   = '8171AC', ex_purple   = 'B1A8CB',
 		red      = 'EF161E', ex_red      = 'F37176',
 		ruby     = 'CC0066', ex_ruby     = 'DE64A1', exruby     = 'DE64A1', ex_exruby     = 'E89FC4',
 		saffron  = 'FFAB2E', ex_saffron  = 'FFC969',
 		sky      = '069DD3', ex_sky      = '67C2E3',
 		steel    = 'A1B3D4', ex_steel    = 'C4CFE3',
 		teal     = '339999', ex_teal     = '82C0C0', exteal     = '82C0C0', ex_exteal     = 'B1D6D6',
 		violet   = '800080', ex_violet   = 'B164B1',
 		yellow   = 'FFD702', ex_yellow   = 'FFEB81',
 	}
 	return colors[code] or colors.bahn
 end
 
 p.RGBbyCode = makeInvokeFunction('_RGBbyCode')
 
 function p._RGBbyCode(args)
 	return RGBbyCode(args[1])
 end
 
 local function properties(str)
 --str is a combination of properties with following syntax:
 --property name=value,property name1=value1,property name2=value2 and so on
 	local result = {}
 	for i, v in ipairs(mw.text.split(str, ',')) do
 		if v then
 			local t = mw.text.split(v, '=')
 			if string.find(v, '=') then
 				t[1] = mw.text.trim(t[1]) --trim parameter names
 				table.insert(result, t[1])
 				result[t[1]] = t[2] or '' --fill table with pairs &quot;property&quot;=&quot;value&quot;
 			elseif result[result[i - 1]] then
 				table.insert(result, result[i - 1])
 				result[result[i]] = result[result[i]]..','..t[1] --if no equals sign then tack t[1] onto the previous result
 			else
 				table.insert(result, '~~')
 			end
 		else
 			table.insert(result, '~~')
 		end
 	end
 	return result
 end
 
 local function positive(x)
 	if not x then return nil else x = string.lower(x) end
 	if x == 'yes' or x == 'y' or x == '1' or x == 'true' then return 1 end
 end
 
 local function negative(x)
 	if not x then return nil else x = string.lower(x) end
 	if x == 'no' or x == 'n' or x == '0' or x == 'false' then return 0 end
 end
 
 local function alignment(x, y, z)
 	if not x then return nil end
 	local directions = {
 		['inherit-left']    = {'l', 'left',},
 		['inherit-right']   = {'r', 'right',},
 		['top-inherit']     = {'a', 't', 'top',},
 		['bottom-inherit']  = {'e', 'b', 'bottom',},
 		['top-left']        = {'la', 'tl', 'c4', 'nw', 'top-left', 'topleft',},
 		['top-right']       = {'ra', 'tr', 'c1', 'ne', 'top-right', 'topright',},
 		['bottom-left']     = {'le', 'bl', 'c3', 'sw', 'bottom-left', 'bottomleft',},
 		['bottom-right']    = {'re', 'br', 'c2', 'se', 'bottom-right', 'bottomright',},
 		['inherit-center']  = {'c', 'center', 'centre',},
 		['middle-inherit']  = {'m', 'middle',},
 		['top-center']      = {'ma', 'tc', 'top-center', 'top-centre', 'topcenter', 'topcentre',},
 		['bottom-center']   = {'me', 'bc', 'bottom-center', 'bottom-centre', 'bottomcenter', 'bottomcentre',},
 		['middle-left']     = {'lm', 'ml', 'middle-left', 'middleleft',},
 		['middle-right']    = {'rm', 'mr', 'middle-right', 'middleright',},
 		['middle-center']   = {'cm', 'mc', 'middle-center', 'middle-centre', 'middlecenter', 'middlecentre',},
 	}
 	for k, v in pairs(directions) do
 		for _, name in ipairs(v) do
 			if x:lower() == name then
 				local values = mw.text.split(k, '-')
 				if values[1] == 'inherit' then values[1] = y end
 				if values[2] == 'inherit' then values[2] = z end
 				return values
 			end
 		end
 	end
 	return {y, z}
 end
 
 local function cell(icon,overlapIcons,rowProps)--[[
 
 Icon handling. Each icon is defined as in the following example:
 icon ID!~overlap icon ID!@image link target
 Values for an icon ID containing &quot;*&quot; are treated as text, with the letter(s) before &quot;*&quot; as width prefix(es).
 No limit on overlapping icons or text; just separate them by &quot;!~&quot;.
 Parameters can be added after every object, separated to the left by &quot;!_&quot;. This, if there is a link, must be after the link.
 Parameters for individual objects in an overlapping stack can also be added, separated to the left by &quot;__&quot;.
 Unless a link is provided, each cell will have mouseover text indicating its contents.
 
 ]]
 	local tmp, tmp2, cellProps, iconProps, overlapProps, tmp_sep, link, tracking, icontext, iconpre = {}, {}, {}, {}, {}, '', '', ''
 	if #overlapIcons &gt; 0 then
 		tmp = mw.text.split(overlapIcons[#overlapIcons], '!_')
 		if #tmp &gt; 1 then overlapIcons[#overlapIcons], cellProps = tmp[1], properties(tmp[2]) end
 		tmp = mw.text.split(overlapIcons[#overlapIcons], '!@')
 		overlapIcons[#overlapIcons] = tmp[1]
 		if #tmp &gt; 1 then link = tmp[2] end
 		tmp = mw.text.split(icon, '__')
 		icon = tmp[1]
 		if #tmp &gt; 1 then iconProps = properties(tmp[2]) end
 		for i, v in ipairs(overlapIcons) do
 			tmp = mw.text.split(v, '__')
 			overlapIcons[i] = mw.text.trim(tmp[1])
 			if #tmp &gt; 1 then overlapProps[i] = properties(tmp[2]) else overlapProps[i] = {} end
 		end
 	else
 		tmp = mw.text.split(icon, '[!_]_')
 		if #tmp &gt; 1 then icon, cellProps = tmp[1], properties(tmp[2]) end
 		tmp = mw.text.split(icon, '!@')
 		icon = mw.text.trim(tmp[1])
 		if #tmp &gt; 1 then link = tmp[2] end
 	end
 	if #overlapIcons &gt; 0 and icon ~= '' then tmp_sep = '; ' end
 	local icontip = mw.text.nowiki(mw.text.unstripNoWiki(icon..tmp_sep..table.concat(overlapIcons, '; ')))
 	local textspl = string.find(icon, '%*')
 	if textspl then
 		icontext = mw.text.trim(mw.ustring.sub(icon, textspl + 1))
 		if textspl ~= 1 then iconpre = mw.text.trim(mw.ustring.sub(icon, 1, textspl - 1)) end
 	end
 	cellProps.class = ''
 	if cellProps.style then cellProps.style = ';'..cellProps.style else cellProps.style = '' end
 	cellProps.bg = cellProps.bg or cellProps.background or cellProps.bgcolor
 	if cellProps.bg then cellProps.style = cellProps.style..';background:'..cellProps.bg end
 	if #overlapIcons &gt; 0 or icontext then
 		cellProps._before, cellProps._after = rowProps._before or '', rowProps._after or ''
 		cellProps.color = cellProps.color or cellProps.colour ; cellProps.bold = cellProps.bold or cellProps.b ; cellProps.italic = cellProps.italic or cellProps.i or cellProps.it
 		if cellProps.color then cellProps.style = cellProps.style..';color:'..cellProps.color end
 		if positive(cellProps.italic) then cellProps.style = cellProps.style..';font-style:italic' end
 		if positive(cellProps.bold) then cellProps.style = cellProps.style..';font-weight:bold' end
 		if not cellProps.fontsize or rowProps.fontsize or cellProps.fontsize == 'info' then
 		elseif cellProps.fontsize == 'cmt' or cellProps.fontsize == 'comment' then
 			cellProps._before, cellProps._after = '&lt;div class=&quot;RMsi&quot;&gt;', '&lt;/div&gt;'
 		else
 			cellProps.style = cellProps.style..';font-size:'..cellProps.fontsize
 		end
 		if cellProps.align or rowProps.align then
 			rowProps.align = rowProps.align or {'middle', 'center'}
 			cellProps.align = alignment(cellProps.align, rowProps.align[1], rowProps.align[2]) or rowProps.align
 			cellProps.style, cellProps.textfmt = cellProps.style..';text-align:'..cellProps.align[2], ';vertical-align:'..cellProps.align[1]
 		else
 			cellProps.textfmt = ''
 		end
 	end
 	if #overlapIcons &gt; 0 then
 		tmp = {}
 		for i, v in ipairs(overlapIcons) do
 			local thislink = link
 			if i ~= #overlapIcons then thislink = '' end
 			if thislink and thislink ~= '' then icontip = thislink end
 			if overlapProps[i].style then overlapProps.style = ';'..overlapProps[i].style else overlapProps.style = '' end
 			overlapProps[i].bg = overlapProps[i].bg or overlapProps[i].background or overlapProps[i].bgcolor
 			if overlapProps[i].bg then overlapProps.style = overlapProps.style..';background:'..overlapProps[i].bg end
 			local tmp_textspl = string.find(v, '%*')
 			if tmp_textspl then
 				overlapProps.class = ''
 				local tmp_icontext, tmp_iconpre = mw.text.trim(mw.ustring.sub(v, tmp_textspl + 1)), ''
 				if tmp_textspl ~= 1 then tmp_iconpre = mw.text.trim(mw.ustring.sub(v, 1, tmp_textspl - 1)) end
 				overlapProps._before, overlapProps._after = cellProps._before, cellProps._after
 				overlapProps[i].color = overlapProps[i].color or overlapProps[i].colour ; overlapProps[i].bold = overlapProps[i].bold or overlapProps[i].b ; overlapProps[i].italic = overlapProps[i].italic or overlapProps[i].i or overlapProps[i].it
 				if overlapProps[i].color then overlapProps.style = overlapProps.style..';color:'..overlapProps[i].color end
 				if positive(overlapProps[i].italic) then overlapProps.style = overlapProps.style..';font-style:italic' end
 				if positive(overlapProps[i].bold) then overlapProps.style = overlapProps.style..';font-weight:bold' end
 				if rowProps.fontsize or cellProps.fontsize or overlapProps[i].fontsize == 'info' then
 				elseif not overlapProps[i].fontsize then
 					overlapProps.class = ' class=&quot;RMts&quot;'
 				elseif overlapProps[i].fontsize == 'cmt' or overlapProps[i].fontsize == 'comment' then
 					overlapProps._before, overlapProps._after = '&lt;div class=&quot;RMsi&quot;&gt;', '&lt;/div&gt;'
 				else
 					overlapProps.style = overlapProps.style..';font-size:'..overlapProps[i].fontsize
 				end
 				if overlapProps[i].align or cellProps.align then
 					cellProps.align = cellProps.align or {'middle', 'center'}
 					overlapProps.align = alignment(overlapProps[i].align, cellProps.align[1], cellProps.align[2]) or cellProps.align
 					overlapProps.style, overlapProps.textfmt = overlapProps.style..';text-align:'..overlapProps.align[2], ';vertical-align:'..overlapProps.align[1]
 				else
 					overlapProps.style, overlapProps.textfmt = overlapProps.style..';text-align:center', ';vertical-align:middle'
 				end
 				if overlapProps[i].abbr then
 					overlapProps.tag = {'&lt;abbr title=&quot;'..string.gsub(overlapProps[i].abbr, '&quot;', '&amp;quot;')..'&quot;&gt;', '&lt;/abbr&gt;'}
 				else
 					overlapProps.tag = {'', ''}
 				end
 				table.insert(tmp, string.format(i18n.html['cell-overlaptext-fmt'], (tmp_iconpre and tmp_iconpre ~= '' and tmp_iconpre or '_'), overlapProps.style, overlapProps.class, overlapProps.textfmt, icontip, overlapProps.tag[1], overlapProps._before, tmp_icontext, overlapProps._after, overlapProps.tag[2]))
 			else
 				v = mw.text.trim(v)
 				if string.find(v, 'num') then
 					if not string.find(v, 'numN%d+') then tracking = tracking..(i18n['error-categories']['text-images'] or i18n['error-categories'].default) end
 				end
 				table.insert(tmp, string.format(i18n.html['cell-overlapicon-fmt'], overlapProps.style, v, thislink, icontip))
 			end
 		end
 		if iconProps.style then tmp2[1] = true else iconProps.style = '' end
 		iconProps.bg = iconProps.bg or iconProps.background or iconProps.bgcolor
 		if iconProps.bg then iconProps.style = iconProps.style..';background:'..iconProps.bg end
 		if string.match(icon, '^[%+_]?o?c?d?b?s?w?$') then
 			if tmp2[1] then iconProps.style = ';'..iconProps.style end
 			return string.format(i18n.html['cell-empty-fmt-with-overlap'], cellProps.style, mw.text.trim(table.concat(tmp)), (string.match(icon, '^.+$') or '_'), iconProps.style, tracking)
 		elseif icontext then
 			iconProps.class = ''
 			iconProps._before, iconProps._after = cellProps._before, cellProps._after
 			iconProps.color = iconProps.color or iconProps.colour ; iconProps.bold = iconProps.bold or iconProps.b ; iconProps.italic = iconProps.italic or iconProps.i or iconProps.it
 			if iconProps.color then iconProps.style = iconProps.style..';color:'..iconProps.color end
 			if positive(iconProps.italic) then iconProps.style = iconProps.style..';font-style:italic' end
 			if positive(iconProps.bold) then iconProps.style = iconProps.style..';font-weight:bold' end
 			if rowProps.fontsize or cellProps.fontsize or iconProps.fontsize == 'info' then
 			elseif not iconProps.fontsize then
 				iconProps.class = ' class=&quot;RMts&quot;'
 			elseif iconProps.fontsize == 'cmt' or iconProps.fontsize == 'comment' then
 				iconProps._before, iconProps._after = '&lt;div class=&quot;RMsi&quot;&gt;', '&lt;/div&gt;'
 			else
 				iconProps.style = iconProps.style..';font-size:'..iconProps.fontsize
 			end
 			if iconProps.align or cellProps.align then
 				cellProps.align = cellProps.align or {'middle', 'center'}
 				iconProps.align = alignment(iconProps.align, cellProps.align[1], cellProps.align[2]) or cellProps.align
 				iconProps.style, iconProps.textfmt = iconProps.style..';text-align:'..iconProps.align[2], ';vertical-align:'..iconProps.align[1]
 			else
 				iconProps.style, iconProps.textfmt = iconProps.style..';text-align:center', ';vertical-align:middle'
 			end
 			if iconProps.abbr then
 				iconProps.tag = {'&lt;abbr title=&quot;'..string.gsub(iconProps.abbr, '&quot;', '&amp;quot;')..'&quot;&gt;', '&lt;/abbr&gt;'}
 			else
 				iconProps.tag = {'', ''}
 			end
 			if tmp2[1] then iconProps.style = ';'..iconProps.style end
 			return string.format(i18n.html['cell-text-fmt-with-overlap'], (iconpre and iconpre ~= '' and iconpre or '_'), cellProps.style, mw.text.trim(table.concat(tmp)), (iconpre and iconpre ~= '' and iconpre or '_'), iconProps.style, iconProps.class, iconProps.textfmt, icontip, iconProps.tag[1], iconProps._before, icontext, iconProps._after, tracking, iconProps.tag[2])
 		else
 			if iconProps.style ~= '' then iconProps.style = string.gsub(' style=&quot;'..iconProps.style..'&quot;', '&quot;;', '&quot;', 1) end
 			if string.find(icon, 'num') then
 				if not string.find(icon, 'numN%d+') then tracking = tracking..(i18n['error-categories']['text-images'] or i18n['error-categories'].default) end
 			end
 			return string.format(i18n.html['cell-icon-fmt-with-overlap'], cellProps.style, mw.text.trim(table.concat(tmp)), iconProps.style, icon, icontip, tracking)
 		end
 	end
 	if string.match(icon, '^[%+_]?o?c?d?b?s?w?$') then
 		return string.format(i18n.html['cell-empty-fmt'], (string.match(icon, '^.+$') or '_'), cellProps.style, tracking)
 	else
 		if link and link ~= '' then icontip = link end
 		if icontext then
 			if not cellProps.fontsize and not rowProps.fontsize then cellProps.class = ' class=&quot;RMts&quot;' end
 			if cellProps.abbr then
 				cellProps.tag = {'&lt;abbr title=&quot;'..string.gsub(cellProps.abbr, '&quot;', '&amp;quot;&gt;')..'&quot;&gt;', '&lt;/abbr&gt;'}
 			else
 				cellProps.tag = {'', ''}
 			end
 			return string.format(i18n.html['cell-text-fmt'], (iconpre and iconpre ~= '' and iconpre or '_'), cellProps.style, cellProps.class, cellProps.textfmt, icontip, cellProps.tag[1], cellProps._before, icontext, cellProps._after, tracking, cellProps.tag[2])
 		else
 			if string.find(icon, 'num') then
 				if not string.find(icon, 'numN%d+') then tracking = tracking..(i18n['error-categories']['text-images'] or i18n['error-categories'].default) end
 			end
 			return string.format(i18n.html['cell-icon-fmt'], cellProps.style, icon, link, icontip, tracking)
 		end
 	end
 end
 
 local function fillercell(code, height)
 --Creates a 5px-high row.
 --Values in icon pattern can only be [blank], d, [BSicon color] or #[hex triplet].
 	height = mw.text.trim(height)
 	if height ~= '' then
 		if tonumber(height) then height = height..'px' end
 		height = 'height:'..height..';min-height:'..height
 	end
 	if string.match(code, '^[%+_]?o?c?d?b?s?w?$') then
 		return string.format(i18n.html['cell-filler-empty-fmt'], (string.match(code, '^.+$') or '_'), height)
 	elseif mw.ustring.sub(code,1,1) == '#' then
 		return string.format(i18n.html['cell-filler-fmt'], height, code)
 	else
 		return string.format(i18n.html['cell-filler-fmt'], height, '#'..RGBbyCode(code))
 	end
 end
 
 local function row(pattern,noformatting,filler)--[[
 
 Row handling. Each row looks like the following:
 row properties~~linfo4~~linfo3~~linfo2~~linfo1! !(icon pattern)~~rinfo1~~rinfo2~~rinfo3~~rinfo4~~row properties
 
 ]]
 	local result = {['linfo4'] = '', ['linfo3+2'] = '', ['linfo1'] = '', rowstyle = '', ['cells'] = {}, ['rinfo1'] = '', ['rinfo2+3'] = '', ['rinfo4'] = '', ['rowProp'] = {}}
 	local lcolspan, rcolspan, linfo4_fmt, rinfo4_fmt = '2', '2', '', ''
 	local left, right, icons, overlapIcons, tmp = {}, {}, {}, {}, mw.text.split(pattern, '! !')
 	if #tmp &gt; 1 then--splitting the pattern by '! !'
 		left = tmp[1] ; right = tmp[2]
 	else
 		left = '' ; right = tmp[1] or ''
 	end
 
 	tmp = mw.text.split(left, '~~')--analysing the left part
 	if #tmp &gt; 1 then--if there are several ~~
 		result['linfo1'] = mw.getCurrentFrame():preprocess(mw.text.trim(tmp[#tmp]))
 		result['linfo3+2'] = mw.text.trim(tmp[#tmp - 1])
 		if #tmp &gt; 2 then
 			tmp[#tmp - 2] = mw.text.trim(tmp[#tmp - 2])
 			if tmp[#tmp - 2] ~= '' then result['linfo3+2'] = string.format(i18n.html['row-linfo3-fmt'], tmp[#tmp - 2]) .. result['linfo3+2'] end
 			if #tmp &gt; 3 then
 				tmp[#tmp - 3] = mw.text.trim(tmp[#tmp - 3])
 				if tmp[#tmp - 3] ~= '' then
 					result['linfo4'] = mw.getCurrentFrame():preprocess(tmp[#tmp - 3])
 					lcolspan = '1'
 					linfo4_fmt = string.format(i18n.html['row-linfo4-fmt'], '', result['linfo4'])
 				end
 				if #tmp &gt; 4 then result.rowProp = properties(mw.text.trim(tmp[#tmp - 4])) end
 			end
 		end
 	else--assume only linfo2 was provided.
 		result['linfo3+2'] = mw.text.trim(tmp[1])
 	end
 	result['linfo3+2'] = mw.getCurrentFrame():preprocess(result['linfo3+2'])--expand possible templates in info.
 
 	tmp = mw.text.split(right, '~~')--analysing the right part
 	if #tmp &gt; 2 then
 		result['rinfo1'] = mw.getCurrentFrame():preprocess(mw.text.trim(tmp[2]))
 		result['rinfo2+3'] = mw.text.trim(tmp[3])
 		if #tmp &gt; 3 then
 			tmp[4] = mw.text.trim(tmp[4])
 			if tmp[4] ~= '' then result['rinfo2+3'] = result['rinfo2+3'] .. string.format(i18n.html['row-rinfo3-fmt'], tmp[4]) end
 			if #tmp &gt; 4 then
 				tmp[5] = mw.text.trim(tmp[5])
 				if tmp[5] ~= '' then
 					result['rinfo4'] = mw.getCurrentFrame():preprocess(tmp[5])
 					rcolspan = '1'
 					rinfo4_fmt = string.format(i18n.html['row-rinfo4-fmt'], '', result['rinfo4'])
 				end
 				if #tmp &gt; 5 then result.rowProp = properties(mw.text.trim(tmp[6])) end
 			end
 		end
 	else--assume only rinfo2 was provided.
 		result['rinfo2+3'] = mw.text.trim(tmp[2] or '')
 	end
 	result['rinfo2+3'] = mw.getCurrentFrame():preprocess(result['rinfo2+3'])
 
 -- The below parameter functions are passed through to the cells.
 	if result.rowProp.fontsize == 'cmt' or result.rowProp.fontsize == 'comment' then
 		result.rowProp._before, result.rowProp._after = '&lt;div class=&quot;RMsi&quot;&gt;', '&lt;/div&gt;'
 	end
 	if result.rowProp.align then
 		result.rowProp.align = alignment(result.rowProp.align, 'middle', 'center') or {'middle', 'center'}
 	end
 
 	icons = mw.text.split(tmp[1], '\\')--splitting the string of icons first by &quot;\&quot;
 	if type(filler) == 'string' then
 		result.style = ';font-size:0px'
 		for i, v in ipairs(icons) do table.insert(result['cells'], fillercell(v, filler)) end--no !@ or !~ for filler row
 	else
 		result.style = ''
 		for i, v in ipairs(icons) do
 			tmp = mw.text.split(v, '!~')
 			icons[i] = tmp[1]
 			table.remove(tmp, 1)
 			table.insert(overlapIcons, tmp)
 		end
 		for i, v in ipairs(icons) do table.insert(result['cells'], cell(v, overlapIcons[i], result.rowProp)) end
 	end
 	result['cells'] = table.concat(result['cells'])
 	if result.rowProp.style then result.style = result.style..';'..result.rowProp.style end
 	result.rowProp.bg = result.rowProp.bg or result.rowProp.background or result.rowProp.bgcolor ; result.rowProp.color = result.rowProp.color or result.rowProp.colour ; result.rowProp.bold = result.rowProp.bold or result.rowProp.b ; result.rowProp.italic = result.rowProp.italic or result.rowProp.i or result.rowProp.it
 	if result.rowProp.bg then result.style = result.style..';background:'..result.rowProp.bg end
 	if result.rowProp.color then result.style = result.style..';color:'..result.rowProp.color end
 	if positive(result.rowProp.italic) then result.style = result.style..';font-style:italic' end
 	if positive(result.rowProp.bold) then result.style = result.style..';font-weight:bold' end
 	if result.rowProp.fontsize and result.rowProp._after == '' and result.rowProp.fontsize ~= 'info' then
 		result.style = result.style..';font-size:'..result.rowProp.fontsize
 	end
 	if noformatting then
 		return result
 	else
 		return string.format(i18n.html['row-general-fmt'], linfo4_fmt, lcolspan, '', result['linfo3+2'], q.linfo1_pad, '', result['linfo1'], result.style,
 			result['cells'], q.rinfo1_pad, '', result['rinfo1'], rcolspan, '', result['rinfo2+3'], rinfo4_fmt)
 	end
 end
 
 --↓ This table handles diagram rows beginning with a hyphen (&quot;-&quot;).
 q = {collapsibles = -1, text_width = {'', '', '', '', '', ''}, linfo1_pad = 'class=&quot;RMl1&quot;', rinfo1_pad = 'class=&quot;RMr1&quot;', bg = '#F9F9F9'}
 q.isKeyword = function(pattern, i, rows, justTest)
 	if mw.ustring.sub(pattern, 1, 1) ~= '-' then if justTest then return false else return nil end end--not a valid keyword
 	local tmp = mw.text.split(string.sub(pattern, 2), '%-')
 	if type(q[tmp[1]])==&quot;function&quot; and tmp[1] ~= 'isKeyword' then
 		if justTest then return tmp[1] else return q[tmp[1]](tmp, i, rows) end--valid keyword
 	else
 		if justTest then return false else return nil end
 	end
 end
 q['startCollapsible'] = function(params, i, rows)
 	table.remove(rows, i)
 	local tmp = q.isKeyword(rows[i], i, rows, true)
 	if tmp then
 		if tmp == 'endCollapsible' then return formaterror('collapsible-block-empty')
 		else return formaterror('collapsible-block-no-first-row') .. q.isKeyword(rows[i], i, rows) --no valid keywords that can follow &quot;startCollapsible&quot;
 		end
 	end
 	if q.collapsibles == -1 then q.collapsibles = 1 else q.collapsibles = q.collapsibles + 1 end--q.collapsibles == -1 means there are no collapsibles at all; 0 - all closed; &gt;0 - some not closed
 	local collapsed, replace, props = params[2], params[3] or '', properties(table.concat(params, '-', 4))--params[1] is the keyword name so all indices are shifted by one.
 	if collapsed == nil or collapsed == '' then collapsed = 'collapsed' end
 	if props.bg == nil or props.bg == '' then props.bg = 'transparent' ; props['bg-replace'] = q.bg else props['bg-replace'] = props.bg end
 	local mode, float, result
 	if q.rinfo1_pad == '' then mode = 'collapsible ' ; float = 'float:right;'
 	else mode = 'mw-collapsible mw-' ; float = ''
 	end
 	result = string.format(i18n.html[&quot;row-collapsible-begin-fmt&quot;], props.bg, mode, collapsed, float)
 	tmp = row(rows[i], true, nil)
 	local linfo4_3_2_fmt, rinfo2_3_4_fmt = '', ''
 	if q.rinfo1_pad == '' then
 		if tmp['linfo4'] ~= '' or tmp['linfo3+2'] ~= '' then linfo4_3_2_fmt = string.format(i18n.html['row-collapsible-left-linfo4+3+2-fmt'], tmp['linfo4'], tmp['linfo3+2']) end
 		result = result .. string.format(i18n.html['row-general-fmt'], string.format(i18n.html['row-collapsible-left-button-fmt'], i18n.html['row-collapsible-left-button-width'], q.text_width[1]),
 			'1', q.text_width[2], linfo4_3_2_fmt, q.linfo1_pad, q.text_width[3], tmp['linfo1'], tmp.style, tmp['cells'], '', '', '', '1', '', '', string.format(i18n.html['row-rinfo4-fmt'], '', ''))
 	else
 		if tmp['rinfo4'] ~= '' or tmp['rinfo2+3'] ~= '' then rinfo2_3_4_fmt = string.format(i18n.html['row-collapsible-right-rinfo2+3+4-fmt'], tmp['rinfo2+3'], tmp['rinfo4']) end
 		result = result .. string.format(i18n.html['row-general-fmt'], string.format(i18n.html['row-linfo4-fmt'], q.text_width[1], tmp['linfo4']),
 			'1', q.text_width[2], tmp['linfo3+2'], q.linfo1_pad, q.text_width[3], tmp['linfo1'], tmp.style, tmp['cells'], q.rinfo1_pad, q.text_width[4], tmp['rinfo1'],
 			'1', q.text_width[5], rinfo2_3_4_fmt, string.format(i18n.html['row-collapsible-right-button-fmt'], i18n.html['row-collapsible-right-button-width'], q.text_width[6]))
 	end
 	if replace ~= '' then
 		if q.isKeyword(rows[i + 1], i, rows, true) then return result .. formaterror('collapsible-block-no-replacement') end--a plain row needed for replacement
 		table.remove(rows, i)
 		tmp = row(rows[i], true, nil)
 		local padding, right = i18n.html['row-collapsible-right-button-width'] .. ' 0 0', ''
 		if q.rinfo1_pad == '' then padding = '0 0 ' .. i18n.html['row-collapsible-left-button-width'] ; right = 'right:0px;' end
 		result = result .. string.format(i18n.html['row-collapsible-replace-begin-fmt'], padding, right, props['bg-replace'])
 		linfo4_3_2_fmt = '' ; rinfo2_3_4_fmt = ''
 		if q.rinfo1_pad == '' then
 			if tmp['linfo4'] ~= '' or tmp['linfo3+2'] ~= '' then linfo4_3_2_fmt = string.format(i18n.html['row-collapsible-left-linfo4+3+2-fmt'], tmp['linfo4'], tmp['linfo3+2']) end
 			result = result .. string.format(i18n.html['row-general-fmt'], string.format(i18n.html['row-linfo4-fmt'], '', ''), '1', q.text_width[2], linfo4_3_2_fmt,
 				q.linfo1_pad, q.text_width[3], tmp['linfo1'], tmp.style, tmp['cells'], '', '', '', '1', '', '', string.format(i18n.html['row-rinfo4-fmt'], '', ''))
 		else
 			if tmp['rinfo4'] ~= '' or tmp['rinfo2+3'] ~= '' then rinfo2_3_4_fmt = string.format(i18n.html['row-collapsible-right-rinfo2+3+4-fmt'], tmp['rinfo2+3'], tmp['rinfo4']) end
 			result = result .. string.format(i18n.html['row-general-fmt'], string.format(i18n.html['row-linfo4-fmt'], q.text_width[1], tmp['linfo4']), '1', q.text_width[2],
 				tmp['linfo3+2'], q.linfo1_pad, q.text_width[3], tmp['linfo1'], tmp.style, tmp['cells'], q.rinfo1_pad, q.text_width[4], tmp['rinfo1'], '1', q.text_width[5],
 				rinfo2_3_4_fmt, string.format(i18n.html['row-rinfo4-fmt'], '', ''))
 		end
 		result = result .. i18n.html['row-collapsible-replace-end-fmt']
 	end
 	return result
 end
 q['endCollapsible'] = function(params, i, rows)
 	if q.collapsibles &gt; 0 then
 		q.collapsibles = q.collapsibles - 1
 		return i18n.html['row-collapsible-end-fmt']
 	else
 		return formaterror('collapsible-block-not-open')
 	end
 end
 q['colspan'] = function(params, i, rows)
 	if params[2] == 'end' then return '' end
 	local tmp, j, nrows, props = {}, 0, tonumber(params[2]), properties(table.concat(params, '-', 3))
 	if nrows ~= 0 then table.remove(rows, i) end
 	if nrows == nil then nrows = #rows - i + 1 end
 	while j &lt; nrows and i &lt;= #rows do
 		j = j + 1
 		if rows[i] == '-colspan-end'  then
 			j = nrows
 		else
 			table.insert(tmp, rows[i])
 		end
 		if nrows ~= j or i == #rows then table.remove(rows, i) end
 	end
 	if j &lt; nrows then j = formaterror('colspan-less-rows-than-set',j) else j = '' end
 	return string.format(i18n.html['colspan-fmt'], j, props.bg or '', props.align or '', props['style'] or '', mw.getCurrentFrame():preprocess(table.concat(tmp, '\n')))
 end
 q['filler'] = function(params, i, rows)
 	local tmp, height = table.concat(params, '-', 3), (params[2] or '')
 	if #params &lt; 3 or tmp == '' then return formaterror('parameter-missing') end--TODO: specify the name of the parameter
 	if params[2] ~= '' then height = params[2] end
 	return row(tmp, nil, height)
 end
 
 function p.RGBbyCode(frame)
 	return RGBbyCode(mw.text.trim(frame.args[1] or ''))
 end
 
 local function localroute(pattern,ptw,pbg,process)
 	local tmp = {}
 	if mw.text.trim(pbg) ~= '' then q.bg = pbg end
 	tmp = mw.text.split(mw.text.trim(ptw), '%s*,%s*')
 	if #tmp == 6 then
 		for i = 1, 6 do
 			if tmp[i] ~= '' then
 				if tonumber(string.sub(tmp[i],-1)) then
 					q.text_width[i] = 'width:' .. tmp[i] .. 'px;min-width:' .. tmp[i] .. 'px;'
 				else
 					q.text_width[i] = 'width:' .. tmp[i] .. ';min-width:' .. tmp[i] .. ';'
 				end
 			end
 		end
 		if tmp[4] == '' and tmp[5] == '' and tmp[6] == '' then
 			q.rinfo1_pad = ''--padding for rinfo1 column = 0, not 3px
 		elseif tmp[1] == '' and tmp[2] == '' and tmp[3] == '' then
 			q.linfo1_pad = ''
 		end--padding for linfo1 column = 0, not 3px
 	elseif #tmp == 3 then
 		for i = 1, 3 do
 			if tmp[i] ~= '' then
 				if tonumber(string.sub(tmp[i],-1)) then
 					q.text_width[i + 3] = 'width:' .. tmp[i] .. 'px;min-width:' .. tmp[i] .. 'px;'
 				else
 					q.text_width[i + 3] = 'width:' .. tmp[i] .. ';min-width:' .. tmp[i] .. ';'
 				end
 			end
 		end
 		q.linfo1_pad = ''
 	elseif #tmp == 1 and tmp[1] ~= '' then
 		if tonumber(string.sub(tmp[1],-1)) then
 			q.text_width[5] = 'width:' .. tmp[1] .. 'px;min-width:' .. tmp[1] .. 'px;'
 		else
 			q.text_width[5] = 'width:' .. tmp[1] .. ';min-width:' .. tmp[1] .. ';'
 		end
 		q.linfo1_pad = ''
 	end
 	for i = 1, 6 do
 		tmp = tonumber(mw.ustring.match(q.text_width[i], ':([0-9]+%.?[0-9]*)px;'))
 		if tmp then
 			tmp = tmp*3/40
 			q.text_width[i] = 'width:' .. tmp .. 'em;min-width:' .. tmp .. 'em;'
 		end
 	end
 	tmp = {}
 
 	local index = 0
 	local rows = {}
 	if not process or process == '' or negative(process) then
 		pattern = mw.ustring.gsub(pattern, '\n(#[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])', '%1')
 	end
 	for item in pattern:gmatch('([^\n]*)\n?') do
 		item = mw.text.trim(item)
 		if item ~= '' then
 			index = index + 1
 			rows[index] = item
 		end
 	end
 	if index == 0 then return formaterror('parameter-missing') end
 	for i, v in ipairs(rows) do
 		local keyword = q.isKeyword(v, i, rows)
 		if type(keyword) ~= &quot;string&quot; then
 			table.insert(tmp, row(v, nil, nil))
 		else
 			table.insert(tmp, keyword)
 		end
 	end
 
 	if q.collapsibles &gt; 0 then table.insert(tmp, formaterror('collapsible-block-not-closed') .. q['endCollapsible']()) end
 	if q.collapsibles ~= -1 then
 		if q.rinfo1_pad == '' then
 			q.text_width[1] = q.text_width[1] .. 'min-width:' .. i18n.html['row-collapsible-left-button-width'] .. ';'
 		else
 			q.text_width[6] = q.text_width[6] .. 'min-width:' .. i18n.html['row-collapsible-right-button-width'] .. ';'
 		end
 	end
 	-- ↓ empty row to set column widths; ↑ if q.collapsibles ≠ -1 and there are collapsible sections, leftmost or rightmost column should be wide enough to accomodate the button
 	table.insert(tmp, string.format(i18n.html['empty-row-fmt'], q.text_width[1], q.text_width[2], q.linfo1_pad, q.text_width[3], q.rinfo1_pad, q.text_width[4], q.text_width[5], q.text_width[6]))
 	return mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(table.concat(tmp), 'style=&quot;;* *', 'style=&quot;'), '\n| *style=&quot;&quot; *|', '\n|'), ' ?style=&quot;&quot;', ''), ' ?colspan=&quot;1&quot;', ''), '&lt;div class=&quot;RMsi&quot;&gt;&lt;/div&gt;', ''), 'class=&quot;RM%+', 'class=&quot;RM_'), '(class=&quot;[^&quot;]* RM)%+', '%1_')
 end
 
 local function getArgNums(prefix, args)
 	-- Copied from Module:Infobox on enwiki.
 	-- Returns a table containing the numbers of the arguments that exist
 	-- for the specified prefix. For example, if the prefix were 'data', and
 	-- 'data1', 'data2', and 'data5' existed, this would return {1, 2, 5}.
 	local nums = {}
 	for k, v in pairs(args) do
 		local num = tostring(k):match('^' .. prefix .. '([1-9]%d*)$')
 		if num then table.insert(nums, tonumber(num)) end
 	end
 	table.sort(nums)
 	return nums
 end
 
 local greatercontrast = require('Module:Color contrast')._greatercontrast
 local rgb_black = '#252525' -- class .mw-body in Mediawiki:Common.css
 
 p.infobox = makeInvokeFunction('_infobox')
 
 function p._infobox(args) -- Creates a pretty box.
 	args.map1, args.tw, args['map1-title'], args['map1-collapsible'], args['map1-collapse'] = args.map1 or args.map, args.tw or args['text-width'] or args['text width'], args['map1-title'] or args['map-title'], args['map1-collapsible'] or args['map-collapsible'], args['map1-collapse'] or args['map1-collapsed'] or args['map-collapse'] or args['map-collapsed']
 	local function map_prefix(x) return 'map'..x end
 	local mapnums, prefix = {}
 	if args[1] and args[1] ~= '' then
 		prefix = tonumber
 		for k, v in pairs(args) do
 			if type(k) == 'number' then table.insert(mapnums, k) end
 		end
 	else
 		prefix = map_prefix
 		mapnums = getArgNums('map', args)
 		table.sort(mapnums)
 	end
 	local classes = {}
 	args['title bg color'] = args['title bg color'] or args['title bg'] or args['title-bg'] or '#27404E'
 	args['title color'] = args['title color'] or args['title-color'] or greatercontrast{args['title bg color'], '#FFF', rgb_black}
 	args.legend = args.legend or ''
 	local navbar = require('Module:Navbar').navbar
 	local navtable = {}
 	if args.navbar then
 		navtable = {args.navbar, mini = i18n.text.navbar_mini, text = i18n.text.navbar_text}
 		args.navbar = navbar(navtable)
 	else
 		args.navbar = ''
 	end
 	local result = ''
 	if args.inline then result = result..'&amp;#32;\n' end
 	result = result..'{|'
 	args.collapse = args.collapse or args.collapsed
 	if args.inline or negative(args.collapsible) then
 		args.collapsible = '0'
 	else
 		table.insert(classes, 'collapsible')
 		if args.collapse then table.insert(classes, 'collapsed') end
 	end
 	args.float = args.float or 'right'
 	if args.float == 'right' then
 		args.margin = 'margin-left:1em;'
 	elseif args.float == 'left' then
 		args.margin = 'margin-right:1em;'
 	else
 		args.margin = ''
 	end
 	args.fontsize2 = 10000/88
 	if args.inline then
 		table.insert(classes, 'RMinline')
 		args.fontsize = 100
 	else
 		table.insert(classes, 'RMbox')
 		args.fontsize = 88 -- as above: CSS rule for .infobox in %
 	end
 	args.bg = args.bg or '#F9F9F9'
 	args.style = args.style or ''
 	result = result .. 'class=&quot;' .. table.concat(classes, ' ') .. '&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; style=&quot;float:' .. args.float .. ';clear:' .. args.float .. ';margin-top:0;margin-bottom:1em;' .. args.margin .. 'empty-cells:show;border-collapse:collapse;font-size:' .. args.fontsize .. '%;background:' .. args.bg .. ';' .. args.style .. '&quot;'
 	args.title = args.title or ''
 	if args.inline or args.title == 'no' or args.title == '0' then
 	else
 		result = result .. '\n! style=&quot;color:' .. args['title color'] .. ';background:' .. args['title bg color'] .. ';text-align:center;padding:5px&quot;|'
 		if args['navbar pos'] then
 			result = result .. '&lt;div&gt;'
 		else
 			if args.navbar ~= '' then
 				navtable.mini = true
 				navtable.brackets = true
 				navtable.style = 'float:left;margin-right:5px;white-space:nowrap'
 				navtable.fontstyle = 'font-size:'..args.fontsize2..'%;color:' .. args['title color']
 				args.navbar = navbar(navtable) .. '&lt;div style=&quot;margin-left:55px&quot;&gt;'
 			else
 				args.navbar = '&lt;div&gt;'
 			end
 			result = result .. args.navbar
 		end
 		result = result .. '&lt;div style=&quot;white-space:nowrap;'
 		if args.collapsible == '0' and (args['navbar pos'] or args.navbar == '&lt;div&gt;') then
 		else
 			result = result .. 'margin-right:55px;'
 			if args['navbar pos'] or args.navbar == '&lt;div&gt;' then
 				result = result .. 'margin-left:55px;'
 			end
 		end
 		result = result .. 'font-size:'..args.fontsize2..'%&quot;&gt;' .. args.title .. '&lt;/div&gt;&lt;/div&gt;'
 	end
 	args.top = args.top or args['on top']
 	if args.top then
 		result = result .. '\n|-\n|style=&quot;padding:0px 5px;text-align:center;'..(args.topstyle or '')..'&quot;|' .. args.top
 	end
 	result = result .. '\n|-\n|style=&quot;line-height:normal;padding:4px 5px&quot;|'
 	if args.navbar ~= '' and args['navbar pos'] == '1' then
 		if not positive(args['navbar long']) and not negative(args['navbar mini']) then navtable.mini = true; args.navbar = navbar(navtable) end
 		result = result .. '&lt;div style=&quot;float:left;padding-right:5px&quot;&gt;' .. args.navbar .. '&lt;/div&gt;'
 	end
 	args.legend2 = mw.ustring.lower(args.legend)
 	if args.legend2 ~= 'no' and args.legend2 ~= '0' then
 		args.legend = i18n.text.legend[args.legend2] or ((args.legend2 ~= '') and ('[['..args.legend) or i18n.text.legend.default)
 		args.legend = args.legend .. '|' .. (args['legend alt'] or i18n.text.legend_text) .. ']]'
 		result = result .. '&lt;div class=&quot;selfreference noprint&quot; style=&quot;text-align:right;font-size:97%&quot;&gt;' .. args.legend .. '&lt;/div&gt;'
 	end
 	if args.inline then args.padding2 = '0px' else args.padding2 = '0px 6px' end
 	for k, v in ipairs(mapnums) do
 		if not mapnums[k + 1] then
 			if not args.inline then args.padding2 = '0px 6px 6px' end
 		end
 		args.ending = ''
 		if args['map'..v..'-title'] then
 			args.header_margin = '0'
 			if k == 1 then args.border_header = 'border-bottom: 5px solid '..args.bg..';' else args.border_header = 'border-top: 5px solid '..args.bg..';border-bottom: 5px solid '..args.bg..';' end
 			if positive(args['map'..v..'-collapsible']) then
 				args.header_margin = '0 55px'
 				args.ending = '\n|}'
 				if positive(args['map'..v..'-collapse']) or positive(args['map'..v..'-collapsed']) then args.map_collapsed = ' mw-collapsed autocollapse' else args.map_collapsed = '' end
 				result = result..'\n|-\n|\n{|class=&quot;mw-collapsible'..args.map_collapsed..'&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; style=&quot;display:table;min-width:100%;margin:0 auto&quot;'
 			end
 			if args.inline then args.header_style2 = ' style=&quot;line-height:normal&quot;' else args.header_style2 = '' end
 			result = result..'\n|-'..args.header_style2..'\n!style=&quot;'..args.border_header..'padding:3px 5px;text-align:center;vertical-align:middle;color:'..rgb_black..';background:#EEEEEE&quot; | &lt;div style=&quot;margin:'..args.header_margin..';font-size:'..10000/args.fontsize..'%&quot;&gt;'..args['map'..v..'-title']..'&lt;/div&gt;'
 			args.border_top = ''
 		else
 			if k == 1 then args.border_top = '' else args.border_top = 'border-top: 5px solid '..args.bg..';' end
 		end
 		result = result .. '\n|-\n|style=&quot;'..args.border_top..'padding:' .. args.padding2 .. '&quot;|\n{|class=&quot;nogrid routemap&quot; style=&quot;font-size:'..(args.fontsize2 * .95)..'%&quot;\n'..localroute(args[prefix(v)], (args['tw'..v] or args['text-width'..v] or args['text width'..v] or args.tw or ''), args.bg, args.process)..'\n|}'..args.ending
 	end
 	args.bottom = args.bottom or args.footnote
 	if args.bottom then
 		if args.inline then args.padding2 = '6px' else args.padding2 = '0px' end
 		result = result .. '\n|-\n|style=&quot;line-height:normal;text-align:right;padding:' .. args.padding2 .. ' 5px 5px;'..(args.bottomstyle or args.footnotestyle or '')..'&quot;|' .. args.bottom
 		if string.find(args.bottom, '&amp;action=edit') then result = result .. (i18n['error-categories']['separate-navbar'] or i18n['error-categories'].default) end
 	end
 	if args.navbar ~= '' and args['navbar pos'] == '2' then
 		if negative(args['navbar long']) or positive(args['navbar mini']) then navtable.mini = true; args.navbar = navbar(navtable) end
 		if args.inline and not args.bottom then args.padding2 = '6px' else args.padding2 = '0px' end
 		result = result .. '\n|-\n|style=&quot;line-height:normal;padding:' .. args.padding2 .. ' 5px 3px;text-align:center&quot;|' .. args.navbar
 	end
 	return result .. '\n|}'
 end
 
 local function base(t1,t2,link,stn,italic,it,it2,bold,align,style,bg1,bg2,line,fs1,fs2,lh,v1,swap,inp,bs)
 --Creates an inline table with two rows of text. Can be used in any Routemap text cell.
 --Implemented in the BSsplit, BSto, BSsrws and BScvt templates.
 	if not align then
 		if bs == 'cvt' then
 			align = 'right'
 		else
 			align = 'inherit'
 		end
 	end
 	style = style or ''
 	local result = '&amp;#32;&lt;table cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; class=&quot;RMsplit&quot; style=&quot;text-align:'..align
 	if italic or it == 'all' then result = result..';font-style:italic' end
 	if bold then result = result..';font-weight:bold' end
 	local rowstart = '&lt;tr&gt;&lt;td style=&quot;text-align:inherit;padding:0;line-height:'
 	result = result..';'..style..'&quot;&gt;'..rowstart..lh
 	if line then result = result..';border-bottom:1px solid gray' end
 	local bgpad = ';padding-left:.5em;padding-right:.5em'
 	local function bgtext(v)
 		return ';color:'..greatercontrast{v, '#FFF', rgb_black}
 	end
 	if bg1 then
 		result = result..bgpad..bgtext(bg1)..';background:'..bg1
 	elseif bg2 then
 		result = result..bgpad
 	end
 	if fs1 then result = result..';font-size:'..fs1 end
 	result = result..'&quot;&gt;'
 	if not t1 or string.find(t1, '^%s*$') then
 		if not t2 then t2 = '' end
 		if string.find(t2, '&lt;br ?/?&gt;') == nil then t1 = '&amp;nbsp;' end
 	end
 	if not t2 or string.find(t2, '^%s*$') then
 		if not t1 then t1 = '' end
 		if string.find(t1, '&lt;br ?/?&gt;') == nil then t2 = '&amp;nbsp;' end
 	end
 	if bs == 'srws' then
 		if stn then
 			link = t1..' '..t2..' '..stn
 		else
 			link = t1..' '..t2..' railway station'
 		end
 	elseif bs == 'cvt' then
 		local split, floor, outp, v2, mult = mw.text.split, math.floor
 		local function trim(x)
 			return string.gsub(x, '%s', '')
 		end
 		local cvt = { -- conversion values
 			['mi'] = 1.609344,
 			['ch'] = 20.1168,
 			['mi;ch'] = 80,
 			['m'] = 1 / .9144,
 			['yd'] = .9144,
 			['ft'] = .3048,
 		}
 		local sf = { -- 10 ^ floor(log10(cvt[inp]) + .5); or 10 ^ floor(log10(cvt[inps[1]] * cvt[inp]) + .5) for dual-unit inputs. this corrects the accuracy of result so that it usually has same significant figures
 			['mi'] = 1,
 			['ch'] = 10,
 			['mi;ch'] = .01,
 			['m'] = 1,
 			['yd'] = 1,
 			['ft'] = .1,
 		}
 		if not inp then inp = 'mi' end
 		inp = string.lower(trim(inp))
 		if inp == 'ch' or inp == 'yd' or inp == 'ft' then -- output unit
 			outp = 'm'
 		elseif inp == 'm' then
 			outp = 'yd'
 		else
 			if inp ~= 'mi;ch' then inp = 'mi' end
 			outp = 'km'
 		end
 		local pos = string.find(v1, '%.')
 		if not pos then
 			mult = 1
 		else
 			mult = 10 ^ (string.len(v1) - pos)
 		end
 		local inps = string.find(inp, ';')
 		if inps then
 			inps = split(inp, ';')
 			if swap then
 				t1 = v1..'&amp;nbsp;'..outp
 				v1 = tonumber(v1)
 				t2 = floor(v1 / cvt[inps[1]])..'&amp;nbsp;'..inps[1]..'&amp;nbsp;'..floor(v1 % cvt[inps[1]] / cvt[inps[1]] * cvt[inp] * mult * sf[inp] + .5) / mult / sf[inp]..'&amp;nbsp;'..inps[2]
 			else
 				v1 = split(trim(v1), ';')
 				t1 = v1[1]..'&amp;nbsp;'..inps[1]..'&amp;nbsp;'..v1[2]..'&amp;nbsp;'..inps[2]
 				t2 = floor((tonumber(v1[1]) * cvt[inps[1]] + tonumber(v1[2]) * cvt[inps[1]] / cvt[inp]) * mult / sf[inp] + .5) / mult * sf[inp]..'&amp;nbsp;'..outp
 			end
 		else
 			if swap then
 				v2 = floor(tonumber(v1) / cvt[inp] * mult * sf[inp] + .5) / mult / sf[inp]
 				inp, outp = outp, inp
 			else
 				v2 = floor(tonumber(v1) * cvt[inp] * mult / sf[inp] + .5) / mult * sf[inp]
 			end
 			t1 = v1..'&amp;nbsp;'..inp
 			t2 = v2..'&amp;nbsp;'..outp
 		end
 	end
 	if t1 then
 		if link then
 			result = result..'[['..link..'|'..t1..']]'
 		else
 			result = result..t1
 		end
 	end
 	local rowend = '&lt;/td&gt;&lt;/tr&gt;'
 	result = result..rowend..rowstart..lh
 	if bg2 then
 		result = result..bgpad..bgtext(bg2)..';background:'..bg2
 	elseif bg1 then
 		result = result..bgpad
 	end
 	if fs2 then result = result..';font-size:'..fs2 end
 	if (it ~= 'off' and bs == 'to') or it2 == 'italic' then
 		result = result..';font-style:italic'
 	elseif it == 'off' then
 		result = result..';font-style:normal'
 	end
 	result = result..'&quot;&gt;'
 	if t2 then
 		if link then
 			result = result..'[['..link..'|'..t2..']]'
 		else
 			result = result..t2
 		end
 	end
 	result = result..rowend..'&lt;/table&gt;&amp;#32;'
 	if bs == 'to' or bs == 'srws' then
 		if t1 == '&amp;nbsp;' or t2 == '&amp;nbsp;' then result = result..(i18n['error-categories']['missing-text-values'] or i18n['error-categories'].default) end
 	end
 	if string.find(t1, '&lt;br ?/?&gt;') ~= nil or string.find(t2, '&lt;br ?/?&gt;') ~= nil then result = result..(i18n['error-categories']['br-tags'] or i18n['error-categories'].default) end
 	if bs == 'split' then
 		if link and t1 and t2 then
 			if string.find(link, '^'..t1..' '..t2..' ') then result = result..(i18n['error-categories']['srws'] or i18n['error-categories'].default) end
 		end
 	end
 	return result
 end
 
 p.BSto = makeInvokeFunction('_BSto')
 
 function p._BSto(args)
 	args[3] = args[3] or args.L
 	args[4] = args[4] or args.it or args.i
 	args[5] = args[5] or args.b
 	return base(args[1],args[2],args[3],nil,nil,args[4],nil,args[5],args.align,args.style,args.bg1,args.bg2,args.line,'105%','inherit','.9',nil,nil,nil,'to')
 end
 
 p.BSsplit = makeInvokeFunction('_BSsplit')
 
 function p._BSsplit(args)
 	args[3] = args[3] or args.L
 	args[4] = args[4] or args.it or args.i
 	args[5] = args[5] or args.b
 	return base(args[1],args[2],args[3],nil,args[4],nil,nil,args[5],args.align,args.style,args.bg1,args.bg2,args.line,'inherit','inherit','.9',nil,nil,nil,'split')
 end
 
 p.BSsrws = makeInvokeFunction('_BSsrws')
 
 function p._BSsrws(args)
 	args[3] = args[3] or args.S
 	args[4] = args[4] or args.it or args.i
 	args[5] = args[5] or args.b
 	return base(args[1],args[2],nil,args[3],args[4],nil,nil,args[5],args.align,args.style,args.bg1,args.bg2,args.line,'inherit','inherit','.9',nil,nil,nil,'srws')
 end
 
 p.BScvt = makeInvokeFunction('_BScvt')
 
 function p._BScvt(args)
 	return base(nil,nil,nil,nil,nil,nil,args.alt,nil,args.align,args.style,args.bg1,args.bg2,args.line,'inherit','inherit','.9',args[1],args[2],args['in'],'cvt')
 end
 
 p.rmri = makeInvokeFunction('_rmri')
 
 function p._rmri(args)--[[
 
 Displays a blue arrow pointing in one of eight directions.
 Implemented in the RoutemapRouteIcon template.
 
 ]]
 	local directions, result = {
 	['Up']         = {'u', 'up'},
 	['Down']       = {'d', 'dn', 'down'},
 	['Left']       = {'l', 'left'},
 	['Right']      = {'r', 'right'},
 	['UpperRight'] = {'ur', 'ne', 'c1', 'upperright'},
 	['LowerRight'] = {'lr', 'se', 'c2', 'lowerright'},
 	['LowerLeft']  = {'ll', 'sw', 'c3', 'lowerleft'},
 	['UpperLeft']  = {'ul', 'nw', 'c4', 'upperleft'},
 	}
 	local d, link, size = args[1], args[2], args[3]
 	if not d then
 		if args[4] ~= ' ' then d, link, size = args[2], args[3], 's' end
 	end
 	for k, v in pairs(directions) do
 		for _, name in ipairs(v) do
 			if d:lower() == name then
 				if size == 's' then
 					size = '7'
 				elseif not size then
 					size = '10'
 				end
 				if not link then link = '' end
 				result = '[[File:Arrow Blue '..k..' 001.svg|'..size..'px|alt='..k..' arrow|link='..link..']]'
 			end
 		end
 	end
 	if not result then
 		return '&lt;span style=&quot;color:#f00&quot;&gt;Invalid [[Template:RoutemapRoute]] arrow value &quot;&lt;span style=&quot;font-style:italic&quot;&gt;'..d..'&lt;/span&gt;&quot;.&lt;/span&gt;'..(i18n['error-categories']['rmr-error'] or i18n['error-categories'].default)
 	else
 		return result
 	end
 end
 
 p.rmr = makeInvokeFunction('_rmr')
 
 function p._rmr(args)--[[
 
 Displays text between two blue arrows (or to the left/right side of one).
 Text can be split with an en dash if entered in both first and second numbered parameters.
 Implemented in the RoutemapRoute template.
 
 ]]
 	args.l = args.l or args.Licon or args.licon or args.L
 	args.r = args.r or args.Ricon or args.ricon or args.R
 	if args.l then args.l = p._rmri{args.l,args.llink,(args.lsize or args.size),' '}..'&amp;nbsp;' else args.l = '' end
 	if args.r then args.r = '&amp;nbsp;'..p._rmri{args.r,args.rlink,(args.rsize or args.size),' '} else args.r = '' end
 	if args[1] then
 		if args[2] then args[1] = args[1]..'&amp;nbsp;–&amp;nbsp;'..args[2] end
 	else
 		args[1] = args[2] or ''
 	end
 	if args[1] == '' or args.enclosed == 'no' then
 		args.b1, args.b2 = '', ''
 	else
 		args.b1, args.b2 = '(', ')'
 	end
 	return args.b1..args.l..args[1]..args.r..args.b2
 end
 
 function p.BSrow(frame)
 	local args = getArgs(frame, {
 		parentOnly = true,
 		removeBlanks = false,
 	})
 	return p._BSrow(args)
 end
 
 function p._BSrow(args)--[[
 
 Creates Routemap syntax for a diagram row based on parameters.
 Implemented in the RDTr template.
 
 ]]
 	args.n = tonumber(args.n or '')
 	if not args.n then
 		local icontotal = getArgNums('', args)
 		table.sort(icontotal)
 		args.n = icontotal[#icontotal] or 1
 	end
 	local count, icons, overlaps, overlapCalc = tonumber(args['$count']) or 1, {}, {}, math.log10(args.n)
 	local text = (args.text and '*') or ''
 	if overlapCalc == math.floor(overlapCalc) then overlapCalc = 10^(overlapCalc) else overlapCalc = 10^(math.floor(overlapCalc) + 1) end
 	while count &lt;= args.n do
 		local cellparams, overlapn = {}, (string.match(count/overlapCalc, '%.(0+)') or '')..count
 		table.insert(icons, (text..(args[count] or '')))
 		if args['O'..overlapn] then
 			local iconparams, overlapparams, overlapt = {}, {}, {}
 			for k, v in pairs({bg = (args['O'..overlapn..'0-bg'] or args['O'..overlapn..'0-background'] or args['O'..overlapn..'0-bgcolor']), color = (args['O'..overlapn..'0-color'] or args['O'..overlapn..'0-colour']), b = (args['O'..overlapn..'0-b'] or args['O'..overlapn..'0-bold']), i = (args['O'..overlapn..'0-i'] or args['O'..overlapn..'0-it'] or args['O'..overlapn..'0-italic']), align = args['O'..overlapn..'0-align'], fontsize = args['O'..overlapn..'0-fontsize'], abbr = args['O'..overlapn..'0-abbr'], style = args['O'..overlapn..'0-style']}) do
 				if v then table.insert(iconparams, k..'='..v) end
 			end
 			if iconparams[1] then icons[count] = icons[count]..'__'..table.concat(iconparams, ',') end
 			for k, v in pairs({bg = (args['O'..overlapn..'-bg'] or args['O'..overlapn..'-background'] or args['O'..overlapn..'-bgcolor']), color = (args['O'..overlapn..'-color'] or args['O'..overlapn..'-colour']), b = (args['O'..overlapn..'-b'] or args['O'..overlapn..'-bold']), i = (args['O'..overlapn..'-i'] or args['O'..overlapn..'-it'] or args['O'..overlapn..'-italic']), align = args['O'..overlapn..'-align'], fontsize = args['O'..overlapn..'-fontsize'], abbr = args['O'..overlapn..'-abbr'], style = args['O'..overlapn..'-style']}) do
 				if v then table.insert(overlapparams, k..'='..v) end
 			end
 			if overlapparams[1] then args['O'..overlapn] = args['O'..overlapn]..'__'..table.concat(overlapparams, ',') end
 			overlaps = getArgNums('O'..overlapn, args) or {}
 			table.sort(overlaps)
 			if overlaps[1] then
 				for i, v in ipairs(overlaps) do
 					overlapparams = {}
 					for k, v2 in pairs({bg = (args['O'..overlapn..v..'-bg'] or args['O'..overlapn..v..'-background'] or args['O'..overlapn..v..'-bgcolor']), color = (args['O'..overlapn..v..'-color'] or args['O'..overlapn..v..'-colour']), b = (args['O'..overlapn..v..'-b'] or args['O'..overlapn..v..'-bold']), i = (args['O'..overlapn..v..'-i'] or args['O'..overlapn..v..'-it'] or args['O'..overlapn..v..'-italic']), align = args['O'..overlapn..v..'-align'], fontsize = args['O'..overlapn..v..'-fontsize'], abbr = args['O'..overlapn..v..'-abbr'], style = args['O'..overlapn..v..'-style']}) do
 						if v2 then table.insert(overlapparams, k..'='..v2) end
 					end
 					if overlapparams[1] then args['O'..overlapn..v] = args['O'..overlapn..v]..'__'..table.concat(overlapparams, ',') end
 					table.insert(overlapt, text..args['O'..overlapn..v])
 				end
 				overlaps = '!~'..text..args['O'..overlapn]..'!~'..table.concat(overlapt, '!~')
 			else
 				overlaps = '!~'..text..args['O'..overlapn]
 			end
 			icons[count] = icons[count]..overlaps
 		else
 			if args[count..'-abbr'] then table.insert(cellparams, 'abbr='..args[count..'-abbr']) end
 		end
 		if args[count..'-link'] then icons[count] = icons[count]..'!@'..args[count..'-link'] end
 		for k, v in pairs({bg = (args[count..'-bg'] or args[count..'-background'] or args[count..'-bgcolor']), color = (args[count..'-color'] or args[count..'-colour']), b = (args[count..'-b'] or args[count..'-bold']), i = (args[count..'-i'] or args[count..'-it'] or args[count..'-italic']), align = args[count..'-align'], fontsize = args[count..'-fontsize'], style = args[count..'-style']}) do
 			if v then table.insert(cellparams, k..'='..v) end
 		end
 		if cellparams[1] then icons[count] = icons[count]..'!_'..table.concat(cellparams, ',') end
 		count = count + 1
 	end
 	local row, rowparams, left, right = table.concat(icons, '\\'), {}
 	for k, v in pairs({bg = (args.bg or args.background or args.bgcolor), color = (args.color or args.colour), b = (args.b or args.bold), i = (args.i or args.it or args.italic), align = args.align, fontsize = args.fontsize, style = args.style}) do
 		if v then table.insert(rowparams, k..'='..v) end
 	end
 	if rowparams[1] then args.R5 = table.concat(rowparams, ',') end
 	for i, v in ipairs({'R1', 'R2', 'R3', 'R4', 'R5', 'L1', 'L2', 'L3', 'L4'}) do
 		if not args[v] or string.find(args[v], '^%s*$') then args[v] = nil end
 	end
 	if args.R5 then
 		right = {(args.R1 or ' '), (args.R2 or ' '), (args.R3 or ' '), (args.R4 or ' '), args.R5}
 	elseif args.R4 then
 		right = {(args.R1 or ' '), (args.R2 or ' '), (args.R3 or ' '), args.R4}
 	elseif args.R3 then
 		right = {(args.R1 or ' '), (args.R2 or ' '), args.R3}
 	elseif args.R1 then
 		right = {args.R1, (args.R2 or '')}
 	elseif args.R2 then
 		right = {args.R2}
 	end
 	if right then row = row..'~~'..table.concat(right, '~~') end
 	if args.L4 then
 		left = {args.L4, (args.L3 or ' '), (args.L2 or ' '), (args.L1 or '')}
 	elseif args.L3 then
 		left = {args.L3, (args.L2 or ' '), (args.L1 or '')}
 	elseif args.L1 then
 		left = {(args.L2 or ''), args.L1}
 	elseif args.L2 then
 		left = {args.L2}
 	end
 	if left then row = table.concat(left, '~~')..'! !'..row end
 	return row
 end
 
 function p.BSrow_lite(frame)
 	local args = getArgs(frame, {
 		removeBlanks = false,
 	})
 	return p._BSrow_lite(args)
 end
 
 function p._BSrow_lite(args)--[[
 
 Creates Routemap syntax for a diagram row based on parameters.
 Intended to be used to substitute legacy templates.
 Note that for compatibility the link and sidebar parameter names are different.
 
 ]]
 	args.n = tonumber(args.n or '')
 	if not args.n then
 		local icontotal = getArgNums('', args)
 		table.sort(icontotal)
 		args.n = icontotal[#icontotal] or 1
 	end
 	local count, icons, overlaps, overlapCalc = tonumber(args['$count']) or 1, {}, {}, math.log10(args.n)
 	local text = (args.text and '*') or ''
 	if overlapCalc == math.floor(overlapCalc) then overlapCalc = 10^(overlapCalc) else overlapCalc = 10^(math.floor(overlapCalc) + 1) end
 	while count &lt;= args.n do
 		local cellparams, overlapn = {}, (string.match(count/overlapCalc, '%.(0+)') or '')..count
 		table.insert(icons, (text..(args[count] or '')))
 		if args['O'..overlapn] then
 			local overlapt = {}
 			overlaps = getArgNums('O'..overlapn, args) or {}
 			table.sort(overlaps)
 			if overlaps[1] then
 				for i, v in ipairs(overlaps) do table.insert(overlapt, text..args['O'..overlapn..v]) end
 				overlaps = '!~'..text..args['O'..overlapn]..'!~'..table.concat(overlapt, '!~')
 			else
 				overlaps = '!~'..text..args['O'..overlapn]
 			end
 			icons[count] = icons[count]..overlaps
 		end
 		if args['L'..count] then icons[count] = icons[count]..'!@'..args['L'..count] end
 		count = count + 1
 	end
 	local row, rowparams, left, right = table.concat(icons, '\\'), {}
 	for k, v in pairs({bg = (args.bg or args.background or args.bgcolor), style = args.style}) do
 		if v then table.insert(rowparams, k..'='..v) end
 	end
 	if rowparams[1] then args.r5 = table.concat(rowparams, ',') end
 	for i, v in ipairs({'r1', 'r2', 'r3', 'r4', 'r5', 'l1', 'l2', 'l3', 'l4'}) do
 		if not args[v] or string.find(args[v], '^%s*$') then args[v] = nil end
 	end
 	if args.r5 then
 		right = {(args.r1 or ' '), (args.r2 or ' '), (args.r3 or ' '), (args.r4 or ' '), args.r5}
 	elseif args.r4 then
 		right = {(args.r1 or ' '), (args.r2 or ' '), (args.r3 or ' '), args.r4}
 	elseif args.r3 then
 		right = {(args.r1 or ' '), (args.r2 or ' '), args.r3}
 	elseif args.r1 then
 		right = {args.r1, (args.r2 or '')}
 	elseif args.r2 then
 		right = {args.r2}
 	end
 	if right then row = row..'~~'..table.concat(right, '~~') end
 	if args.l4 then
 		left = {args.l4, (args.l3 or ' '), (args.l2 or ' '), (args.l1 or '')}
 	elseif args.l3 then
 		left = {args.l3, (args.l2 or ' '), (args.l1 or '')}
 	elseif args.l1 then
 		left = {(args.l2 or ''), args.l1}
 	elseif args.l2 then
 		left = {args.l2}
 	end
 	if left then row = table.concat(left, '~~')..'! !'..row end
 	return row
 end
 
 local function pre_block(text)
 	-- Pre tags returned by a module do not act like wikitext &lt;pre&gt;...&lt;/pre&gt;.
 	return '&lt;pre&gt;' ..
 		mw.text.nowiki(text) ..
 		(text:sub(-1) == '\n' and '' or '\n') ..
 		'&lt;/pre&gt;\n'
 end
 
 function p.convertbs(frame)--[[
 
 Converts a legacy route diagram into Routemap format.
 Code to be used is displayed in preview mode or after saving the page, above the original code.
 
 {{#invoke:Routemap|convertbs|&lt;nowiki&gt;
 (Original diagram)
 &lt;/nowiki&gt;}}
 
 ]]
 	local org = mw.text.unstripNoWiki(frame.args[1] or 'Paste legacy RDT markup between nowiki tags')
 	local res = org
 	res = string.gsub(res, '{{[Bb][Ss]%-?map', '{{Routemap') -- &quot;%-&quot; is an escape for hyphen which is used as &quot;between&quot; in pattern.
 	res = string.gsub(res, '{|%s?{{[Rr]ailway line header}}', '{{Routemap')
 	res = string.gsub(res, '{{[Bb][Ss]%-header%d?|', '{{safesubst:BS-header/safesubst|') -- &quot;%d?&quot; means optional digit in case use of variant template like BS-header3.
 	res = string.gsub(res, '{{[Bb][Ss]%-table%d?}}', '|map =')
 	res = string.gsub(res, '{{[Bb][Ss](%d?)(%d?)|', '{{safesubst:BS%1%2/safesubst|')
 	res = string.gsub(res, '{{[Bb][Ss](%d?)(%d?)%-replace|', '!replace{{safesubst:BS%1%2/safesubst|')
 	res = string.gsub(res, '{{[Bb][Ss](%d?)(%d?)%-startCollapsible|', '-startCollapsible-collapsed\n{{safesubst:BS%1%2/safesubst|')
 	res = string.gsub(res, '{{[Bb][Ss](%d?)(%d?)%-sc|', '-startCollapsible-collapsed\n{{safesubst:BS%1%2/safesubst|')
 	res = string.gsub(res, '{{[Bb][Ss](%d?)(%d?)%text|', '{{safesubst:BS%1%2text/safesubst|')
 	res = string.gsub(res, '{{[Bb][Ss](%d?)(%d?)%-2|', '{{safesubst:BS%1%2-2/safesubst|')
 	res = string.gsub(res, '{{[Bb][Ss](%d?)(%d?)%-2replace|', '!replace{{safesubst:BS%1%2-2|')
 	res = string.gsub(res, '{{[Bb][Ss](%d?)(%d?)%-2sc|', '-startCollapsible-collapsed\n{{safesubst:BS%1%2-2|')
 	res = string.gsub(res, '{{!}}}', '-endCollapsible-')
 	res = string.gsub(res, '{{[Ee]nd}}', '-endCollapsible-')
 	res = string.gsub(res, '|}\n?|}', '}}') -- Replace ending of Railway line header map setup.
 	res = string.gsub(res, '{{[Bb][Ss]%-colspan}}\n{{safesubst', '{{safesubst') -- BS-colspan is unnecessary and would cause error in Routemap.
 	res = string.gsub(res, '{{[Bb][Ss]%-colspan}}\n%-%-%-%-', '-colspan-2\n----')
 	res = string.gsub(res, '&amp;lt;', '&lt;')
 	res = string.gsub(res, '&amp;gt;', '&gt;')
 	if string.find(res, '!replace') or string.find(res, '|%s*bg%s*=') then
 		local restable = mw.text.split(res, '\n')
 		for i, v in ipairs(restable) do
 			if string.find(v, '!replace') then
 				restable[i] = string.gsub(restable[i], '!replace', '')
 				restable[i-2] = string.gsub(restable[i-2], 'collapsed', 'collapsed-replace')
 			end
 			if (string.find(v, '|%s*bg%s*=%s*#?[a-zA-Z0-9]+') or string.find(v, '|%s*bg%s*=%s*#?{{[^{}]+}}%s*|') or string.find(v, '|%s*bg%s*=%s*#?{{[^{}]+}}%s*}}')) and string.find(restable[i-1], '^-startCollapsible') then
 				local bg = string.match(v, '|%s*bg%s*=%s*(#?[a-zA-Z0-9]+)') or string.find(v, '|%s*bg%s*=%s*(#?{{[^{}]+}})%s*|') or string.find(v, '|%s*bg%s*=%s*(#?{{[^{}]+}})%s*}}')
 				restable[i] = string.gsub(restable[i], '|%s*bg%s*=%s*'..bg, '')
 				restable[i-1] = string.gsub(restable[i-1], '%-?$', '--bg=')..bg
 				if string.find(restable[i+1], '!replace') then
 					restable[i+1] = string.gsub(restable[i+1], '!replace', '')
 					restable[i-1] = string.gsub(restable[i-1], 'collapsed%-', 'collapsed-replace')
 					if (string.find(restable[i+1], '|%s*bg%s*=%s*#?[a-zA-Z0-9]+') or string.find(restable[i+1], '|%s*bg%s*=%s*#?{{[^{}]+}}%s*|') or string.find(restable[i+1], '|%s*bg%s*=%s*#?{{[^{}]+}}%s*}}')) then
 						local bg2 = string.match(restable[i+1], '|%s*bg%s*=%s*(#?[a-zA-Z0-9]+)') or string.find(restable[i+1], '|%s*bg%s*=%s*(#?{{[^{}]+}})%s*|') or string.find(restable[i+1], '|%s*bg%s*=%s*(#?{{[^{}]+}})%s*}}')
 						if bg2 == bg then restable[i+1] = string.gsub(restable[i], '|%s*bg%s*=%s*'..bg2, '') end
 					end
 				end
 			end
 		end
 		res = table.concat(restable, '\n')
 	end
 	return &quot;\n'''Safe substitution''':\n&quot; .. pre_block(res) .. &quot;'''''Original''''':\n&quot; .. pre_block(org)
 end