Module:BSicon/sandbox/T

From Wikimedia Commons, the free media repository
Jump to navigation Jump to search
Lua
CodeDiscussionEditHistoryLinksLink count Subpages:DocumentationTestsResultsSandboxLive code All modules

Documentation for this module may be created at Module:BSicon/sandbox/T/doc

Code

local p = {}

-- local test = {}

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

p.category = makeInvokeFunction('_category')

function p._category(args)
	local title, categories, color, result, tmp = mw.title.getCurrentTitle(), '', {''}, ''
	if title.namespace ~= 14 then return error("This template should only be used on category pages") end
	title = title.text
	title = mw.ustring.gsub(title, '%+', '#')
	title = mw.ustring.gsub(title, '%-', '_')
	local title2 = mw.clone(title)
	local rgb, contrast = require('Module:Routemap')._RGBbyCode, require('Module:Color contrast')._ratio
	local function colortext(x)
		x = tostring(x) or 'BE2D2C'
		return '<span style="background-color: #'..x..'; font-family: monospace,monospace; color: '..((contrast{x, 'FFF'} < 4) and 'inherit' or '#FFF')..'; padding: 0.3em 0.3em 0.1em 0.3em; border: 1px solid '..((contrast{x, 'FFF'} < 4) and 'black' or 'white')..'">\'\'\'#'..x..'\'\'\'</span>'
	end
	local function hex(x, ex)
		x = rgb{mw.ustring.gsub((ex and 'ex_' or '')..(tostring(x) or ''), '^ex_([ufg]?)$', '%1ex', 1)}
		return colortext(x)
	end
	local roots = {
		BHF = 'stations and stops/',
		HST = 'stations and stops/',
		DST = 'stations and stops/',
		BST = 'stations and stops/',
		INT = 'stations and stops/',
		ACC = 'stations and stops/',
		INTACC = 'stations and stops/',
		HSTACC = 'stations and stops/',
		suburban = 'stations and stops/',
		SBHF = 'stations and stops/',
		SHST = 'stations and stops/',
		['S#BHF'] = 'stations and stops/',
		['S#HST'] = 'stations and stops/',
		HSTACC = 'stations and stops/',
		RD = 'generic road/',
		RP1 = 'generic road/',
		RP2 = 'generic road/',
		RP4 = 'generic road/',
		wye = 'junction/',
		formations = 'legende/',
		['straight#curve'] = 'curve/',
		['straight#junction'] = 'junction/',
		['straight#corner'] = 'corner/',
	}
	local compounds = {
		['road–rail'] = 'railway/road',
		INTACC = 'INT/ACC',
		HSTACC = 'HST/ACC',
		['S#BHF'] = 'suburban/BHF',
		['S#HST'] = 'suburban/HST',
		SBHF = 'suburban/BHF',
		SHST = 'suburban/HST',
		['curve#corner'] = 'curve/corner',
		['crossing#corner'] = 'crossing/corner',
		['crossing#junction'] = 'crossing/junction',
		['junction#corner'] = 'junction/corner',
	}
	local used_roots = {}
	local matches = {}
	local used_compounds = {}
	title = title..'/'
	for k, v in pairs(roots) do
		if mw.ustring.match(title, '/'..k..'/') then
			title = mw.ustring.gsub(title, k, v..k)
			table.insert(used_roots, k)
			used_roots[k] = true
		end
	end
	title = mw.ustring.gsub(title, '/$', '')
	for k, v in pairs(compounds) do
		if mw.ustring.match(title, k) then
			title = mw.ustring.gsub(title, k, v)
			table.insert(matches, k)
			table.insert(used_compounds, v)
		end
	end
	local legende_color
	if mw.ustring.match(title, 'road–rail') then title = mw.ustring.gsub(title, 'road–rail', 'railway/road') end
	if mw.ustring.match(title, 'water') then
		result = result..'\n\124-\n\124* Water color: ||'..colortext('007CC3')
	end
	if mw.ustring.match(title, 'tunnel to') or mw.ustring.match(title, 'portal') or mw.ustring.match(title, 'elevated') or mw.ustring.match(title, 'bridge') or mw.ustring.match(title, 'crossing') or mw.ustring.match(title, '/tower') or mw.ustring.match(title, 'cutting') or mw.ustring.match(title, 'embankment') then
		result = result..'\n|-\n|• Structure color: ||'..colortext('80A080')
		legende_color = true
	end
	if mw.ustring.match(title, 'line endings') then
		result = result..'\n|-\n|• Line ending colors: ||'..colortext('000')..' (open) and '..colortext('AAA')..' (closed)'
		legende_color = true
	end
	if mw.ustring.match(title, 'platform') then
		result = result..'\n|-\n|• Platform colors: ||'..colortext('888')..' (open) and '..colortext('CCC')..' (closed)'
		legende_color = true
	end
	if mw.ustring.match(title, 'mask') then
		result = result..'\n|-\n|• Mask color: ||'..colortext('F9F9F9')
	end
	if mw.ustring.match(title, 'INT') then
		result = result..'\n|-\n|• INT colors: ||'..colortext('000')..' (open) and '..colortext('AAA')..' (closed)'
		legende_color = true
	end
	if mw.ustring.match(title, 'ACC') then
		result = result..'\n|-\n|• ACC colors: ||'..colortext('034EA2')..' (open) and '..colortext('6592C5')..' (closed)'
		legende_color = true
	end
	if mw.ustring.match(title, 'CPIC') then
		result = result..'\n|-\n|• Cross-platform interchange colors: ||'..colortext('000')..' and '..colortext('B3B3B3')
	end
	if mw.ustring.match(title, 'S#?BHF') or mw.ustring.match(title, 'S#?HST') or mw.ustring.match(title, 'suburban') then
		result = result..'\n|-\n|• S-Bahn colors: ||'..colortext('006E34')..' (open) and '..colortext('5ABF89')..' (closed)'
		legende_color = true
	end
	if mw.ustring.match(title, 'DST') or mw.ustring.match(title, 'BST') or mw.ustring.match(title, 'ACC') or mw.ustring.match(title, 'INT') or mw.ustring.match(title, 'S#?BHF') or mw.ustring.match(title, 'S#?HST') then
		result = result..'\n|-\n|• Fill color: ||'..colortext('FFF')
	end
	legende_color = legende_color and mw.ustring.match(title, 'legende')
	title = mw.text.split(title, '/')
	if title[1] ~= 'BSicon' then return '' end
	if title[2] == 'railway' and (((title[3] or 'road') ~= 'road') or title[4]) and (not used_roots['formations']) and (not legende_color) then
		if mw.ustring.match(((title[3] ~= 'road') and title[3] or title[4]), '^set ') then color[1] = mw.ustring.match(((title[3] ~= 'road') and title[3] or title[4]), '^set (.+)$') or '' end
		if color[1] == 'mixed' then
			color = {'', 'u'}
		elseif mw.ustring.match(color[1], '–') then
			color = mw.text.split(color[1], '–')
		end
		result = "\n|-\n|"..(color[2] and ('* Main colors: ||'..hex(color[1])..' and '..hex(color[2])..'\n\n|-\n|* ex colors: ||'..hex(color[1], true)..' and '..hex(color[2], true)) or ('• Main color: ||'..hex(color[1])..'\n|-\n|• ex color: ||'..hex(color[1], true)))..result
	end
	result = "These [[BSicon]]s are to be used with '''route diagram templates'''. For an overview, see [[:Category:BSicon]]."..'\n\123\124'..result..'\n\124\125'
	table.remove(title, 1)
	for k, v in ipairs(title) do
		if not ((mw.ustring.match((title[2] or ''), '^set ') or mw.ustring.match((title[3] or ''), '^set ')) and title[k] == 'railway')
		and not ((mw.ustring.match((title[2] or ''), 'R([A-Z0-9]+)$') or mw.ustring.match((title[3] or ''), 'R([A-Z0-9]+)$') or mw.ustring.match((title[4] or ''), 'R([A-Z0-9]+)$') or mw.ustring.match((title[5] or ''), 'R([A-Z0-9]+)$') or title[2] == 'generic road' or title[3] == 'generic road' or title[4] == 'generic road') and title[k] == 'road')
		and (#title < 3 or k > 1 or (title[2] == 'road' and k == 1) or (title[1] ~= 'railway' and title[1] ~= 'road' and title[1] ~= 'canal'))
		and not (mw.ustring.match((title[k+1] or ''), ' quarters?$'))
		and not (title[k] == 'stations and stops' and (title[k+1] == 'interchange' or title[k+1] == 'express'))
		and not (title[k] == 'interchange' and (title[k+1] == 'CPIC'))
		and not (title[k] == 'uw' and title[k+1] == 'double')
		and not (title[k] == 'tunnel' and (title[k+1] == 'portal' or title[k+2] == 'portal')) then
			tmp = mw.clone(title)
			tmp = 'BSicon/'..table.concat(tmp, '/')
			for _, x in ipairs(used_compounds) do
				if mw.ustring.match(x, v) then
					x = mw.ustring.gsub(x, v, '')
					x = mw.ustring.gsub(x, '/', '')
					local tmp_root = roots[x]
					if tmp_root then
						tmp = mw.ustring.gsub(tmp, tmp_root, '')
					end
				end
			end
			tmp = tmp..'/'
			tmp = mw.ustring.gsub(tmp, '/'..v..'/', '/')
			tmp = mw.ustring.gsub(tmp, '/+', '/')
			for k, v in ipairs(matches) do
				tmp = mw.ustring.gsub(tmp, compounds[v], v)
			end
			for k, v in ipairs(used_roots) do
				if mw.ustring.match(tmp, '/'..v..'/') then tmp = mw.ustring.gsub(tmp, '/'..roots[v], '/') end
			end
			tmp = mw.ustring.gsub(tmp, '/$', '')
			if title2 ~= tmp then categories = categories..mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub('\n[[Category:'..tmp..'|'..mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(title[k], '^set ', '!'), '^R([A-Z0-9]+)$', '$%1'), '^generic road$', '$generic'), '^road$', '$road'), '^railway$', '!railway'), '^(.*width)$', '*%1'), '^parallel lines$', '*parallel lines'), '^one quarter$', '1'), '^two quarters$', '2'), '^three quarters$', '3'), '^four quarters$', '4'), '^five quarters$', '5'), '^six quarters$', '6'), '^seven quarters$', '7'), '^eight quarters$', '8')..']]', '/|', '|'), 'railway|!([a-z][a-z]+)', 'railway/other colors|!%1'), 'railway|!([fg])', 'railway/other colors|!%1') end
		end
	end
	categories = mw.ustring.gsub(categories, '#', '+')
	categories = mw.ustring.gsub(categories, '_', '-')
	return result..categories
end

p.categorize = makeInvokeFunction('_categorize')

-- NOT COMPLETE YET. THIS WILL NOT WORK ON A LOT OF ICONS AND NEEDS A LOT OF CATEGORY TITLE PARTS TO BE ADDED.

function p._categorize(args)
	local title = (mw.ustring.match(mw.title.getCurrentTitle().text, '^BSicon (.*)%.svg$') or 'BHF')
	local category = {['Category:BSicon'] = true}
	local titleparts
	local tmp_set
	local tmp_match = ''
	local result = {}
	if not (mw.ustring.match(title, '[^~]R[ABDEGMPRY]') or mw.ustring.match(title, '^R[ABDEGMPRY]') or mw.ustring.match(title, 'WASSER') or mw.ustring.match(title, 'WABZ')) then
		category['railway'] = true
		titleparts = mw.text.split(title, ' ')
		if titleparts[2] then 
			for k = 2, #titleparts do
				if mw.ustring.match(titleparts[k], '^[a-z]+$') then
					category['set '..titleparts[k]] = true
					category['other colors'] = true
				else
					tmp_set = mw.ustring.match(titleparts[k], '^[a-z]+')
					if tmp_set then category['set '..tmp_set] = true end
					titleparts[1] = titleparts[1]..string.sub(titleparts[k], string.len(tmp_set)+1)
				end
			end
		end
		titleparts = titleparts[1]
		titleparts = '|'..mw.ustring.gsub(titleparts, '.', '%0|')
		titleparts = mw.ustring.gsub(titleparts, '([A-ZÜ])|([A-ZÜ])', '%1%2')
		titleparts = mw.ustring.gsub(titleparts, '([A-ZÜ])|([A-ZÜ])', '%1%2')
		titleparts = mw.ustring.gsub(titleparts, '|n|u|m|', '|NUM|')
		titleparts = mw.ustring.gsub(titleparts, '(SHI)|([1-8])', '%1%2')
		titleparts = mw.ustring.gsub(titleparts, '(BRÜCKE)|([1-3]|[^%+])', '%1%2')
		titleparts = mw.ustring.gsub(titleparts, '(BRÜCKE)|([1-3]|)$', '%1%2')
		titleparts = mw.ustring.gsub(titleparts, '(VIADUKT)|([1-3]|[^%+])', '%1%2')
		titleparts = mw.ustring.gsub(titleparts, '(VIADUKT)|([1-3]|)$', '%1%2')
		titleparts = mw.ustring.gsub(titleparts, '(TUNNEL)|([12]|[^%+])', '%1%2')
		titleparts = mw.ustring.gsub(titleparts, '(TUNNEL)|([12]|)$', '%1%2')
		-- Other roots
		titleparts = mw.ustring.gsub(titleparts, '|?(SW)([A-HJ-ZÜ][A-HJ-ZÜ])', '|!SW|%2')
		titleparts = mw.ustring.gsub(titleparts, '|?S|%+|([A-ZÜ][A-ZÜ])', '|S+%1')
		titleparts = mw.ustring.gsub(titleparts, '|LL?([A-KMNPQS-ZÜ])', '|L|%1')
		titleparts = mw.ustring.gsub(titleparts, '|M([A-ZÜ])', '|M|%1')
		titleparts = mw.ustring.gsub(titleparts, '|M|ASK', '|MASK')
		titleparts = mw.ustring.gsub(titleparts, '|T([A-DF-QSTV-ZÜ])', '|T|%1')
		titleparts = mw.ustring.gsub(titleparts, '|K([A-LN-QS-ZÜ])', '|K|%1')
		titleparts = mw.ustring.gsub(titleparts, '|X([A-ZÜ])', '|X|%1')
		-- Other capital prefix and combining suffix searches
		-- Discard x, since it isn't used for categorization and only has one meaning
		titleparts = mw.ustring.gsub(titleparts, '|x|', '|')
		titleparts = mw.ustring.gsub(titleparts, '^([ufgelhatpnk|]*|)(c?)|?(d?)|?(b?)|', '%1%2%3%4|')
		titleparts = mw.ustring.gsub(titleparts, '|([%+%-])|([lhtnCDLM]?)|?([ck])|([1-4])|?([1-4]?)|?([1-4]?)|?([1-4]?)|', '|%1%3%4%5%6%7|%2|')
		titleparts = mw.ustring.gsub(titleparts, '|([lhtnCDLM]?)|?c|([1-4])|?([1-4]?)|?([1-4]?)|?([1-4]?)|', '|c%2%3%4%5|%1|')
		titleparts = mw.ustring.gsub(titleparts, '(|[%-~@%+])|([LRFGM]+|)', '%1%2')
		titleparts = mw.ustring.gsub(titleparts, '(|%-)([LRFGM]+|[A-ZÜ]+)', '%1|%2') -- split prefix L/F/M from parallel lines syntax
		titleparts = mw.ustring.gsub(titleparts, '|([~@])|([lrfgm])|?([lrfgm]*)|?([lrfgm]*)|?([lrfgm]*)|?([lrfgm]*)|?([lrfgm]*)|', '|%1%2%3%4%5%6|')
		titleparts = mw.ustring.gsub(titleparts, '|%(|([LRFGM]*)|?([lrfgm]*)|?([lrfgm]*)|?([lrfgm]*)|?([lrfgm]*)|?([lrfgm]*)|%)|', '|(%1%2%3%4%5%6)|')
		titleparts = mw.ustring.gsub(titleparts, '^|([ufg])|', '|#%1|')
		titleparts = mw.ustring.gsub(titleparts, '(|[%-%+]|[^A-ZÜ%-%+]+|)([fg]|.*|[A-ZÜ][A-ZÜ])', '%1#%2')
		titleparts = mw.ustring.gsub(titleparts, '(|[%-%+]|[^A-ZÜ%-%+]+|)([fg]|.*|[A-ZÜ][A-ZÜ])', '%1#%2')
		titleparts = mw.ustring.gsub(titleparts, '(|[%-%+]|[^A-ZÜ%-%+]+|)([fg]|[A-ZÜ][A-ZÜ])', '%1#%2')
		titleparts = mw.ustring.gsub(titleparts, '(|[%-%+]|[^A-ZÜ%-%+]+|)([fg]|[A-ZÜ][A-ZÜ])', '%1#%2')
		titleparts = mw.ustring.gsub(titleparts, '^(|[^A-ZÜ%-%+]+|)([fg]|.*|[A-ZÜ][A-ZÜ])', '%1#%2')
		titleparts = mw.ustring.gsub(titleparts, '^(|[^A-ZÜ%-%+]+|)([fg]|.*|[A-ZÜ][A-ZÜ])', '%1#%2')
		titleparts = mw.ustring.gsub(titleparts, '^(|[^A-ZÜ%-%+]+|)([fg]|[A-ZÜ][A-ZÜ])', '%1#%2')
		titleparts = mw.ustring.gsub(titleparts, '^(|[^A-ZÜ%-%+]+|)([fg]|[A-ZÜ][A-ZÜ])', '%1#%2')
		if mw.ustring.match(titleparts, '|m|') then
			category['set mixed'] = true
			titleparts = mw.ustring.gsub(titleparts, '|m|', '|')
		end
		titleparts = mw.ustring.gsub(titleparts, '|([%-%+])|([fg]|.*|[A-ZÜ][A-ZÜ])', '|%1|#%2')
		titleparts = mw.ustring.gsub(titleparts, '|([%-%+])|([fg]|[A-ZÜ][A-ZÜ])', '|%1|#%2')
		titleparts = mw.ustring.gsub(titleparts, '|([^%-]+)|([htCD])|([1-4lrfgm])|([ae])|$', '|%2|%1|%3|%4|')
		titleparts = mw.ustring.gsub(titleparts, '|([^%-]+)|([htCD])|([1-4lrfgm])|([ae])|([^A-Z%-]+)|', '|%2|%1|%3|%5|%4|')
		titleparts = mw.ustring.gsub(titleparts, '|%+|([LRFG]+)|', '|+%1|')
		-- remove q from KRZ because it will trip up other regexes
		titleparts = mw.ustring.gsub(titleparts, 'KRZ|q|', 'KRZ|')
		titleparts = mw.ustring.gsub(titleparts, '|ABZ|([gq]?)|?([1-4lrfgm%+])|?([1-4lrfgm%+]?)|?([1-4lrfgm%+]?)|?([1-4lrfgm%+]?)|?([1-4lrfgm%+]?)|?([1-4lrfgm%+]?)|?([1-4lrfgm%+]?)|', '|ABZ|%1%2%3%4%5%6%7%8|')
		titleparts = mw.ustring.gsub(titleparts, '|WYE|([gq]?)|?([1-4lrfgm%+])|?([1-4lrfgm%+]?)|?([1-4lrfgm%+]?)|?([1-4lrfgm%+]?)|', '|WYE|%1%2%3%4%5|')
		titleparts = mw.ustring.gsub(titleparts, '|(SHI%d)|(g?)|?([lr%+])|?([lr%+]?)|?([lr%+]?)|?([lr%+]?)|?([lr%+]?)|?(q?)|', '|%1|%2%3%4%5%6%7%8|')
		titleparts = mw.ustring.gsub(titleparts, '|(SHI%d)|(g?[lr]?[lr]?)(q?)|', '|%1|%2+%3|')
		titleparts = mw.ustring.gsub(titleparts, '|KRW|(g?)|?([lr%+])|?([lr%+]?)|?([lr%+]?)|?([lr%+]?)|?([lr%+]?)|?(q?)|', '|KRW|%1%2%3%4%5%6%7|')
		titleparts = mw.ustring.gsub(titleparts, '|([A-Z][A-Z%+]+[1-3]?)|([1-4lrfgm])|?([ou]?)|%+|([1-4lrfgm])|?([ou]?)|', '|%1|%2+%4|%3%5|')
		titleparts = mw.ustring.gsub(titleparts, '|([A-Z][A-Z%+]+[1-3]?)|%+|([1-4lrfgm])|?([ou]?)|', '|%1|+%2|%3|')
		titleparts = mw.ustring.gsub(titleparts, '|([A-Z][A-Z%+]+[1-3]?)|([1-4lrfg])|?([ou]?)|', '|%1|%2+|%3|')
		titleparts = mw.ustring.gsub(titleparts, '(|[%-%+]|[^A-ZÜ%-%+]+|)(u)|', '%1#%2|')
		titleparts = mw.ustring.gsub(titleparts, '(|[%-%+]|[^A-ZÜ%-%+]+|)(u)|', '%1#%2|')
		titleparts = mw.ustring.gsub(titleparts, '^(|[^A-ZÜ%-%+]+|)(u)|', '%1#%2|')
		titleparts = mw.ustring.gsub(titleparts, '^(|[^A-ZÜ%-%+]+|)(u)|', '%1#%2|')
		titleparts = mw.ustring.gsub(titleparts, '|([%-%+])|(u)|', '|%1|#%2|')
		-- Add handling for icon names containing more than one root
		-- Affixes always treated the same
		for k, v in pairs({
			['|c|'] = 'quarter-width',
			['|d|'] = 'half-width',
			['|cd|'] = 'three-quarter-width',
			['|b|'] = 'double-width',
			['|v|'] = 'parallel lines',
			['|%-|'] = 'parallel lines',
			['|l|'] = 'legende',
			['|h|'] = 'elevated',
			['|t|'] = 'tunnel',
			['|p|'] = 'express',
			['|n|'] = 'narrow',
			['|C|'] = 'cutting',
			['|D|'] = 'embankment',
			['|k|'] = 'k',
			['|3|'] = '3',
			['|L|'] = 'interruption',
			['|M|'] = 'mask',
			['|T|'] = 'crossing',
			['|[%+%-]?k[1-4][1-4]?[1-4]?[1-4]?|'] = 'k',
			['|[%+%-]?[ck][1-4][1-4]?[1-4]?[1-4]?|'] = 'corner',
			['|#u|'] = 'set u',
			['|#f|'] = 'set f',
			['|#g|'] = 'set g',
			['|[cdbswv%|]+|e?|?#[ufg]|'] = 'set mixed',
			['|%-|e?|?#[ufg]|'] = 'set mixed',
			['|X|'] = 'interchange',
			['|[X]|'] = 'CPIC',
			['|ABZ|'] = 'junction',
			['|WYE|'] = 'wye',
			['|BHF|'] = 'BHF',
			['|HST|'] = 'HST',
			['|DST|'] = 'DST',
			['|BST|'] = 'BST',
			['|INT|'] = 'INT',
			['|ACC|'] = 'ACC',
			['|INTACC|'] = 'INTACC',
			['|HSTACC|'] = 'HSTACC',
			['|SBHF|'] = 'SBHF',
			['|S%+BHF|'] = 'S+BHF',
			['|SHST|'] = 'SHST',
			['|S%+HST|'] = 'S+HST',
			['|HUB|'] = 'hub',
			['|CONT|'] = 'continuation',
			['|ENDE|'] = 'line endings',
			['|GRZ|'] = 'border',
			['|KR[XZ]|'] = 'crossing',
			['|KRX|'] = 'uw',
			['|SPL|'] = 'split',
			['|SHI%d|'] = 'shift',
			['|SHI1|'] = 'one quarter',
			['|SHI2|'] = 'two quarters',
			['|SHI3|'] = 'three quarters',
			['|SHI4|'] = 'four quarters',
			['|KRW|'] = 'krw',
			['|SHI5|'] = 'five quarters',
			['|SHI6|'] = 'six quarters',
			['|SHI7|'] = 'seven quarters',
			['|SHI8|'] = 'eight quarters',
			['|WSL|'] = 'loop',
			['|ZOLL|'] = 'customs',
			['|HUB|'] = 'hub',
			['|%-[LMR]+|'] = 'interchange',
			['|MASK|'] = 'mask',
			
		}) do
			if mw.ustring.match(titleparts, k) then category[v] = true end
		end
		if category['set mixed'] and category['set u'] and not category['other colors'] then category['set u'] = nil end
		if category['legende'] and (category['elevated'] or category['cutting'] or category['embankment']) then
			category['legende'] = nil
			category['formations'] = true
			if category['BHF'] then
				category['BHF'] = nil
				category['stations and stops'] = true
			end
		end
		if category['3'] then
			category['parallel lines'] = nil
			if not (category['junction'] or category['crossing']) then category['curve'] = true end
		elseif category['k'] then
			if not (category['junction'] or category['wye']) then
				tmp_match = mw.ustring.match(titleparts, '|[A-Z][A-Z%+]+[1-3]?|([1-4lrfgm]?%+[1-4lrfgm])|') or mw.ustring.match(titleparts, '|[A-Z][A-Z%+]+[1-3]?|([1-4lrfgm]%+[1-4lrfgm]?)|') or ''
				if mw.ustring.match(tmp_match, '[1-4]') and not category['crossing'] then category['curve'] = true end
			end
		elseif category['shift'] then
			tmp_match = mw.ustring.match(titleparts, '|SHI%d|(g?[lr]?[lr]?%+?[lr]?[lr]?q?)|') or ''
			if mw.ustring.match(tmp_match, 'g') or mw.ustring.match(tmp_match, 'lr') or mw.ustring.match(tmp_match, 'rl') then
				category['junction'] = true
				if mw.ustring.match(tmp_match, 'l.*%+.*l') or mw.ustring.match(tmp_match, 'r.*%+.*r') then
					category['crossing'] = true
				end
			elseif mw.ustring.match(tmp_match, 'l.*%+.*l') or mw.ustring.match(tmp_match, 'r.*%+.*r') then
				category['crossing'] = true
			elseif not category['corner'] then
				category['curve'] = true
			end
		else
			if category['junction'] or category['wye'] then -- add other junctions?
				if mw.ustring.match(titleparts, '|[A-ZÜ]+|[^%-ck]*[1234]') then category['uw'] = true end
			else
				tmp_match = mw.ustring.match(titleparts, '|[A-Z][A-Z%+]+[1-3]?|([1-4lrfgm]?%+[1-4lrfgm])|') or mw.ustring.match(titleparts, '|[A-Z][A-Z%+]+[1-3]?|([1-4lrfgm]%+[1-4lrfgm]?)|') or ''
				if mw.ustring.match(tmp_match, '[1-4]') then
					category['uw'] = true
					if not ((category['half-width'] and mw.ustring.match(tmp_match, 'm'))
						or ((not mw.ustring.match(titleparts, '^[ufgelhatpnk|]*|[ocdbsw]')) and (tmp_match == '3+1' or tmp_match == '2+4' or tmp_match == '1+3' or tmp_match == '4+2'))
						or mw.ustring.match(titleparts, '|K|[^|]+|[1-4]%+||$') or mw.ustring.match(titleparts, '|K|[^|]+|[1-4]%+||[~@][fglmrFGLMR]')
						or mw.ustring.match(titleparts, '|CONT|[1-4]%+||$') or mw.ustring.match(titleparts, '|CONT|[1-4]%+||[~@][fglmrFGLMR]')
						or mw.ustring.match(titleparts, '|ENDE|[1-4]%+||$') or mw.ustring.match(titleparts, '|ENDE|[1-4]%+||[~@][fglmrFGLMR]')
						or category['crossing']) then
						category['curve'] = true
					end
				elseif mw.ustring.match(tmp_match, '^[fg]?%+[lr]$') or mw.ustring.match(tmp_match, '^[lr]%+[fg]?$') or mw.ustring.match(tmp_match, '^[lr]%+[lr]$') then
					category['curve'] = true
				elseif mw.ustring.match(tmp_match, '^[fg]%+$') and not (category['continuation'] or category['line endings']) then
					category['direction'] = true
				end
			end
		end
		if category['corner'] and not category['3'] and not category['k'] and not category['shift'] and not category['krw'] then category['uw'] = true end
		-- if mw.ustring.match(titleparts, '|%-[LMR]') then
		--	if -- stations then category['interchange'] = true
		--	elseif -- one side?
		--	end
		-- end
		if category['tunnel'] and not mw.ustring.match(titleparts, '|K|') and not ((category['continuation'] or category['line endings']) and not category['uw']) then
			if mw.ustring.match(titleparts, '[A-ZÜ][A-ZÜ]+.*|[ae][fgae]?|') then category['portal'] = true end
		end
		
		if category['crossing'] then
			if category['junction'] then
				category['crossing+junction'] = true
				category['crossing'], category['junction'] = nil, nil
			elseif category['corner'] then
				category['crossing+corner'] = true
				category['crossing'], category['corner'] = nil, nil
			end
		elseif category['curve'] then
			if category['corner'] then
				category['curve+corner'] = true
				category['curve'], category['corner'] = nil, nil
			end
		elseif category['corner'] then
			if mw.ustring.match(titleparts, '|%+[ck][1-4][1-4]?[1-4]?[1-4]?|') then
				category['straight+corner'] = true
				category['corner'] = nil
			end
		end
		
		local order = {
			'Category:BSicon',
			
			'railway',
			'road–rail',
			'road',
			'water',
			
			'set u',
			'set f',
			'set g',
			'set mixed',
			'set azure',
			'set black',
			'set blue',
			'set brown',
			'set carrot',
			'set cerulean',
			'set cyan',
			'set deepsky',
			'set denim',
			'set fuchsia',
			'set golden',
			'set green',
			'set grey',
			'set jade',
			'set lavender',
			'set lime',
			'set maroon',
			'set ochre',
			'set olive',
			'set orange',
			'set pink',
			'set purple',
			'set red',
			'set ruby',
			'set saffron',
			'set sky',
			'set steel',
			'set teal',
			'set violet',
			'set white',
			'set yellow',
			'mixed',
			'set u-f',
			'set u-g',
			'set black-orange',
			'set green-yellow',
			'set saffron-azure',
			'set yellow-blue',
			'generic road',
			'RP4',
			'RP2',
			'RP1',
			'RD',
			'RA',
			'RB',
			'RE',
			'RG',
			'RM',
			'RR',
			'RY',
			
			'quarter-width',
			'half-width',
			'three-quarter-width',
			'double-width',
			'parallel lines',
			
			'legende',
			'formations',
			'elevated',
			'tunnel',
			'portal',
			'cutting',
			'embankment',
			'interruption',
			'narrow',
			'hub',
			'3',
			'k',
			'uw',
			'shift',
			'one quarter',
			'two quarters',
			'three quarters',
			'four quarters',
			'krw', -- deprecated?
			'five quarters',
			'six quarters',
			'seven quarters',
			'eight quarters',
			'split',
			
			'crossing',
			'crossing+junction',
			'crossing+corner',
			'junction',
			'straight+junction',
			'wye',
			'line endings',
			'continuation',
			'loop',
			'border', -- determine exact order
			'customs', -- determine exact order
			'stations and stops',
			'suburban',
			'BHF',
			'HST',
			'DST',
			'BST',
			'INT',
			'ACC',
			'SBHF',
			'SHST',
			'S+BHF',
			'S+HST',
			'HSTACC',
			'INTACC',
			
			'hub',
			'express',
			'interchange',
			'CPIC',
			'direction',
			'curve',
			'corner',
			'straight+curve',
			'straight+corner',
			'curve+corner',
		}
		for k, v in ipairs(order) do
			if category[v] then table.insert(result, v) end
		end
		result = table.concat(result, '/')
		-- return (mw.dumpObject(result) or '')..(mw.dumpObject(titleparts) or '')..(mw.dumpObject(test) or '')
	end
	return result
end

return p