<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://petitplanet.wiki/index.php?action=history&amp;feed=atom&amp;title=Module%3ASandbox%2FStevium</id>
	<title>Module:Sandbox/Stevium - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://petitplanet.wiki/index.php?action=history&amp;feed=atom&amp;title=Module%3ASandbox%2FStevium"/>
	<link rel="alternate" type="text/html" href="https://petitplanet.wiki/index.php?title=Module:Sandbox/Stevium&amp;action=history"/>
	<updated>2026-04-12T23:54:59Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://petitplanet.wiki/index.php?title=Module:Sandbox/Stevium&amp;diff=6368&amp;oldid=prev</id>
		<title>Stevium: Testing subtitle</title>
		<link rel="alternate" type="text/html" href="https://petitplanet.wiki/index.php?title=Module:Sandbox/Stevium&amp;diff=6368&amp;oldid=prev"/>
		<updated>2026-02-21T11:02:37Z</updated>

		<summary type="html">&lt;p&gt;Testing subtitle&lt;/p&gt;
&lt;a href=&quot;https://petitplanet.wiki/index.php?title=Module:Sandbox/Stevium&amp;amp;diff=6368&amp;amp;oldid=4669&quot;&gt;Show changes&lt;/a&gt;</summary>
		<author><name>Stevium</name></author>
	</entry>
	<entry>
		<id>https://petitplanet.wiki/index.php?title=Module:Sandbox/Stevium&amp;diff=4669&amp;oldid=prev</id>
		<title>Stevium: Created Module:Sandbox/Stevium</title>
		<link rel="alternate" type="text/html" href="https://petitplanet.wiki/index.php?title=Module:Sandbox/Stevium&amp;diff=4669&amp;oldid=prev"/>
		<updated>2025-11-19T14:00:46Z</updated>

		<summary type="html">&lt;p&gt;Created Module:Sandbox/Stevium&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;-- Imported from: https://defaultloadout.wiki.gg/wiki/Module:Navbox&lt;br /&gt;
-- version 1.2.5.1&lt;br /&gt;
&lt;br /&gt;
-- config table for RANGER.&lt;br /&gt;
-- If you want to change the default config, DO NOT change it here,&lt;br /&gt;
-- please do it via the `onLoadConfig` hook in [[Module:Navbox/Hooks]].&lt;br /&gt;
local config = {&lt;br /&gt;
	default_navbox_class = &amp;quot;navigation-not-searchable noexcerpt&amp;quot;,   -- Base value of the `class` parameter.&lt;br /&gt;
	default_title_class = nil,    -- Base value of the `title_class` parameter.&lt;br /&gt;
	default_above_class = nil,    -- Base value of the `above_class` parameter.&lt;br /&gt;
	default_below_class = nil,    -- Base value of the `below_class` parameter.&lt;br /&gt;
	default_section_class =nil,   -- Base value of the `section_class` parameter.&lt;br /&gt;
	default_header_class = nil,   -- Base value of the `header_class` parameter.&lt;br /&gt;
	default_group_class = nil,    -- Base value of the `group_class` parameter.&lt;br /&gt;
	default_list_class = &amp;#039;hlist&amp;#039;, -- Base value of the `list_class` parameter.&lt;br /&gt;
	&lt;br /&gt;
	default_header_state = nil, -- Base value of the `state` parameter.&lt;br /&gt;
&lt;br /&gt;
	editlink_hover_message_key = &amp;#039;Navbox-edit-hover&amp;#039;, -- The system message name for hover text of the edit icon. &lt;br /&gt;
&lt;br /&gt;
	auto_flatten_top_level = true, -- If true, when a section has only one list with no content and no corresponding group but has sublists, these sublists will be moved to top level.&lt;br /&gt;
	-- This helps make the hierarchy of sections and content clearer.&lt;br /&gt;
	-- An example:&lt;br /&gt;
	-- {{navbox&lt;br /&gt;
	-- ...&lt;br /&gt;
	--   |header1 = Items&lt;br /&gt;
	--   | group1.1 = Weapons&lt;br /&gt;
	--   |  list1.1 = Swords · Guns · Wands&lt;br /&gt;
	--   | group1.2 = Armors&lt;br /&gt;
	--   |  list1.2 = Head pieces · Capes&lt;br /&gt;
	--   |header2 = NPCs&lt;br /&gt;
	--   | group2.1 = Town NPCs&lt;br /&gt;
	--   |  list2.1 = Guide · Witch&lt;br /&gt;
	-- ...&lt;br /&gt;
	-- }}&lt;br /&gt;
	-- will be equal to:&lt;br /&gt;
	-- {{navbox&lt;br /&gt;
	-- ...&lt;br /&gt;
	--   |header1 = Items&lt;br /&gt;
	--   | group2 = Weapons&lt;br /&gt;
	--   |  list2 = Swords · Guns · Wands&lt;br /&gt;
	--   | group3 = Armors&lt;br /&gt;
	--   |  list3 = Head pieces · Capes&lt;br /&gt;
	--   |header5 = NPCs&lt;br /&gt;
	--   | group6 = Town NPCs&lt;br /&gt;
	--   |  list6 = Guide · Witch&lt;br /&gt;
	-- ...&lt;br /&gt;
	-- }}&lt;br /&gt;
	&lt;br /&gt;
	custom_render_handle = nil, -- usually for debugging purposes only. if set, it should be a function accept 2 parameters: `dataTree` and `args`, and return a string as module output.&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
---------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
-- Argument alias.&lt;br /&gt;
local CANONICAL_NAMES = {&lt;br /&gt;
	[&amp;#039;titlestyle&amp;#039;] = &amp;#039;title_style&amp;#039;,&lt;br /&gt;
	[&amp;#039;listclass&amp;#039;] = &amp;#039;list_class&amp;#039;,&lt;br /&gt;
	[&amp;#039;groupstyle&amp;#039;] = &amp;#039;group_style&amp;#039;,&lt;br /&gt;
	[&amp;#039;collapsible&amp;#039;] = &amp;#039;state&amp;#039;,&lt;br /&gt;
	[&amp;#039;editlink&amp;#039;] = &amp;#039;meta&amp;#039;,&lt;br /&gt;
	[&amp;#039;editlinks&amp;#039;] = &amp;#039;meta&amp;#039;,&lt;br /&gt;
	[&amp;#039;editicon&amp;#039;] = &amp;#039;meta&amp;#039;,&lt;br /&gt;
	[&amp;#039;edit_link&amp;#039;] = &amp;#039;meta&amp;#039;,&lt;br /&gt;
	[&amp;#039;edit_links&amp;#039;] = &amp;#039;meta&amp;#039;,&lt;br /&gt;
	[&amp;#039;edit_icon&amp;#039;] = &amp;#039;meta&amp;#039;,&lt;br /&gt;
	[&amp;#039;navbar&amp;#039;] = &amp;#039;meta&amp;#039;,&lt;br /&gt;
	[&amp;#039;name&amp;#039;] = &amp;#039;template&amp;#039;,&lt;br /&gt;
	[&amp;#039;evenodd&amp;#039;] = &amp;#039;striped&amp;#039;,&lt;br /&gt;
	[&amp;#039;class&amp;#039;] = &amp;#039;navbox_class&amp;#039;,&lt;br /&gt;
	[&amp;#039;css&amp;#039;] = &amp;#039;navbox_style&amp;#039;,&lt;br /&gt;
	[&amp;#039;style&amp;#039;] = &amp;#039;navbox_style&amp;#039;,&lt;br /&gt;
	[&amp;#039;group&amp;#039;] = &amp;#039;1:group&amp;#039;,&lt;br /&gt;
	[&amp;#039;list&amp;#039;] = &amp;#039;1:list&amp;#039;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local DEFAULT_ARGS = {&lt;br /&gt;
	[&amp;#039;meta&amp;#039;] = true,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local STATES = {&lt;br /&gt;
	[&amp;#039;no&amp;#039;] = &amp;#039;&amp;#039;,&lt;br /&gt;
	[&amp;#039;off&amp;#039;] = &amp;#039;&amp;#039;,&lt;br /&gt;
	[&amp;#039;plain&amp;#039;] = &amp;#039;&amp;#039;,&lt;br /&gt;
	[&amp;#039;collapsed&amp;#039;] = &amp;#039;mw-collapsible mw-collapsed&amp;#039;,&lt;br /&gt;
	[&amp;#039;expanded&amp;#039;] = &amp;#039;mw-collapsible&amp;#039;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local BOOL_FALSE = {&lt;br /&gt;
	[&amp;#039;no&amp;#039;] = true,&lt;br /&gt;
	[&amp;#039;off&amp;#039;] = true,&lt;br /&gt;
	[&amp;#039;false&amp;#039;] = true,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local STRIPED = {&lt;br /&gt;
	[&amp;#039;odd&amp;#039;] = &amp;#039;striped-odd&amp;#039;,&lt;br /&gt;
	[&amp;#039;swap&amp;#039;] = &amp;#039;striped-odd&amp;#039;,&lt;br /&gt;
	[&amp;#039;y&amp;#039;] = &amp;#039;striped-even&amp;#039;,&lt;br /&gt;
	[&amp;#039;yes&amp;#039;] = &amp;#039;striped-even&amp;#039;,&lt;br /&gt;
	[&amp;#039;on&amp;#039;] = &amp;#039;striped-even&amp;#039;,&lt;br /&gt;
	[&amp;#039;even&amp;#039;] = &amp;#039;striped-even&amp;#039;,&lt;br /&gt;
	[&amp;#039;striped&amp;#039;] = &amp;#039;striped-even&amp;#039;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local NAVBOX_CHILD_INDICATOR = &amp;#039;!!C$H$I$L$D!!&amp;#039;&lt;br /&gt;
local NAVBOX_CHILD_INDICATOR_LENGTH = string.len( NAVBOX_CHILD_INDICATOR )&lt;br /&gt;
&lt;br /&gt;
local CLASS_PREFIX = &amp;#039;ranger-&amp;#039;&lt;br /&gt;
&lt;br /&gt;
---------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
local h = {} -- non-public&lt;br /&gt;
local hooks = mw.title.new(&amp;#039;Module:Navbox/Hooks&amp;#039;).exists and require(&amp;#039;Module:Navbox/Hooks&amp;#039;) or {}&lt;br /&gt;
&lt;br /&gt;
---------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
-- For templates: {{#invoke:navbox|main|...}}&lt;br /&gt;
function p.main(frame)&lt;br /&gt;
	local args = p.mergeArgs(frame)&lt;br /&gt;
	return p.build(args, true)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- For modules: return require(&amp;#039;module:navbox&amp;#039;).build(args)&lt;br /&gt;
-- By default this method will skip the arguments sanitizing phase &lt;br /&gt;
-- (and onSanitizeArgsStart/onSanitizeArgsEnd hooks).&lt;br /&gt;
-- Set `doParseArgs` to true to do arguments sanitizing.&lt;br /&gt;
-- If `customConfig` table is provided, it will be merged into default config table (after onLoadConfig()).&lt;br /&gt;
-- If `customHooks` table is provided, all default hook handles will be overrided, unprovided hooks will be empty.&lt;br /&gt;
function p.build(args, doParseArgs, customConfig, customHooks)&lt;br /&gt;
	if customHooks then&lt;br /&gt;
		hooks = customHooks&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	if doParseArgs then &lt;br /&gt;
		args = h.parseArgs(args)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	h.runHook(&amp;#039;onLoadConfig&amp;#039;, config, args)&lt;br /&gt;
&lt;br /&gt;
	if customConfig then&lt;br /&gt;
		for k,v in pairs(customConfig) do&lt;br /&gt;
			config[k] = v&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	--merge default args&lt;br /&gt;
	for k,v in pairs(DEFAULT_ARGS) do&lt;br /&gt;
		if args[k] == nil then&lt;br /&gt;
			args[k] = DEFAULT_ARGS[k]&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	h.runHook(&amp;#039;onBuildTreeStart&amp;#039;, args)&lt;br /&gt;
	local dataTree = h.buildDataTree(args)&lt;br /&gt;
	h.runHook(&amp;#039;onBuildTreeEnd&amp;#039;, dataTree, args)&lt;br /&gt;
	&lt;br /&gt;
	if type(config.custom_render_handle) == &amp;#039;function&amp;#039; then&lt;br /&gt;
		return config.custom_render_handle(dataTree, args)&lt;br /&gt;
	else&lt;br /&gt;
		return h.render(dataTree)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- merge args from frame and frame:getParent()&lt;br /&gt;
-- It may be used when creating custom wrapping navbox module.&lt;br /&gt;
--&lt;br /&gt;
-- For example, Module:PillNavbox&lt;br /&gt;
--&lt;br /&gt;
-- local RANGER = require(&amp;#039;Module:Navbox&amp;#039;)&lt;br /&gt;
-- local p = {}&lt;br /&gt;
-- function p.main(frame)&lt;br /&gt;
--     return RANGER.build(RANGER.mergeArgs(frame), true, {&lt;br /&gt;
--         default_navbox_class = &amp;#039;pill&amp;#039;, -- use &amp;quot;pill&amp;quot; style by default.&lt;br /&gt;
--     })&lt;br /&gt;
-- end&lt;br /&gt;
-- return p&lt;br /&gt;
--&lt;br /&gt;
function p.mergeArgs(frame)&lt;br /&gt;
	local inputArgs = {}&lt;br /&gt;
	&lt;br /&gt;
	for k, v in pairs(frame.args) do&lt;br /&gt;
		v = mw.text.trim(tostring(v))&lt;br /&gt;
		if v ~= &amp;#039;&amp;#039; then&lt;br /&gt;
			inputArgs[k] = v&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	for k, v in pairs(frame:getParent().args) do&lt;br /&gt;
		v = mw.text.trim(v)&lt;br /&gt;
		if v ~= &amp;#039;&amp;#039; then&lt;br /&gt;
			inputArgs[k] = v&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return inputArgs&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
-- equivalent to mw.text.split(str, div, true) for non-empty separator, but can be over 60x faster, since the latter is Unicode-aware.&lt;br /&gt;
-- Original version credit: http://richard.warburton.it.&lt;br /&gt;
function h.explode(div, str)&lt;br /&gt;
	if (div==&amp;#039;&amp;#039;) then return nil end&lt;br /&gt;
	local pos,arr = 0,{}&lt;br /&gt;
	-- for each divider found&lt;br /&gt;
	for st,sp in function() return string.find(str,div,pos,true) end do&lt;br /&gt;
		arr[#arr+1] = string.sub(str,pos,st-1) -- Attach chars left of current divider&lt;br /&gt;
		pos = sp+1 -- Jump past current divider&lt;br /&gt;
	end&lt;br /&gt;
	arr[#arr+1] = string.sub(str,pos) -- Attach chars right of last divider&lt;br /&gt;
	return arr&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function h.parseArgs(inputArgs)&lt;br /&gt;
	h.runHook(&amp;#039;onSanitizeArgsStart&amp;#039;, inputArgs)&lt;br /&gt;
	&lt;br /&gt;
	local args = {}&lt;br /&gt;
	&lt;br /&gt;
	for k, v in pairs(inputArgs) do&lt;br /&gt;
		if type(k) == &amp;#039;string&amp;#039; then&lt;br /&gt;
			-- all named args have already been trimmed&lt;br /&gt;
			local key = h.normalizeKey(k)&lt;br /&gt;
			args[key] = h.normalizeValue(key, v)&lt;br /&gt;
		else&lt;br /&gt;
			args[k] = mw.text.trim(v) -- keep number-index arguments (for {{navbox|child|...}})&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	h.runHook(&amp;#039;onSanitizeArgsEnd&amp;#039;, args, inputArgs)&lt;br /&gt;
	&lt;br /&gt;
	return args&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Normalize the name string of arguments.&lt;br /&gt;
-- the normalized form is (index:)?name, in which:&lt;br /&gt;
-- index is number index such as 1, 1.3, 1.2.45,&lt;br /&gt;
-- name is in lowercase underscore-case, such as group, group_style&lt;br /&gt;
-- e.g: header_state, 1.3:list_style&lt;br /&gt;
-- the input argument name can be:&lt;br /&gt;
-- * camel-case: listStyle, ListStyle&lt;br /&gt;
-- * space separated: list style&lt;br /&gt;
-- * prefix+index+postfix?, and can be in camel-case or space/hyphen separated or mixed: list 1 style, list1, list1Style, list1_style&lt;br /&gt;
-- * index.name: 1.3.list&lt;br /&gt;
-- * index_name: 1.3_list (Space separated are treated as underscore separated, therefore 1.3 list are vaild too)&lt;br /&gt;
function h.normalizeKey(s)&lt;br /&gt;
	-- camel-case to lowercase underscore-case&lt;br /&gt;
	s = s:gsub(&amp;#039;%l%f[%u]&amp;#039;, &amp;#039;%0_&amp;#039;) -- listStyle to list_style&lt;br /&gt;
	s = (s:gsub(&amp;#039; &amp;#039;, &amp;#039;_&amp;#039;)):lower() -- space to underscore &lt;br /&gt;
	s = s:gsub(&amp;#039;%l%f[%d]&amp;#039;, &amp;#039;%0_&amp;#039;) -- group1* to group_1*&lt;br /&gt;
	s = s:gsub(&amp;#039;%d%f[%l]&amp;#039;, &amp;#039;%0_&amp;#039;) -- *1style to *1_style&lt;br /&gt;
	&lt;br /&gt;
	-- number format x_y_z to x.y.z&lt;br /&gt;
	s = s:gsub(&amp;#039;(%d)_%f[%d]&amp;#039;, &amp;#039;%1%.&amp;#039;)&lt;br /&gt;
	&lt;br /&gt;
	-- move index to the beginning:&lt;br /&gt;
	-- group_1.2_style to 1.2:group_style&lt;br /&gt;
	-- group_1 to 1:group&lt;br /&gt;
	s = s:gsub(&amp;#039;^([%l_]+)_([%d%.]+)&amp;#039;, &amp;#039;%2:%1&amp;#039;)&lt;br /&gt;
	&lt;br /&gt;
	-- support index.name and index_name:&lt;br /&gt;
	-- 1.2.group / 1.2_group to 1.2:group&lt;br /&gt;
	s = s:gsub(&amp;#039;^([%d%.]+)[%._]%f[%l]&amp;#039;, &amp;#039;%1:&amp;#039;)&lt;br /&gt;
	&lt;br /&gt;
	-- now the key should be in normalized form, if the origin key is vaild&lt;br /&gt;
&lt;br /&gt;
	-- standardize *_css to *_style&lt;br /&gt;
	s = s:gsub(&amp;#039;_css$&amp;#039;, &amp;#039;_style&amp;#039;)&lt;br /&gt;
	-- standardize *collapsible to *state&lt;br /&gt;
	s = s:gsub(&amp;#039;collapsible$&amp;#039;, &amp;#039;state&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
	-- standardize all aliases to the canonical name&lt;br /&gt;
	return CANONICAL_NAMES[s] or s&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function h.normalizeValue(k, v)&lt;br /&gt;
	k = tostring(k)&lt;br /&gt;
	if k:find(&amp;#039;_style$&amp;#039;) then&lt;br /&gt;
		v = (v .. &amp;#039;;&amp;#039;):gsub(&amp;#039;;;&amp;#039;, &amp;#039;;&amp;#039;)&lt;br /&gt;
		return v&lt;br /&gt;
	elseif k:find(&amp;#039;state$&amp;#039;) then&lt;br /&gt;
		return STATES[v]&lt;br /&gt;
	elseif k == &amp;#039;striped&amp;#039; then&lt;br /&gt;
		return STRIPED[v]&lt;br /&gt;
	elseif k == &amp;#039;meta&amp;#039; then&lt;br /&gt;
		return not BOOL_FALSE[v]&lt;br /&gt;
	elseif v:sub(1, 2) == &amp;#039;{|&amp;#039; or v:match(&amp;#039;^[*:;#]&amp;#039;) then&lt;br /&gt;
		-- Applying nowrap to lines in a table does not make sense.&lt;br /&gt;
		-- Add newlines to compensate for trim of x in |parm=x in a template.&lt;br /&gt;
		return &amp;#039;\n&amp;#039; .. v ..&amp;#039;\n&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	return v&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- parse arguments, convert them to structured data tree&lt;br /&gt;
function h.buildDataTree(args)&lt;br /&gt;
	-- parse args to a tree&lt;br /&gt;
	local tree = h.buildTree(args)&lt;br /&gt;
&lt;br /&gt;
	-- build root navbox data&lt;br /&gt;
	local data = h.buildNavboxData(tree.info)&lt;br /&gt;
	&lt;br /&gt;
	-- Recursively build section tree&lt;br /&gt;
	if tree.children then&lt;br /&gt;
		data.sections = h.buildSections(tree.children, {&lt;br /&gt;
			listClass = h.mergeAttrs(args.list_class, config.default_list_class),&lt;br /&gt;
			listStyle =  args.list_style,&lt;br /&gt;
			groupClass = h.mergeAttrs(args.group_class, config.default_group_class),&lt;br /&gt;
			groupStyle = args.group_style,&lt;br /&gt;
			sectionClass = h.mergeAttrs(args.section_class, config.default_section_class),&lt;br /&gt;
			sectionStyle = args.section_style,&lt;br /&gt;
			headerClass = h.mergeAttrs(args.header_class, config.default_header_class),&lt;br /&gt;
			headerStyle = args.header_style,&lt;br /&gt;
			headerState = args.header_state or config.default_header_state,&lt;br /&gt;
		})&lt;br /&gt;
	end&lt;br /&gt;
	if args[1] == &amp;#039;child&amp;#039; then&lt;br /&gt;
		data.CHILD_MODE = true&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return data&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function h.buildSections(list, defaults)&lt;br /&gt;
	local sections = {}&lt;br /&gt;
	local section = nil&lt;br /&gt;
	for k, node in h.orderedPairs(list) do&lt;br /&gt;
		local info = node.info or {}&lt;br /&gt;
		--start a new section if needed&lt;br /&gt;
		if info.header or not section then&lt;br /&gt;
			section = { &lt;br /&gt;
				class = h.mergeAttrs(info.section_class, defaults.sectionClass),&lt;br /&gt;
				style = h.mergeAttrs(info.section_style, defaults.sectionStyle),&lt;br /&gt;
				body = {}&lt;br /&gt;
			}&lt;br /&gt;
			-- Section header if needed.&lt;br /&gt;
			-- If the value of a `|header_n=` is two or more consecutive &amp;quot;-&amp;quot; characters (e.g. --, -----), &lt;br /&gt;
			-- it means start a new section without header, and the new section will be not collapsable.&lt;br /&gt;
			if info.header and not string.match(info.header, &amp;#039;^%-%-+$&amp;#039;) then&lt;br /&gt;
				section.header = {&lt;br /&gt;
					content = info.header,&lt;br /&gt;
					class = h.mergeAttrs(info.header_class, defaults.headerClass),&lt;br /&gt;
					style = h.mergeAttrs(info.header_style, defaults.headerStyle),&lt;br /&gt;
				}&lt;br /&gt;
				section.state = info.state or defaults.headerState or &amp;#039;mw-collapsible&amp;#039;&lt;br /&gt;
			end&lt;br /&gt;
			sections[#sections+1] = section&lt;br /&gt;
		end&lt;br /&gt;
		-- above/below for this section&lt;br /&gt;
		if info.above then&lt;br /&gt;
			section.above = {&lt;br /&gt;
				content = info.above,&lt;br /&gt;
				class= h.mergeAttrs(info.above_class, config.default_above_class),&lt;br /&gt;
				style = info.above_style,&lt;br /&gt;
			}&lt;br /&gt;
		end&lt;br /&gt;
		if info.below then&lt;br /&gt;
			section.below = {&lt;br /&gt;
				content = info.below,&lt;br /&gt;
				class= h.mergeAttrs(info.below_class, config.default_below_class),&lt;br /&gt;
				style = info.below_style,&lt;br /&gt;
			}&lt;br /&gt;
		end&lt;br /&gt;
		-- this group+list row&lt;br /&gt;
		if info.group or info.list or node.children then&lt;br /&gt;
			local row = {}&lt;br /&gt;
			section.body[#section.body+1] = row&lt;br /&gt;
			if info.group then&lt;br /&gt;
				row.group = {&lt;br /&gt;
					content = info.group,&lt;br /&gt;
					class = h.mergeAttrs(info.group_class, defaults.groupClass),&lt;br /&gt;
					style = h.mergeAttrs(info.group_style, defaults.groupStyle),&lt;br /&gt;
				}&lt;br /&gt;
			end&lt;br /&gt;
			if info.list then&lt;br /&gt;
				if string.sub(info.list, 1, NAVBOX_CHILD_INDICATOR_LENGTH) == NAVBOX_CHILD_INDICATOR then&lt;br /&gt;
					-- it is from {{navbox|child| ... }}&lt;br /&gt;
					row.sections = mw.text.jsonDecode(string.sub(info.list, NAVBOX_CHILD_INDICATOR_LENGTH+1))&lt;br /&gt;
				else&lt;br /&gt;
					row.list = {&lt;br /&gt;
						content = info.list,&lt;br /&gt;
						class = h.mergeAttrs(info.list_class, defaults.listClass),&lt;br /&gt;
						style = h.mergeAttrs(info.list_style, defaults.listStyle),&lt;br /&gt;
					}&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			-- sub-nodes, will override {{navbox|child| ... }}&lt;br /&gt;
			if node.children then&lt;br /&gt;
				row.sections = h.buildSections(node.children, defaults)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	-- flatten if needed:&lt;br /&gt;
	-- If a section has only one list with no content and no corresponding group but has sublists, these sublists will be moved to upper level.&lt;br /&gt;
	if config.auto_flatten_top_level then&lt;br /&gt;
		for _, sect in ipairs(sections) do&lt;br /&gt;
			if #sect.body == 1 then&lt;br /&gt;
				local node = sect.body[1]&lt;br /&gt;
				if not node.group and not node.list and node.sections and #node.sections == 1 and not node.sections[1].header then&lt;br /&gt;
					sect.body = node.sections[1].body&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return sections&lt;br /&gt;
end&lt;br /&gt;
	&lt;br /&gt;
function h.buildNavboxData(info)&lt;br /&gt;
	local data = {&lt;br /&gt;
		state = info.state or &amp;#039;mw-collapsible&amp;#039;, -- here we need a default value for empty input&lt;br /&gt;
		striped = info.striped,&lt;br /&gt;
		class = h.mergeAttrs(info.navbox_class, config.default_navbox_class),&lt;br /&gt;
		style = info.navbox_style,&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	-- data for titlebar&lt;br /&gt;
	if info.title or info.meta or data.state ~= &amp;#039;&amp;#039; then&lt;br /&gt;
		data.title = {&lt;br /&gt;
			content = info.title,&lt;br /&gt;
			class = h.mergeAttrs(info.title_class, config.default_title_class),&lt;br /&gt;
			style = info.title_style,&lt;br /&gt;
		}&lt;br /&gt;
		if info.meta then&lt;br /&gt;
			data.metaLinks = {&lt;br /&gt;
				link = info.meta_link, -- will be used as [[$link|$text]]&lt;br /&gt;
				url = info.meta_url,  -- will be used as [$url $text], only if there is no data.metaLinks.link&lt;br /&gt;
				text = info.meta_text, --hovertext&lt;br /&gt;
			}&lt;br /&gt;
			if not info.meta_link and not info.meta_url then&lt;br /&gt;
				-- default link target&lt;br /&gt;
				local title = mw.title.new(info.template or mw.getCurrentFrame():getParent():getTitle(), &amp;#039;Template&amp;#039;)&lt;br /&gt;
				if not title then&lt;br /&gt;
					error(&amp;#039;Invalid title &amp;#039; .. info.template)&lt;br /&gt;
				end&lt;br /&gt;
				data.metaLinks.link = title.fullText&lt;br /&gt;
			end&lt;br /&gt;
			if not info.meta_text then&lt;br /&gt;
				local msg = mw.message.new(config.editlink_hover_message_key)&lt;br /&gt;
				data.metaLinks.text = msg:exists() and msg:plain() or &amp;#039;View or edit this template&amp;#039;&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- above/below&lt;br /&gt;
	if info.above then&lt;br /&gt;
		data.above = {&lt;br /&gt;
			content = info.above,&lt;br /&gt;
			class= h.mergeAttrs(info.above_class, config.default_above_class),&lt;br /&gt;
			style = info.above_style,&lt;br /&gt;
		}&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if info.below then&lt;br /&gt;
		data.below = {&lt;br /&gt;
			content = info.below,&lt;br /&gt;
			class= h.mergeAttrs(info.below_class, config.default_below_class),&lt;br /&gt;
			style = info.below_style,&lt;br /&gt;
		}&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return data&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- parse arguments, convert them into a tree based on their index&lt;br /&gt;
-- each node on tree is { info = { #data for this node# }, children = {#children nodes#}  }&lt;br /&gt;
function h.buildTree(args, defaults)&lt;br /&gt;
	local tree = { info = {} }&lt;br /&gt;
	local check = function(key, value)&lt;br /&gt;
		local index, name = string.match(key, &amp;#039;^([%d%.]+):(.+)$&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
		-- no number index found, for root node&lt;br /&gt;
		if not index then &lt;br /&gt;
			tree.info[key] = value&lt;br /&gt;
			return&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		-- filter invalid number index&lt;br /&gt;
		if string.match(index, &amp;#039;^%.&amp;#039;) or string.match(index, &amp;#039;%.$&amp;#039;) or string.match(index, &amp;#039;%.%.&amp;#039;) then&lt;br /&gt;
			return&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		-- find the node that matches the index in the tree&lt;br /&gt;
		local arr = h.explode(&amp;#039;.&amp;#039;, index)&lt;br /&gt;
		local node = tree&lt;br /&gt;
		for _, v in ipairs(arr) do&lt;br /&gt;
			v = tonumber(v)&lt;br /&gt;
			if not node.children then&lt;br /&gt;
				node.children = {}&lt;br /&gt;
			end&lt;br /&gt;
			if not node.children[v] then &lt;br /&gt;
				node.children[v] = { info = {} }&lt;br /&gt;
			end&lt;br /&gt;
			node = node.children[v]&lt;br /&gt;
		end&lt;br /&gt;
		&lt;br /&gt;
		node.info[name] = value&lt;br /&gt;
	end&lt;br /&gt;
	for k,v in pairs(args) do&lt;br /&gt;
		check(k, v)&lt;br /&gt;
	end&lt;br /&gt;
	return tree&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function h.render(data)&lt;br /&gt;
	-- handle {{navbox|child|...}} syntax&lt;br /&gt;
	if data.CHILD_MODE then&lt;br /&gt;
		return NAVBOX_CHILD_INDICATOR..mw.text.jsonEncode(data.sections)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-----  normal case -----&lt;br /&gt;
	&lt;br /&gt;
	local out = mw.html.create()&lt;br /&gt;
	&lt;br /&gt;
	-- build navbox container&lt;br /&gt;
	local navbox = out:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
		:attr(&amp;#039;role&amp;#039;, &amp;#039;navigation&amp;#039;):attr(&amp;#039;aria-label&amp;#039;, &amp;#039;Navbox&amp;#039;)&lt;br /&gt;
		:addClass(CLASS_PREFIX..&amp;#039;navbox&amp;#039;)&lt;br /&gt;
		:addClass(data.class)&lt;br /&gt;
		:addClass(data.striped)&lt;br /&gt;
		:addClass(data.state)&lt;br /&gt;
		:cssText(data.style)&lt;br /&gt;
&lt;br /&gt;
	--title bar&lt;br /&gt;
	if data.title then&lt;br /&gt;
		local titlebar = navbox:tag(&amp;#039;div&amp;#039;):addClass(CLASS_PREFIX..&amp;#039;title&amp;#039;)&lt;br /&gt;
		titlebar:tag(&amp;#039;div&amp;#039;):addClass(&amp;#039;mw-collapsible-toggle-placeholder&amp;#039;)&lt;br /&gt;
		if data.metaLinks then&lt;br /&gt;
			titlebar:node(h.renderMetaLinks(data.metaLinks))&lt;br /&gt;
		end&lt;br /&gt;
		if data.title then&lt;br /&gt;
			titlebar:addClass(data.title.class):tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
			:addClass(CLASS_PREFIX..&amp;#039;title-text&amp;#039;)&lt;br /&gt;
			:addClass(data.title.class)&lt;br /&gt;
			:cssText(data.title.style)&lt;br /&gt;
			:wikitext(data.title.content)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	--above&lt;br /&gt;
	if data.above then&lt;br /&gt;
		navbox:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
		:addClass(CLASS_PREFIX..&amp;#039;above mw-collapsible-content&amp;#039;)&lt;br /&gt;
		:addClass(data.above.class)&lt;br /&gt;
		:cssText(data.above.style)&lt;br /&gt;
		:wikitext(data.above.content)&lt;br /&gt;
		:attr(&amp;#039;id&amp;#039;, (not data.title) and mw.uri.anchorEncode(data.above.content) or nil) -- id for aria-labelledby attribute, if no title&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- sections&lt;br /&gt;
	if data.sections then&lt;br /&gt;
		h.renderSections(data.sections, navbox, 0, true)&lt;br /&gt;
	else&lt;br /&gt;
		-- Insert a blank section for completely empty navbox to ensure it behaves correctly when collapsed.&lt;br /&gt;
		if not data.above and not data.below then &lt;br /&gt;
			navbox:tag(&amp;#039;div&amp;#039;):addClass(CLASS_PREFIX..&amp;#039;section mw-collapsible-content&amp;#039;)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	--below&lt;br /&gt;
	if data.below then&lt;br /&gt;
		navbox:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
		:addClass(CLASS_PREFIX..&amp;#039;below mw-collapsible-content&amp;#039;)&lt;br /&gt;
		:addClass(data.below.class)&lt;br /&gt;
		:cssText(data.below.style)&lt;br /&gt;
		:wikitext(data.below.content)&lt;br /&gt;
	end&lt;br /&gt;
	return tostring(out)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function h.renderSections(data, container, level, even)&lt;br /&gt;
	for i,sect in ipairs(data) do&lt;br /&gt;
		--section box&lt;br /&gt;
		local section = container:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
			:addClass(CLASS_PREFIX..&amp;#039;section mw-collapsible-content&amp;#039;)&lt;br /&gt;
			:addClass(sect.class)&lt;br /&gt;
			:addClass(sect.state)&lt;br /&gt;
			:cssText(sect.style)&lt;br /&gt;
		-- section header&lt;br /&gt;
		if sect.header then&lt;br /&gt;
			section:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
			:addClass(CLASS_PREFIX..&amp;#039;header&amp;#039;)&lt;br /&gt;
			:addClass(sect.header.class)&lt;br /&gt;
			:cssText(sect.header.style)&lt;br /&gt;
			:tag(&amp;#039;div&amp;#039;):addClass(&amp;#039;mw-collapsible-toggle-placeholder&amp;#039;):done()&lt;br /&gt;
			:tag(&amp;#039;div&amp;#039;):addClass(CLASS_PREFIX..&amp;#039;header-text&amp;#039;):wikitext(sect.header.content)&lt;br /&gt;
		end&lt;br /&gt;
		-- above:&lt;br /&gt;
		if sect.above then&lt;br /&gt;
			section:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
			:addClass(CLASS_PREFIX..&amp;#039;above mw-collapsible-content&amp;#039;)&lt;br /&gt;
			:addClass(sect.above.class)&lt;br /&gt;
			:cssText(sect.above.style)&lt;br /&gt;
			:wikitext(sect.above.content)&lt;br /&gt;
		end&lt;br /&gt;
		-- body: groups&amp;amp;lists&lt;br /&gt;
		local box = section:tag(&amp;#039;div&amp;#039;):addClass(CLASS_PREFIX..&amp;#039;section-body mw-collapsible-content&amp;#039;)&lt;br /&gt;
		even = h.renderBody(sect.body, box, level, (level==0) and true or even) -- reset even status each section&lt;br /&gt;
		-- below:&lt;br /&gt;
		if sect.below then&lt;br /&gt;
			section:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
			:addClass(CLASS_PREFIX..&amp;#039;below mw-collapsible-content&amp;#039;)&lt;br /&gt;
			:addClass(sect.below.class)&lt;br /&gt;
			:cssText(sect.below.style)&lt;br /&gt;
			:wikitext(sect.below.content)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return even&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function h.renderMetaLinks(info)&lt;br /&gt;
	local box = mw.html.create(&amp;#039;span&amp;#039;):addClass(CLASS_PREFIX..&amp;#039;meta&amp;#039;)&lt;br /&gt;
	local meta = box:tag(&amp;#039;span&amp;#039;):addClass(&amp;#039;nv nv-view&amp;#039;)&lt;br /&gt;
	&lt;br /&gt;
	if info.link then &lt;br /&gt;
		meta:wikitext(&amp;#039;[[&amp;#039;..info.link..&amp;#039;|&amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;span&amp;#039;):wikitext(info.text):attr(&amp;#039;title&amp;#039;, info.text):done()&lt;br /&gt;
			:wikitext(&amp;#039;]]&amp;#039;)&lt;br /&gt;
	elseif info.url then&lt;br /&gt;
		meta:wikitext(&amp;#039;[&amp;#039;..info.url..&amp;#039; &amp;#039;)&lt;br /&gt;
			:tag(&amp;#039;span&amp;#039;):wikitext(info.text):attr(&amp;#039;title&amp;#039;, info.text):done()&lt;br /&gt;
			:wikitext(&amp;#039;]&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return box&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function h.renderBody(info, box, level, even)&lt;br /&gt;
	local count = 0&lt;br /&gt;
	for _,v in h.orderedPairs(info) do&lt;br /&gt;
		if v.group or v.list or v.sections then&lt;br /&gt;
			count = count + 1&lt;br /&gt;
			-- row container&lt;br /&gt;
			local row = box:tag(&amp;#039;div&amp;#039;):addClass(CLASS_PREFIX..&amp;#039;row&amp;#039;)&lt;br /&gt;
			-- group cell&lt;br /&gt;
			if v.group or (v.sections and level &amp;gt; 0 and not v.list) then&lt;br /&gt;
				local groupCell = row:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
					:addClass(CLASS_PREFIX..&amp;#039;group level-&amp;#039;..level)&lt;br /&gt;
					:addClass((level &amp;gt; 0) and CLASS_PREFIX..&amp;#039;subgroup&amp;#039; or nil)&lt;br /&gt;
				local groupContentWrap = groupCell:tag(&amp;#039;div&amp;#039;):addClass(CLASS_PREFIX..&amp;#039;wrap&amp;#039;)&lt;br /&gt;
				if v.group then&lt;br /&gt;
					groupCell:addClass(v.group.class):cssText(v.group.style)&lt;br /&gt;
					groupContentWrap:wikitext(v.group.content)&lt;br /&gt;
				else&lt;br /&gt;
					groupCell:addClass(&amp;#039;empty&amp;#039;)&lt;br /&gt;
					row:addClass(&amp;#039;empty-group-list&amp;#039;)&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				row:addClass(&amp;#039;empty-group&amp;#039;)&lt;br /&gt;
			end&lt;br /&gt;
			-- list cell&lt;br /&gt;
			local listCell = row:tag(&amp;#039;div&amp;#039;):addClass(CLASS_PREFIX..&amp;#039;listbox&amp;#039;)&lt;br /&gt;
			if not v.list and not v.sections then&lt;br /&gt;
				listCell:addClass(&amp;#039;empty&amp;#039;)&lt;br /&gt;
				row:addClass(&amp;#039;empty-list&amp;#039;)&lt;br /&gt;
			end&lt;br /&gt;
			if v.list or (v.group and not v.sections) then&lt;br /&gt;
				--listCell:node(h.renderList(v[&amp;#039;list&amp;#039;] or &amp;#039;&amp;#039;, k, level, args))&lt;br /&gt;
				even = not even -- flip even/odd status&lt;br /&gt;
				local cell = listCell:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
				:addClass(CLASS_PREFIX..&amp;#039;wrap&amp;#039;)&lt;br /&gt;
				:addClass(even and CLASS_PREFIX..&amp;#039;even&amp;#039; or CLASS_PREFIX..&amp;#039;odd&amp;#039;)&lt;br /&gt;
				if v.list then&lt;br /&gt;
					cell:addClass(v.list.class):cssText(v.list.style)&lt;br /&gt;
					:tag(&amp;#039;div&amp;#039;):addClass(CLASS_PREFIX..&amp;#039;list&amp;#039;):wikitext(v.list.content)&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			if v.sections then&lt;br /&gt;
				local sublistBox = listCell:tag(&amp;#039;div&amp;#039;):addClass(CLASS_PREFIX..&amp;#039;sublist level-&amp;#039;..level)&lt;br /&gt;
				even = h.renderSections(v.sections, sublistBox, level+1, even)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if count &amp;gt; 0 then&lt;br /&gt;
		box:css(&amp;#039;--count&amp;#039;, count) -- for flex-grow&lt;br /&gt;
	end&lt;br /&gt;
	return even&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- pairs, but sort the keys alphabetically&lt;br /&gt;
function h.orderedPairs(t, f)&lt;br /&gt;
	local a = {}&lt;br /&gt;
	for n in pairs(t) do table.insert(a, n) end&lt;br /&gt;
	table.sort(a, f)&lt;br /&gt;
	local i = 0      -- iterator variable&lt;br /&gt;
	local iter = function ()   -- iterator function&lt;br /&gt;
		i = i + 1&lt;br /&gt;
		if a[i] == nil then return nil&lt;br /&gt;
		else return a[i], t[a[i]]&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return iter&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- For cascading parameters, such as style or class, they are merged in exact order (from general to specific). &lt;br /&gt;
-- Any parameter starting with multiple hyphens(minus signs) will terminate the cascade.&lt;br /&gt;
-- An example:&lt;br /&gt;
-- For group_1.1, its style is affected by parameters |group_1.1_style=... , |subgroup_level_1_style=... , and |subgroup_style=... .&lt;br /&gt;
-- If we have |group_1.1_style= color:red; |subgroup_level_1_style= font-weight: bold; and |subgroup_style= color: green; ,&lt;br /&gt;
-- the style of group_1.1 will be style=&amp;quot;color:green; font-weight: bold; color: red;&amp;quot; ;&lt;br /&gt;
-- if we have |group_1.1_style= -- color:red; |subgroup_level_1_style= font-weight: bold; and |subgroup_style= color: green; ,&lt;br /&gt;
-- the style of group_1.1 will be style=&amp;quot;color: red;&amp;quot; only, and the cascade is no longer performed for |subgroup_level_1_style and |subgroup_style.&lt;br /&gt;
function h.mergeAttrs(...)&lt;br /&gt;
	local trim = mw.text.trim&lt;br /&gt;
	local s = &amp;#039;&amp;#039;&lt;br /&gt;
	for i=1, select(&amp;#039;#&amp;#039;, ...) do&lt;br /&gt;
		local v = trim(select(i, ...) or &amp;#039;&amp;#039;)&lt;br /&gt;
		local str = string.match(v, &amp;#039;^%-%-+(.*)$&amp;#039;)&lt;br /&gt;
		if str then&lt;br /&gt;
			s = trim(str..&amp;#039; &amp;#039;..s)&lt;br /&gt;
			break&lt;br /&gt;
		else&lt;br /&gt;
			s = trim(v..&amp;#039; &amp;#039;..s)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if s == &amp;#039;&amp;#039; then s = nil end&lt;br /&gt;
	return s&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function h.runHook(key, ...)&lt;br /&gt;
	if hooks[key] then&lt;br /&gt;
		hooks[key](...)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-----------------------------------------------&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Stevium</name></author>
	</entry>
</feed>