<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://outwar.info/w/index.php?action=history&amp;feed=atom&amp;title=Module%3AProtection_banner</id>
	<title>Module:Protection banner - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://outwar.info/w/index.php?action=history&amp;feed=atom&amp;title=Module%3AProtection_banner"/>
	<link rel="alternate" type="text/html" href="https://outwar.info/w/index.php?title=Module:Protection_banner&amp;action=history"/>
	<updated>2026-04-03T17:56:09Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.44.3</generator>
	<entry>
		<id>https://outwar.info/w/index.php?title=Module:Protection_banner&amp;diff=107&amp;oldid=prev</id>
		<title>Wangsta thug: 1 revision imported</title>
		<link rel="alternate" type="text/html" href="https://outwar.info/w/index.php?title=Module:Protection_banner&amp;diff=107&amp;oldid=prev"/>
		<updated>2023-07-09T22:27:43Z</updated>

		<summary type="html">&lt;p&gt;1 revision imported&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;-- This module implements {{pp-meta}} and its daughter templates such as&lt;br /&gt;
-- {{pp-dispute}}, {{pp-vandalism}} and {{pp-sock}}.&lt;br /&gt;
&lt;br /&gt;
-- Initialise necessary modules.&lt;br /&gt;
require(&amp;#039;strict&amp;#039;)&lt;br /&gt;
local makeFileLink = require(&amp;#039;Module:File link&amp;#039;)._main&lt;br /&gt;
local effectiveProtectionLevel = require(&amp;#039;Module:Effective protection level&amp;#039;)._main&lt;br /&gt;
local effectiveProtectionExpiry = require(&amp;#039;Module:Effective protection expiry&amp;#039;)._main&lt;br /&gt;
local yesno = require(&amp;#039;Module:Yesno&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
-- Lazily initialise modules and objects we don&amp;#039;t always need.&lt;br /&gt;
local getArgs, makeMessageBox, lang&lt;br /&gt;
&lt;br /&gt;
-- Set constants.&lt;br /&gt;
local CONFIG_MODULE = &amp;#039;Module:Protection banner/config&amp;#039;&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- Helper functions&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local function makeCategoryLink(cat, sort)&lt;br /&gt;
	if cat then&lt;br /&gt;
		return string.format(&lt;br /&gt;
			&amp;#039;[[%s:%s|%s]]&amp;#039;,&lt;br /&gt;
			mw.site.namespaces[14].name,&lt;br /&gt;
			cat,&lt;br /&gt;
			sort&lt;br /&gt;
		)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Validation function for the expiry and the protection date&lt;br /&gt;
local function validateDate(dateString, dateType)&lt;br /&gt;
	if not lang then&lt;br /&gt;
		lang = mw.language.getContentLanguage()&lt;br /&gt;
	end&lt;br /&gt;
	local success, result = pcall(lang.formatDate, lang, &amp;#039;U&amp;#039;, dateString)&lt;br /&gt;
	if success then&lt;br /&gt;
		result = tonumber(result)&lt;br /&gt;
		if result then&lt;br /&gt;
			return result&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	error(string.format(&lt;br /&gt;
		&amp;#039;invalid %s: %s&amp;#039;,&lt;br /&gt;
		dateType,&lt;br /&gt;
		tostring(dateString)&lt;br /&gt;
	), 4)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function makeFullUrl(page, query, display)&lt;br /&gt;
	return string.format(&lt;br /&gt;
		&amp;#039;[%s %s]&amp;#039;,&lt;br /&gt;
		tostring(mw.uri.fullUrl(page, query)),&lt;br /&gt;
		display&lt;br /&gt;
	)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Given a directed graph formatted as node -&amp;gt; table of direct successors,&lt;br /&gt;
-- get a table of all nodes reachable from a given node (though always&lt;br /&gt;
-- including the given node).&lt;br /&gt;
local function getReachableNodes(graph, start)&lt;br /&gt;
	local toWalk, retval = {[start] = true}, {}&lt;br /&gt;
	while true do&lt;br /&gt;
		-- Can&amp;#039;t use pairs() since we&amp;#039;re adding and removing things as we&amp;#039;re iterating&lt;br /&gt;
		local k = next(toWalk) -- This always gets the &amp;quot;first&amp;quot; key&lt;br /&gt;
		if k == nil then&lt;br /&gt;
			return retval&lt;br /&gt;
		end&lt;br /&gt;
		toWalk[k] = nil&lt;br /&gt;
		retval[k] = true&lt;br /&gt;
		for _,v in ipairs(graph[k]) do&lt;br /&gt;
			if not retval[v] then&lt;br /&gt;
				toWalk[v] = true&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- Protection class&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local Protection = {}&lt;br /&gt;
Protection.__index = Protection&lt;br /&gt;
&lt;br /&gt;
Protection.supportedActions = {&lt;br /&gt;
	edit = true,&lt;br /&gt;
	move = true,&lt;br /&gt;
	autoreview = true,&lt;br /&gt;
	upload = true&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Protection.bannerConfigFields = {&lt;br /&gt;
	&amp;#039;text&amp;#039;,&lt;br /&gt;
	&amp;#039;explanation&amp;#039;,&lt;br /&gt;
	&amp;#039;tooltip&amp;#039;,&lt;br /&gt;
	&amp;#039;alt&amp;#039;,&lt;br /&gt;
	&amp;#039;link&amp;#039;,&lt;br /&gt;
	&amp;#039;image&amp;#039;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function Protection.new(args, cfg, title)&lt;br /&gt;
	local obj = {}&lt;br /&gt;
	obj._cfg = cfg&lt;br /&gt;
	obj.title = title or mw.title.getCurrentTitle()&lt;br /&gt;
&lt;br /&gt;
	-- Set action&lt;br /&gt;
	if not args.action then&lt;br /&gt;
		obj.action = &amp;#039;edit&amp;#039;&lt;br /&gt;
	elseif Protection.supportedActions[args.action] then&lt;br /&gt;
		obj.action = args.action&lt;br /&gt;
	else&lt;br /&gt;
		error(string.format(&lt;br /&gt;
			&amp;#039;invalid action: %s&amp;#039;,&lt;br /&gt;
			tostring(args.action)&lt;br /&gt;
		), 3)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Set level&lt;br /&gt;
	obj.level = args.demolevel or effectiveProtectionLevel(obj.action, obj.title)&lt;br /&gt;
	if not obj.level or (obj.action == &amp;#039;move&amp;#039; and obj.level == &amp;#039;autoconfirmed&amp;#039;) then&lt;br /&gt;
		-- Users need to be autoconfirmed to move pages anyway, so treat&lt;br /&gt;
		-- semi-move-protected pages as unprotected.&lt;br /&gt;
		obj.level = &amp;#039;*&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Set expiry&lt;br /&gt;
	local effectiveExpiry = effectiveProtectionExpiry(obj.action, obj.title)&lt;br /&gt;
	if effectiveExpiry == &amp;#039;infinity&amp;#039; then&lt;br /&gt;
		obj.expiry = &amp;#039;indef&amp;#039;&lt;br /&gt;
	elseif effectiveExpiry ~= &amp;#039;unknown&amp;#039; then&lt;br /&gt;
		obj.expiry = validateDate(effectiveExpiry, &amp;#039;expiry date&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Set reason&lt;br /&gt;
	if args[1] then&lt;br /&gt;
		obj.reason = mw.ustring.lower(args[1])&lt;br /&gt;
		if obj.reason:find(&amp;#039;|&amp;#039;) then&lt;br /&gt;
			error(&amp;#039;reasons cannot contain the pipe character (&amp;quot;|&amp;quot;)&amp;#039;, 3)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Set protection date&lt;br /&gt;
	if args.date then&lt;br /&gt;
		obj.protectionDate = validateDate(args.date, &amp;#039;protection date&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- Set banner config&lt;br /&gt;
	do&lt;br /&gt;
		obj.bannerConfig = {}&lt;br /&gt;
		local configTables = {}&lt;br /&gt;
		if cfg.banners[obj.action] then&lt;br /&gt;
			configTables[#configTables + 1] = cfg.banners[obj.action][obj.reason]&lt;br /&gt;
		end&lt;br /&gt;
		if cfg.defaultBanners[obj.action] then&lt;br /&gt;
			configTables[#configTables + 1] = cfg.defaultBanners[obj.action][obj.level]&lt;br /&gt;
			configTables[#configTables + 1] = cfg.defaultBanners[obj.action].default&lt;br /&gt;
		end&lt;br /&gt;
		configTables[#configTables + 1] = cfg.masterBanner&lt;br /&gt;
		for i, field in ipairs(Protection.bannerConfigFields) do&lt;br /&gt;
			for j, t in ipairs(configTables) do&lt;br /&gt;
				if t[field] then&lt;br /&gt;
					obj.bannerConfig[field] = t[field]&lt;br /&gt;
					break&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return setmetatable(obj, Protection)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Protection:isUserScript()&lt;br /&gt;
	-- Whether the page is a user JavaScript or CSS page.&lt;br /&gt;
	local title = self.title&lt;br /&gt;
	return title.namespace == 2 and (&lt;br /&gt;
		title.contentModel == &amp;#039;javascript&amp;#039; or title.contentModel == &amp;#039;css&amp;#039;&lt;br /&gt;
	)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Protection:isProtected()&lt;br /&gt;
	return self.level ~= &amp;#039;*&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Protection:shouldShowLock()&lt;br /&gt;
	-- Whether we should output a banner/padlock&lt;br /&gt;
	return self:isProtected() and not self:isUserScript()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Whether this page needs a protection category.&lt;br /&gt;
Protection.shouldHaveProtectionCategory = Protection.shouldShowLock&lt;br /&gt;
&lt;br /&gt;
function Protection:isTemporary()&lt;br /&gt;
	return type(self.expiry) == &amp;#039;number&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Protection:makeProtectionCategory()&lt;br /&gt;
	if not self:shouldHaveProtectionCategory() then&lt;br /&gt;
		return &amp;#039;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local cfg = self._cfg&lt;br /&gt;
	local title = self.title&lt;br /&gt;
	&lt;br /&gt;
	-- Get the expiry key fragment.&lt;br /&gt;
	local expiryFragment&lt;br /&gt;
	if self.expiry == &amp;#039;indef&amp;#039; then&lt;br /&gt;
		expiryFragment = self.expiry&lt;br /&gt;
	elseif type(self.expiry) == &amp;#039;number&amp;#039; then&lt;br /&gt;
		expiryFragment = &amp;#039;temp&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Get the namespace key fragment.&lt;br /&gt;
	local namespaceFragment = cfg.categoryNamespaceKeys[title.namespace]&lt;br /&gt;
	if not namespaceFragment and title.namespace % 2 == 1 then&lt;br /&gt;
			namespaceFragment = &amp;#039;talk&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Define the order that key fragments are tested in. This is done with an&lt;br /&gt;
	-- array of tables containing the value to be tested, along with its&lt;br /&gt;
	-- position in the cfg.protectionCategories table.&lt;br /&gt;
	local order = {&lt;br /&gt;
		{val = expiryFragment,    keypos = 1},&lt;br /&gt;
		{val = namespaceFragment, keypos = 2},&lt;br /&gt;
		{val = self.reason,       keypos = 3},&lt;br /&gt;
		{val = self.level,        keypos = 4},&lt;br /&gt;
		{val = self.action,       keypos = 5}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	--[[&lt;br /&gt;
	-- The old protection templates used an ad-hoc protection category system,&lt;br /&gt;
	-- with some templates prioritising namespaces in their categories, and&lt;br /&gt;
	-- others prioritising the protection reason. To emulate this in this module&lt;br /&gt;
	-- we use the config table cfg.reasonsWithNamespacePriority to set the&lt;br /&gt;
	-- reasons for which namespaces have priority over protection reason.&lt;br /&gt;
	-- If we are dealing with one of those reasons, move the namespace table to&lt;br /&gt;
	-- the end of the order table, i.e. give it highest priority. If not, the&lt;br /&gt;
	-- reason should have highest priority, so move that to the end of the table&lt;br /&gt;
	-- instead.&lt;br /&gt;
	--]]&lt;br /&gt;
	table.insert(order, table.remove(order, self.reason and cfg.reasonsWithNamespacePriority[self.reason] and 2 or 3))&lt;br /&gt;
 &lt;br /&gt;
	--[[&lt;br /&gt;
	-- Define the attempt order. Inactive subtables (subtables with nil &amp;quot;value&amp;quot;&lt;br /&gt;
	-- fields) are moved to the end, where they will later be given the key&lt;br /&gt;
	-- &amp;quot;all&amp;quot;. This is to cut down on the number of table lookups in&lt;br /&gt;
	-- cfg.protectionCategories, which grows exponentially with the number of&lt;br /&gt;
	-- non-nil keys. We keep track of the number of active subtables with the&lt;br /&gt;
	-- noActive parameter.&lt;br /&gt;
	--]]&lt;br /&gt;
	local noActive, attemptOrder&lt;br /&gt;
	do&lt;br /&gt;
		local active, inactive = {}, {}&lt;br /&gt;
		for i, t in ipairs(order) do&lt;br /&gt;
			if t.val then&lt;br /&gt;
				active[#active + 1] = t&lt;br /&gt;
			else&lt;br /&gt;
				inactive[#inactive + 1] = t&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		noActive = #active&lt;br /&gt;
		attemptOrder = active&lt;br /&gt;
		for i, t in ipairs(inactive) do&lt;br /&gt;
			attemptOrder[#attemptOrder + 1] = t&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
 &lt;br /&gt;
	--[[&lt;br /&gt;
	-- Check increasingly generic key combinations until we find a match. If a&lt;br /&gt;
	-- specific category exists for the combination of key fragments we are&lt;br /&gt;
	-- given, that match will be found first. If not, we keep trying different&lt;br /&gt;
	-- key fragment combinations until we match using the key&lt;br /&gt;
	-- &amp;quot;all-all-all-all-all&amp;quot;.&lt;br /&gt;
	--&lt;br /&gt;
	-- To generate the keys, we index the key subtables using a binary matrix&lt;br /&gt;
	-- with indexes i and j. j is only calculated up to the number of active&lt;br /&gt;
	-- subtables. For example, if there were three active subtables, the matrix&lt;br /&gt;
	-- would look like this, with 0 corresponding to the key fragment &amp;quot;all&amp;quot;, and&lt;br /&gt;
	-- 1 corresponding to other key fragments.&lt;br /&gt;
	-- &lt;br /&gt;
	--   j 1  2  3&lt;br /&gt;
	-- i  &lt;br /&gt;
	-- 1   1  1  1&lt;br /&gt;
	-- 2   0  1  1&lt;br /&gt;
	-- 3   1  0  1&lt;br /&gt;
	-- 4   0  0  1&lt;br /&gt;
	-- 5   1  1  0&lt;br /&gt;
	-- 6   0  1  0&lt;br /&gt;
	-- 7   1  0  0&lt;br /&gt;
	-- 8   0  0  0&lt;br /&gt;
	-- &lt;br /&gt;
	-- Values of j higher than the number of active subtables are set&lt;br /&gt;
	-- to the string &amp;quot;all&amp;quot;.&lt;br /&gt;
	--&lt;br /&gt;
	-- A key for cfg.protectionCategories is constructed for each value of i.&lt;br /&gt;
	-- The position of the value in the key is determined by the keypos field in&lt;br /&gt;
	-- each subtable.&lt;br /&gt;
	--]]&lt;br /&gt;
	local cats = cfg.protectionCategories&lt;br /&gt;
	for i = 1, 2^noActive do&lt;br /&gt;
		local key = {}&lt;br /&gt;
		for j, t in ipairs(attemptOrder) do&lt;br /&gt;
			if j &amp;gt; noActive then&lt;br /&gt;
				key[t.keypos] = &amp;#039;all&amp;#039;&lt;br /&gt;
			else&lt;br /&gt;
				local quotient = i / 2 ^ (j - 1)&lt;br /&gt;
				quotient = math.ceil(quotient)&lt;br /&gt;
				if quotient % 2 == 1 then&lt;br /&gt;
					key[t.keypos] = t.val&lt;br /&gt;
				else&lt;br /&gt;
					key[t.keypos] = &amp;#039;all&amp;#039;&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		key = table.concat(key, &amp;#039;|&amp;#039;)&lt;br /&gt;
		local attempt = cats[key]&lt;br /&gt;
		if attempt then&lt;br /&gt;
			return makeCategoryLink(attempt, title.text)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return &amp;#039;&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Protection:isIncorrect()&lt;br /&gt;
	local expiry = self.expiry&lt;br /&gt;
	return not self:shouldHaveProtectionCategory()&lt;br /&gt;
		or type(expiry) == &amp;#039;number&amp;#039; and expiry &amp;lt; os.time()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Protection:isTemplateProtectedNonTemplate()&lt;br /&gt;
	local action, namespace = self.action, self.title.namespace&lt;br /&gt;
	return self.level == &amp;#039;templateeditor&amp;#039;&lt;br /&gt;
		and (&lt;br /&gt;
			(action ~= &amp;#039;edit&amp;#039; and action ~= &amp;#039;move&amp;#039;)&lt;br /&gt;
			or (namespace ~= 10 and namespace ~= 828)&lt;br /&gt;
		)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Protection:makeCategoryLinks()&lt;br /&gt;
	local msg = self._cfg.msg&lt;br /&gt;
	local ret = {self:makeProtectionCategory()}&lt;br /&gt;
	if self:isIncorrect() then&lt;br /&gt;
		ret[#ret + 1] = makeCategoryLink(&lt;br /&gt;
			msg[&amp;#039;tracking-category-incorrect&amp;#039;],&lt;br /&gt;
			self.title.text&lt;br /&gt;
		)&lt;br /&gt;
	end&lt;br /&gt;
	if self:isTemplateProtectedNonTemplate() then&lt;br /&gt;
		ret[#ret + 1] = makeCategoryLink(&lt;br /&gt;
			msg[&amp;#039;tracking-category-template&amp;#039;],&lt;br /&gt;
			self.title.text&lt;br /&gt;
		)&lt;br /&gt;
	end&lt;br /&gt;
	return table.concat(ret)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- Blurb class&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local Blurb = {}&lt;br /&gt;
Blurb.__index = Blurb&lt;br /&gt;
&lt;br /&gt;
Blurb.bannerTextFields = {&lt;br /&gt;
	text = true,&lt;br /&gt;
	explanation = true,&lt;br /&gt;
	tooltip = true,&lt;br /&gt;
	alt = true,&lt;br /&gt;
	link = true&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function Blurb.new(protectionObj, args, cfg)&lt;br /&gt;
	return setmetatable({&lt;br /&gt;
		_cfg = cfg,&lt;br /&gt;
		_protectionObj = protectionObj,&lt;br /&gt;
		_args = args&lt;br /&gt;
	}, Blurb)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Private methods --&lt;br /&gt;
&lt;br /&gt;
function Blurb:_formatDate(num)&lt;br /&gt;
	-- Formats a Unix timestamp into dd Month, YYYY format.&lt;br /&gt;
	lang = lang or mw.language.getContentLanguage()&lt;br /&gt;
	local success, date = pcall(&lt;br /&gt;
		lang.formatDate,&lt;br /&gt;
		lang,&lt;br /&gt;
		self._cfg.msg[&amp;#039;expiry-date-format&amp;#039;] or &amp;#039;j F Y&amp;#039;,&lt;br /&gt;
		&amp;#039;@&amp;#039; .. tostring(num)&lt;br /&gt;
	)&lt;br /&gt;
	if success then&lt;br /&gt;
		return date&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Blurb:_getExpandedMessage(msgKey)&lt;br /&gt;
	return self:_substituteParameters(self._cfg.msg[msgKey])&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Blurb:_substituteParameters(msg)&lt;br /&gt;
	if not self._params then&lt;br /&gt;
		local parameterFuncs = {}&lt;br /&gt;
&lt;br /&gt;
		parameterFuncs.CURRENTVERSION     = self._makeCurrentVersionParameter&lt;br /&gt;
		parameterFuncs.EDITREQUEST        = self._makeEditRequestParameter&lt;br /&gt;
		parameterFuncs.EXPIRY             = self._makeExpiryParameter&lt;br /&gt;
		parameterFuncs.EXPLANATIONBLURB   = self._makeExplanationBlurbParameter&lt;br /&gt;
		parameterFuncs.IMAGELINK          = self._makeImageLinkParameter&lt;br /&gt;
		parameterFuncs.INTROBLURB         = self._makeIntroBlurbParameter&lt;br /&gt;
		parameterFuncs.INTROFRAGMENT      = self._makeIntroFragmentParameter&lt;br /&gt;
		parameterFuncs.PAGETYPE           = self._makePagetypeParameter&lt;br /&gt;
		parameterFuncs.PROTECTIONBLURB    = self._makeProtectionBlurbParameter&lt;br /&gt;
		parameterFuncs.PROTECTIONDATE     = self._makeProtectionDateParameter&lt;br /&gt;
		parameterFuncs.PROTECTIONLEVEL    = self._makeProtectionLevelParameter&lt;br /&gt;
		parameterFuncs.PROTECTIONLOG      = self._makeProtectionLogParameter&lt;br /&gt;
		parameterFuncs.TALKPAGE           = self._makeTalkPageParameter&lt;br /&gt;
		parameterFuncs.TOOLTIPBLURB       = self._makeTooltipBlurbParameter&lt;br /&gt;
		parameterFuncs.TOOLTIPFRAGMENT    = self._makeTooltipFragmentParameter&lt;br /&gt;
		parameterFuncs.VANDAL             = self._makeVandalTemplateParameter&lt;br /&gt;
		&lt;br /&gt;
		self._params = setmetatable({}, {&lt;br /&gt;
			__index = function (t, k)&lt;br /&gt;
				local param&lt;br /&gt;
				if parameterFuncs[k] then&lt;br /&gt;
					param = parameterFuncs[k](self)&lt;br /&gt;
				end&lt;br /&gt;
				param = param or &amp;#039;&amp;#039;&lt;br /&gt;
				t[k] = param&lt;br /&gt;
				return param&lt;br /&gt;
			end&lt;br /&gt;
		})&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	msg = msg:gsub(&amp;#039;${(%u+)}&amp;#039;, self._params)&lt;br /&gt;
	return msg&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Blurb:_makeCurrentVersionParameter()&lt;br /&gt;
	-- A link to the page history or the move log, depending on the kind of&lt;br /&gt;
	-- protection.&lt;br /&gt;
	local pagename = self._protectionObj.title.prefixedText&lt;br /&gt;
	if self._protectionObj.action == &amp;#039;move&amp;#039; then&lt;br /&gt;
		-- We need the move log link.&lt;br /&gt;
		return makeFullUrl(&lt;br /&gt;
			&amp;#039;Special:Log&amp;#039;,&lt;br /&gt;
			{type = &amp;#039;move&amp;#039;, page = pagename},&lt;br /&gt;
			self:_getExpandedMessage(&amp;#039;current-version-move-display&amp;#039;)&lt;br /&gt;
		)&lt;br /&gt;
	else&lt;br /&gt;
		-- We need the history link.&lt;br /&gt;
		return makeFullUrl(&lt;br /&gt;
			pagename,&lt;br /&gt;
			{action = &amp;#039;history&amp;#039;},&lt;br /&gt;
			self:_getExpandedMessage(&amp;#039;current-version-edit-display&amp;#039;)&lt;br /&gt;
		)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Blurb:_makeEditRequestParameter()&lt;br /&gt;
	local mEditRequest = require(&amp;#039;Module:Submit an edit request&amp;#039;)&lt;br /&gt;
	local action = self._protectionObj.action&lt;br /&gt;
	local level = self._protectionObj.level&lt;br /&gt;
	&lt;br /&gt;
	-- Get the edit request type.&lt;br /&gt;
	local requestType&lt;br /&gt;
	if action == &amp;#039;edit&amp;#039; then&lt;br /&gt;
		if level == &amp;#039;autoconfirmed&amp;#039; then&lt;br /&gt;
			requestType = &amp;#039;semi&amp;#039;&lt;br /&gt;
		elseif level == &amp;#039;extendedconfirmed&amp;#039; then&lt;br /&gt;
			requestType = &amp;#039;extended&amp;#039;&lt;br /&gt;
		elseif level == &amp;#039;templateeditor&amp;#039; then&lt;br /&gt;
			requestType = &amp;#039;template&amp;#039;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	requestType = requestType or &amp;#039;full&amp;#039;&lt;br /&gt;
	&lt;br /&gt;
	-- Get the display value.&lt;br /&gt;
	local display = self:_getExpandedMessage(&amp;#039;edit-request-display&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
	return mEditRequest._link{type = requestType, display = display}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Blurb:_makeExpiryParameter()&lt;br /&gt;
	local expiry = self._protectionObj.expiry&lt;br /&gt;
	if type(expiry) == &amp;#039;number&amp;#039; then&lt;br /&gt;
		return self:_formatDate(expiry)&lt;br /&gt;
	else&lt;br /&gt;
		return expiry&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Blurb:_makeExplanationBlurbParameter()&lt;br /&gt;
	-- Cover special cases first.&lt;br /&gt;
	if self._protectionObj.title.namespace == 8 then&lt;br /&gt;
		-- MediaWiki namespace&lt;br /&gt;
		return self:_getExpandedMessage(&amp;#039;explanation-blurb-nounprotect&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Get explanation blurb table keys&lt;br /&gt;
	local action = self._protectionObj.action&lt;br /&gt;
	local level = self._protectionObj.level&lt;br /&gt;
	local talkKey = self._protectionObj.title.isTalkPage and &amp;#039;talk&amp;#039; or &amp;#039;subject&amp;#039;&lt;br /&gt;
&lt;br /&gt;
	-- Find the message in the explanation blurb table and substitute any&lt;br /&gt;
	-- parameters.&lt;br /&gt;
	local explanations = self._cfg.explanationBlurbs&lt;br /&gt;
	local msg&lt;br /&gt;
	if explanations[action][level] and explanations[action][level][talkKey] then&lt;br /&gt;
		msg = explanations[action][level][talkKey]&lt;br /&gt;
	elseif explanations[action][level] and explanations[action][level].default then&lt;br /&gt;
		msg = explanations[action][level].default&lt;br /&gt;
	elseif explanations[action].default and explanations[action].default[talkKey] then&lt;br /&gt;
		msg = explanations[action].default[talkKey]&lt;br /&gt;
	elseif explanations[action].default and explanations[action].default.default then&lt;br /&gt;
		msg = explanations[action].default.default&lt;br /&gt;
	else&lt;br /&gt;
		error(string.format(&lt;br /&gt;
			&amp;#039;could not find explanation blurb for action &amp;quot;%s&amp;quot;, level &amp;quot;%s&amp;quot; and talk key &amp;quot;%s&amp;quot;&amp;#039;,&lt;br /&gt;
			action,&lt;br /&gt;
			level,&lt;br /&gt;
			talkKey&lt;br /&gt;
		), 8)&lt;br /&gt;
	end&lt;br /&gt;
	return self:_substituteParameters(msg)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Blurb:_makeImageLinkParameter()&lt;br /&gt;
	local imageLinks = self._cfg.imageLinks&lt;br /&gt;
	local action = self._protectionObj.action&lt;br /&gt;
	local level = self._protectionObj.level&lt;br /&gt;
	local msg&lt;br /&gt;
	if imageLinks[action][level] then&lt;br /&gt;
		msg = imageLinks[action][level]&lt;br /&gt;
	elseif imageLinks[action].default then&lt;br /&gt;
		msg = imageLinks[action].default&lt;br /&gt;
	else&lt;br /&gt;
		msg = imageLinks.edit.default&lt;br /&gt;
	end&lt;br /&gt;
	return self:_substituteParameters(msg)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Blurb:_makeIntroBlurbParameter()&lt;br /&gt;
	if self._protectionObj:isTemporary() then&lt;br /&gt;
		return self:_getExpandedMessage(&amp;#039;intro-blurb-expiry&amp;#039;)&lt;br /&gt;
	else&lt;br /&gt;
		return self:_getExpandedMessage(&amp;#039;intro-blurb-noexpiry&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Blurb:_makeIntroFragmentParameter()&lt;br /&gt;
	if self._protectionObj:isTemporary() then&lt;br /&gt;
		return self:_getExpandedMessage(&amp;#039;intro-fragment-expiry&amp;#039;)&lt;br /&gt;
	else&lt;br /&gt;
		return self:_getExpandedMessage(&amp;#039;intro-fragment-noexpiry&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Blurb:_makePagetypeParameter()&lt;br /&gt;
	local pagetypes = self._cfg.pagetypes&lt;br /&gt;
	return pagetypes[self._protectionObj.title.namespace]&lt;br /&gt;
		or pagetypes.default&lt;br /&gt;
		or error(&amp;#039;no default pagetype defined&amp;#039;, 8)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Blurb:_makeProtectionBlurbParameter()&lt;br /&gt;
	local protectionBlurbs = self._cfg.protectionBlurbs&lt;br /&gt;
	local action = self._protectionObj.action&lt;br /&gt;
	local level = self._protectionObj.level&lt;br /&gt;
	local msg&lt;br /&gt;
	if protectionBlurbs[action][level] then&lt;br /&gt;
		msg = protectionBlurbs[action][level]&lt;br /&gt;
	elseif protectionBlurbs[action].default then&lt;br /&gt;
		msg = protectionBlurbs[action].default&lt;br /&gt;
	elseif protectionBlurbs.edit.default then&lt;br /&gt;
		msg = protectionBlurbs.edit.default&lt;br /&gt;
	else&lt;br /&gt;
		error(&amp;#039;no protection blurb defined for protectionBlurbs.edit.default&amp;#039;, 8)&lt;br /&gt;
	end&lt;br /&gt;
	return self:_substituteParameters(msg)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Blurb:_makeProtectionDateParameter()&lt;br /&gt;
	local protectionDate = self._protectionObj.protectionDate&lt;br /&gt;
	if type(protectionDate) == &amp;#039;number&amp;#039; then&lt;br /&gt;
		return self:_formatDate(protectionDate)&lt;br /&gt;
	else&lt;br /&gt;
		return protectionDate&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Blurb:_makeProtectionLevelParameter()&lt;br /&gt;
	local protectionLevels = self._cfg.protectionLevels&lt;br /&gt;
	local action = self._protectionObj.action&lt;br /&gt;
	local level = self._protectionObj.level&lt;br /&gt;
	local msg&lt;br /&gt;
	if protectionLevels[action][level] then&lt;br /&gt;
		msg = protectionLevels[action][level]&lt;br /&gt;
	elseif protectionLevels[action].default then&lt;br /&gt;
		msg = protectionLevels[action].default&lt;br /&gt;
	elseif protectionLevels.edit.default then&lt;br /&gt;
		msg = protectionLevels.edit.default&lt;br /&gt;
	else&lt;br /&gt;
		error(&amp;#039;no protection level defined for protectionLevels.edit.default&amp;#039;, 8)&lt;br /&gt;
	end&lt;br /&gt;
	return self:_substituteParameters(msg)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Blurb:_makeProtectionLogParameter()&lt;br /&gt;
	local pagename = self._protectionObj.title.prefixedText&lt;br /&gt;
	if self._protectionObj.action == &amp;#039;autoreview&amp;#039; then&lt;br /&gt;
		-- We need the pending changes log.&lt;br /&gt;
		return makeFullUrl(&lt;br /&gt;
			&amp;#039;Special:Log&amp;#039;,&lt;br /&gt;
			{type = &amp;#039;stable&amp;#039;, page = pagename},&lt;br /&gt;
			self:_getExpandedMessage(&amp;#039;pc-log-display&amp;#039;)&lt;br /&gt;
		)&lt;br /&gt;
	else&lt;br /&gt;
		-- We need the protection log.&lt;br /&gt;
		return makeFullUrl(&lt;br /&gt;
			&amp;#039;Special:Log&amp;#039;,&lt;br /&gt;
			{type = &amp;#039;protect&amp;#039;, page = pagename},&lt;br /&gt;
			self:_getExpandedMessage(&amp;#039;protection-log-display&amp;#039;)&lt;br /&gt;
		)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Blurb:_makeTalkPageParameter()&lt;br /&gt;
	return string.format(&lt;br /&gt;
		&amp;#039;[[%s:%s#%s|%s]]&amp;#039;,&lt;br /&gt;
		mw.site.namespaces[self._protectionObj.title.namespace].talk.name,&lt;br /&gt;
		self._protectionObj.title.text,&lt;br /&gt;
		self._args.section or &amp;#039;top&amp;#039;,&lt;br /&gt;
		self:_getExpandedMessage(&amp;#039;talk-page-link-display&amp;#039;)&lt;br /&gt;
	)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Blurb:_makeTooltipBlurbParameter()&lt;br /&gt;
	if self._protectionObj:isTemporary() then&lt;br /&gt;
		return self:_getExpandedMessage(&amp;#039;tooltip-blurb-expiry&amp;#039;)&lt;br /&gt;
	else&lt;br /&gt;
		return self:_getExpandedMessage(&amp;#039;tooltip-blurb-noexpiry&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Blurb:_makeTooltipFragmentParameter()&lt;br /&gt;
	if self._protectionObj:isTemporary() then&lt;br /&gt;
		return self:_getExpandedMessage(&amp;#039;tooltip-fragment-expiry&amp;#039;)&lt;br /&gt;
	else&lt;br /&gt;
		return self:_getExpandedMessage(&amp;#039;tooltip-fragment-noexpiry&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Blurb:_makeVandalTemplateParameter()&lt;br /&gt;
	return mw.getCurrentFrame():expandTemplate{&lt;br /&gt;
		title=&amp;quot;vandal-m&amp;quot;,&lt;br /&gt;
		args={self._args.user or self._protectionObj.title.baseText}&lt;br /&gt;
	}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Public methods --&lt;br /&gt;
&lt;br /&gt;
function Blurb:makeBannerText(key)&lt;br /&gt;
	-- Validate input.&lt;br /&gt;
	if not key or not Blurb.bannerTextFields[key] then&lt;br /&gt;
		error(string.format(&lt;br /&gt;
			&amp;#039;&amp;quot;%s&amp;quot; is not a valid banner config field&amp;#039;,&lt;br /&gt;
			tostring(key)&lt;br /&gt;
		), 2)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Generate the text.&lt;br /&gt;
	local msg = self._protectionObj.bannerConfig[key]&lt;br /&gt;
	if type(msg) == &amp;#039;string&amp;#039; then&lt;br /&gt;
		return self:_substituteParameters(msg)&lt;br /&gt;
	elseif type(msg) == &amp;#039;function&amp;#039; then&lt;br /&gt;
		msg = msg(self._protectionObj, self._args)&lt;br /&gt;
		if type(msg) ~= &amp;#039;string&amp;#039; then&lt;br /&gt;
			error(string.format(&lt;br /&gt;
				&amp;#039;bad output from banner config function with key &amp;quot;%s&amp;quot;&amp;#039;&lt;br /&gt;
					.. &amp;#039; (expected string, got %s)&amp;#039;,&lt;br /&gt;
				tostring(key),&lt;br /&gt;
				type(msg)&lt;br /&gt;
			), 4)&lt;br /&gt;
		end&lt;br /&gt;
		return self:_substituteParameters(msg)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- BannerTemplate class&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local BannerTemplate = {}&lt;br /&gt;
BannerTemplate.__index = BannerTemplate&lt;br /&gt;
&lt;br /&gt;
function BannerTemplate.new(protectionObj, cfg)&lt;br /&gt;
	local obj = {}&lt;br /&gt;
	obj._cfg = cfg&lt;br /&gt;
&lt;br /&gt;
	-- Set the image filename.&lt;br /&gt;
	local imageFilename = protectionObj.bannerConfig.image&lt;br /&gt;
	if imageFilename then&lt;br /&gt;
		obj._imageFilename = imageFilename&lt;br /&gt;
	else&lt;br /&gt;
		-- If an image filename isn&amp;#039;t specified explicitly in the banner config,&lt;br /&gt;
		-- generate it from the protection status and the namespace.&lt;br /&gt;
		local action = protectionObj.action&lt;br /&gt;
		local level = protectionObj.level&lt;br /&gt;
		local namespace = protectionObj.title.namespace&lt;br /&gt;
		local reason = protectionObj.reason&lt;br /&gt;
		&lt;br /&gt;
		-- Deal with special cases first.&lt;br /&gt;
		if (&lt;br /&gt;
			namespace == 10&lt;br /&gt;
			or namespace == 828&lt;br /&gt;
			or reason and obj._cfg.indefImageReasons[reason]&lt;br /&gt;
			)&lt;br /&gt;
			and action == &amp;#039;edit&amp;#039;&lt;br /&gt;
			and level == &amp;#039;sysop&amp;#039;&lt;br /&gt;
			and not protectionObj:isTemporary()&lt;br /&gt;
		then&lt;br /&gt;
			-- Fully protected modules and templates get the special red &amp;quot;indef&amp;quot;&lt;br /&gt;
			-- padlock.&lt;br /&gt;
			obj._imageFilename = obj._cfg.msg[&amp;#039;image-filename-indef&amp;#039;]&lt;br /&gt;
		else&lt;br /&gt;
			-- Deal with regular protection types.&lt;br /&gt;
			local images = obj._cfg.images&lt;br /&gt;
			if images[action] then&lt;br /&gt;
				if images[action][level] then&lt;br /&gt;
					obj._imageFilename = images[action][level]&lt;br /&gt;
				elseif images[action].default then&lt;br /&gt;
					obj._imageFilename = images[action].default&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return setmetatable(obj, BannerTemplate)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function BannerTemplate:renderImage()&lt;br /&gt;
	local filename = self._imageFilename&lt;br /&gt;
		or self._cfg.msg[&amp;#039;image-filename-default&amp;#039;]&lt;br /&gt;
		or &amp;#039;Transparent.gif&amp;#039;&lt;br /&gt;
	return makeFileLink{&lt;br /&gt;
		file = filename,&lt;br /&gt;
		size = (self.imageWidth or 20) .. &amp;#039;px&amp;#039;,&lt;br /&gt;
		alt = self._imageAlt,&lt;br /&gt;
		link = self._imageLink,&lt;br /&gt;
		caption = self.imageCaption&lt;br /&gt;
	}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- Banner class&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local Banner = setmetatable({}, BannerTemplate)&lt;br /&gt;
Banner.__index = Banner&lt;br /&gt;
&lt;br /&gt;
function Banner.new(protectionObj, blurbObj, cfg)&lt;br /&gt;
	local obj = BannerTemplate.new(protectionObj, cfg) -- This doesn&amp;#039;t need the blurb.&lt;br /&gt;
	obj.imageWidth = 40&lt;br /&gt;
	obj.imageCaption = blurbObj:makeBannerText(&amp;#039;alt&amp;#039;) -- Large banners use the alt text for the tooltip.&lt;br /&gt;
	obj._reasonText = blurbObj:makeBannerText(&amp;#039;text&amp;#039;)&lt;br /&gt;
	obj._explanationText = blurbObj:makeBannerText(&amp;#039;explanation&amp;#039;)&lt;br /&gt;
	obj._page = protectionObj.title.prefixedText -- Only makes a difference in testing.&lt;br /&gt;
	return setmetatable(obj, Banner)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Banner:__tostring()&lt;br /&gt;
	-- Renders the banner.&lt;br /&gt;
	makeMessageBox = makeMessageBox or require(&amp;#039;Module:Message box&amp;#039;).main&lt;br /&gt;
	local reasonText = self._reasonText or error(&amp;#039;no reason text set&amp;#039;, 2)&lt;br /&gt;
	local explanationText = self._explanationText&lt;br /&gt;
	local mbargs = {&lt;br /&gt;
		page = self._page,&lt;br /&gt;
		type = &amp;#039;protection&amp;#039;,&lt;br /&gt;
		image = self:renderImage(),&lt;br /&gt;
		text = string.format(&lt;br /&gt;
			&amp;quot;&amp;#039;&amp;#039;&amp;#039;%s&amp;#039;&amp;#039;&amp;#039;%s&amp;quot;,&lt;br /&gt;
			reasonText,&lt;br /&gt;
			explanationText and &amp;#039;&amp;lt;br /&amp;gt;&amp;#039; .. explanationText or &amp;#039;&amp;#039;&lt;br /&gt;
		)&lt;br /&gt;
	}&lt;br /&gt;
	return makeMessageBox(&amp;#039;mbox&amp;#039;, mbargs)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- Padlock class&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local Padlock = setmetatable({}, BannerTemplate)&lt;br /&gt;
Padlock.__index = Padlock&lt;br /&gt;
&lt;br /&gt;
function Padlock.new(protectionObj, blurbObj, cfg)&lt;br /&gt;
	local obj = BannerTemplate.new(protectionObj, cfg) -- This doesn&amp;#039;t need the blurb.&lt;br /&gt;
	obj.imageWidth = 20&lt;br /&gt;
	obj.imageCaption = blurbObj:makeBannerText(&amp;#039;tooltip&amp;#039;)&lt;br /&gt;
	obj._imageAlt = blurbObj:makeBannerText(&amp;#039;alt&amp;#039;)&lt;br /&gt;
	obj._imageLink = blurbObj:makeBannerText(&amp;#039;link&amp;#039;)&lt;br /&gt;
	obj._indicatorName = cfg.padlockIndicatorNames[protectionObj.action]&lt;br /&gt;
		or cfg.padlockIndicatorNames.default&lt;br /&gt;
		or &amp;#039;pp-default&amp;#039;&lt;br /&gt;
	return setmetatable(obj, Padlock)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Padlock:__tostring()&lt;br /&gt;
	local frame = mw.getCurrentFrame()&lt;br /&gt;
	-- The nowiki tag helps prevent whitespace at the top of articles.&lt;br /&gt;
	return frame:extensionTag{name = &amp;#039;nowiki&amp;#039;} .. frame:extensionTag{&lt;br /&gt;
		name = &amp;#039;indicator&amp;#039;,&lt;br /&gt;
		args = {name = self._indicatorName},&lt;br /&gt;
		content = self:renderImage()&lt;br /&gt;
	}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
-- Exports&lt;br /&gt;
--------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
function p._exportClasses()&lt;br /&gt;
	-- This is used for testing purposes.&lt;br /&gt;
	return {&lt;br /&gt;
		Protection = Protection,&lt;br /&gt;
		Blurb = Blurb,&lt;br /&gt;
		BannerTemplate = BannerTemplate,&lt;br /&gt;
		Banner = Banner,&lt;br /&gt;
		Padlock = Padlock,&lt;br /&gt;
	}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._main(args, cfg, title)&lt;br /&gt;
	args = args or {}&lt;br /&gt;
	cfg = cfg or require(CONFIG_MODULE)&lt;br /&gt;
&lt;br /&gt;
	local protectionObj = Protection.new(args, cfg, title)&lt;br /&gt;
&lt;br /&gt;
	local ret = {}&lt;br /&gt;
&lt;br /&gt;
	-- If a page&amp;#039;s edit protection is equally or more restrictive than its&lt;br /&gt;
	-- protection from some other action, then don&amp;#039;t bother displaying anything&lt;br /&gt;
	-- for the other action (except categories).&lt;br /&gt;
	if not yesno(args.catonly) and (protectionObj.action == &amp;#039;edit&amp;#039; or&lt;br /&gt;
		args.demolevel or&lt;br /&gt;
		not getReachableNodes(&lt;br /&gt;
			cfg.hierarchy,&lt;br /&gt;
			protectionObj.level&lt;br /&gt;
		)[effectiveProtectionLevel(&amp;#039;edit&amp;#039;, protectionObj.title)])&lt;br /&gt;
	then&lt;br /&gt;
		-- Initialise the blurb object&lt;br /&gt;
		local blurbObj = Blurb.new(protectionObj, args, cfg)&lt;br /&gt;
	&lt;br /&gt;
		-- Render the banner&lt;br /&gt;
		if protectionObj:shouldShowLock() then&lt;br /&gt;
			ret[#ret + 1] = tostring(&lt;br /&gt;
				(yesno(args.small) and Padlock or Banner)&lt;br /&gt;
				.new(protectionObj, blurbObj, cfg)&lt;br /&gt;
			)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Render the categories&lt;br /&gt;
	if yesno(args.category) ~= false then&lt;br /&gt;
		ret[#ret + 1] = protectionObj:makeCategoryLinks()&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return table.concat(ret)	&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.main(frame, cfg)&lt;br /&gt;
	cfg = cfg or require(CONFIG_MODULE)&lt;br /&gt;
&lt;br /&gt;
	-- Find default args, if any.&lt;br /&gt;
	local parent = frame.getParent and frame:getParent()&lt;br /&gt;
	local defaultArgs = parent and cfg.wrappers[parent:getTitle():gsub(&amp;#039;/sandbox$&amp;#039;, &amp;#039;&amp;#039;)]&lt;br /&gt;
&lt;br /&gt;
	-- Find user args, and use the parent frame if we are being called from a&lt;br /&gt;
	-- wrapper template.&lt;br /&gt;
	getArgs = getArgs or require(&amp;#039;Module:Arguments&amp;#039;).getArgs&lt;br /&gt;
	local userArgs = getArgs(frame, {&lt;br /&gt;
		parentOnly = defaultArgs,&lt;br /&gt;
		frameOnly = not defaultArgs&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	-- Build the args table. User-specified args overwrite default args.&lt;br /&gt;
	local args = {}&lt;br /&gt;
	for k, v in pairs(defaultArgs or {}) do&lt;br /&gt;
		args[k] = v&lt;br /&gt;
	end&lt;br /&gt;
	for k, v in pairs(userArgs) do&lt;br /&gt;
		args[k] = v&lt;br /&gt;
	end&lt;br /&gt;
	return p._main(args, cfg)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Wangsta thug</name></author>
	</entry>
</feed>