local categoryData = require("Module:Storm categories/categories") local colors = require("Module:Storm categories/colors").colors local icons = require("Module:Storm categories/icons").icons local cats = categoryData.cats local defaultCategory = categoryData.defaultCategory local p = {}  function p.color(frame) 	return p._color(frame.args[1] or frame:getParent().args[1], false) end  function p.name(frame) 	return p._name( 		frame.args[1] or frame:getParent().args[1], 		frame.args[2] or frame:getParent().args[2], 		false 	) end  function p.sortkey(frame) 	return p._sortkey(frame.args[1] or frame:getParent().args[1], false) end  function p.icon(frame) 	return p._icon(frame.args[1] or frame:getParent().args[1], false) end  function p.isEqual(frame) 	return p._isEqual( 		frame.args[1] or frame:getParent().args[1], 		frame.args[2] or frame:getParent().args[2] 	) and "yes" or "" end  function p._normalizeId(category, fallback) 	-- Normalize if normalizable, fall back to default if not. 	return (category ~= nil and string.len(category) ~= 0) and 		string.gsub(string.lower(category), "[^%w]", "") or fallback end  function p._color(category, nilIfMissing) 	-- This looks confusing, but it's actually nested ternaries (for nil checks) 	local color = p._normalizeId(category, defaultCategory) 		 	return colors[color] or ((cats[color] or ( 		nilIfMissing 		and { color = nil } 		or cats[defaultCategory] 	)).color) end  function p._name(category, basin, nilIfMissing) 	local name_def = (cats[ 		p._normalizeId(category, defaultCategory) 	] or (nilIfMissing and { name = nil } or cats[defaultCategory])).name 	return type(name_def) == "table" and  		( 			name_def[string.lower(basin or "default")] 			or name_def["default"] 			or (not nilIfMissing and error("No default name for basin-based category name.") or nil) 		)  		or name_def end  function p._sortkey(category, nilIfMissing) 	-- This looks confusing, but it's actually nested ternaries (for nil checks) 	return (cats[ 		p._normalizeId(category, defaultCategory) 	] or (nilIfMissing and { sortkey = nil } or cats[defaultCategory])).sortkey end  function p._icon(category, nilIfMissing) 	-- This looks confusing, but it's actually nested ternaries (for nil checks) 	local icon = p._normalizeId(category, defaultCategory) 		 	return icons[icon] or (cats[icon] ~= nil and ( 		cats[icon].icon or cats["tropicalcyclone"].icon 	) or (not nilIfMissing and cats[defaultCategory].icon) or nil) end  function p._isEqual(category1, category2) 	-- Checks if two IDs are equal. 	-- An  check does not consider aliases. This function compares two 	-- IDs in a way that considers category aliases. This works because alias 	-- assignments are references to the actual table containing the category 	-- info found in the main category table. 	--  	-- `false` will be returned if at least one of the categories are nil or 	-- if the category is not defined. 	local _category1 = p._normalizeId(category1) 	local _category2 = p._normalizeId(category2) 	return (_category1 == _category2 and _category1 ~= nil) or 		cats[ _category1 ] == cats[ _category2 ] and 			-- `false` if categories are undefined and not equal. 			cats[ _category1 ] ~= nil end  function p.demo(frame) 	return require("Module:Storm categories/demo").demo(frame) end  return p