<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://stockhub.co/index.php?action=history&amp;feed=atom&amp;title=Module%3ARfx%2Fsandbox</id>
	<title>Module:Rfx/sandbox - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://stockhub.co/index.php?action=history&amp;feed=atom&amp;title=Module%3ARfx%2Fsandbox"/>
	<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Rfx/sandbox&amp;action=history"/>
	<updated>2026-05-28T11:13:43Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://stockhub.co/index.php?title=Module:Rfx/sandbox&amp;diff=144672&amp;oldid=prev</id>
		<title>imported&gt;Mr. Stradivarius: use makePagePattern with getOpenRfxes</title>
		<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Rfx/sandbox&amp;diff=144672&amp;oldid=prev"/>
		<updated>2016-02-04T06:56:53Z</updated>

		<summary type="html">&lt;p&gt;use makePagePattern with getOpenRfxes&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;----------------------------------------------------------------------&lt;br /&gt;
--                          Module:Rfx                              --&lt;br /&gt;
-- This is a library for retrieving information about requests      --&lt;br /&gt;
-- for adminship and requests for bureaucratship on the English     --&lt;br /&gt;
-- Wikipedia. Please see the module documentation for instructions. --&lt;br /&gt;
----------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local libraryUtil = require(&amp;#039;libraryUtil&amp;#039;)&lt;br /&gt;
local lang = mw.getContentLanguage()&lt;br /&gt;
local Rfx = {}&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
-- Helper functions&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
-- Helper functions for making page-matching patterns.&lt;br /&gt;
local escapePageName, escapeNamespace, makePagePattern&lt;br /&gt;
do&lt;br /&gt;
	local whitespaceSet = &amp;#039;[ _]&amp;#039;&lt;br /&gt;
	local wsOnePlusPattern = whitespaceSet .. &amp;#039;+&amp;#039;&lt;br /&gt;
	local wsZeroPlusPattern = whitespaceSet .. &amp;#039;*&amp;#039;&lt;br /&gt;
&lt;br /&gt;
	local function makeCaseInsensitive(char)&lt;br /&gt;
		-- Replaces a character with a case-insensitive set.&lt;br /&gt;
		return &amp;#039;[&amp;#039; .. char:upper() .. char:lower() .. &amp;#039;]&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local function escapeSpecialChars(s)&lt;br /&gt;
		-- Escape characters with a special meaning in Lua patterns.&lt;br /&gt;
		s = s:gsub(&amp;#039;[$()%%.%[%]%*+-?^]&amp;#039;, &amp;#039;%%%1&amp;#039;)&lt;br /&gt;
		-- Escape whitespace with a pattern that matches whitespace.&lt;br /&gt;
		s = s:gsub(wsOnePlusPattern, wsOnePlusPattern)&lt;br /&gt;
		return s&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	function escapePageName(s)&lt;br /&gt;
		s = escapeSpecialChars(s):gsub(&amp;#039;^%a&amp;#039;, makeCaseInsensitive)&lt;br /&gt;
		return s&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	function escapeNamespace(s)&lt;br /&gt;
		s = escapeSpecialChars(s):gsub(&amp;#039;%a&amp;#039;, makeCaseInsensitive)&lt;br /&gt;
		return s&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	function makePagePattern(options)&lt;br /&gt;
		local isEscaped = options.escaped ~= false&lt;br /&gt;
		local hasBrackets = options.brackets&lt;br /&gt;
		local hasBraces = options.braces&lt;br /&gt;
		local ret = {}&lt;br /&gt;
		if hasBrackets then&lt;br /&gt;
			table.insert(ret, &amp;#039;%[%[&amp;#039;)&lt;br /&gt;
			table.insert(ret, wsZeroPlusPattern)&lt;br /&gt;
		elseif hasBraces then&lt;br /&gt;
			table.insert(ret, &amp;#039;{{&amp;#039;)&lt;br /&gt;
			table.insert(ret, wsZeroPlusPattern)&lt;br /&gt;
		end&lt;br /&gt;
		if options.namespace then&lt;br /&gt;
			if isEscaped then&lt;br /&gt;
				table.insert(ret, escapeNamespace(options.namespace))&lt;br /&gt;
			else&lt;br /&gt;
				table.insert(ret, options.namespace)&lt;br /&gt;
			end&lt;br /&gt;
			table.insert(ret, wsZeroPlusPattern)&lt;br /&gt;
			table.insert(ret, &amp;#039;:&amp;#039;)&lt;br /&gt;
			table.insert(ret, wsZeroPlusPattern)&lt;br /&gt;
		end&lt;br /&gt;
		if isEscaped then&lt;br /&gt;
			table.insert(ret, escapePageName(options.page))&lt;br /&gt;
		else&lt;br /&gt;
			table.insert(ret, options.page)&lt;br /&gt;
		end&lt;br /&gt;
		if hasBrackets then&lt;br /&gt;
			table.insert(ret, wsZeroPlusPattern)&lt;br /&gt;
			table.insert(ret, &amp;#039;%]%]&amp;#039;)&lt;br /&gt;
		elseif hasBraces then&lt;br /&gt;
			table.insert(ret, wsZeroPlusPattern)&lt;br /&gt;
			table.insert(ret, &amp;#039;}}&amp;#039;)&lt;br /&gt;
		end&lt;br /&gt;
		return table.concat(ret)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function parseVoteBoundaries(section)&lt;br /&gt;
	-- Returns an array containing the raw wikitext of RfX votes in a given section.&lt;br /&gt;
	section = section:match(&amp;#039;^.-\n#(.*)$&amp;#039;) -- Strip non-votes from the start.&lt;br /&gt;
	if not section then&lt;br /&gt;
		return {}&lt;br /&gt;
	end&lt;br /&gt;
	section = section:match(&amp;#039;^(.-)\n[^#]&amp;#039;) or section -- Discard subsequent numbered lists.&lt;br /&gt;
	local comments = mw.text.split(section, &amp;#039;\n#&amp;#039;)&lt;br /&gt;
	local votes = {}&lt;br /&gt;
	for i, comment in ipairs(comments) do&lt;br /&gt;
		if comment:find(&amp;#039;^[^#*;:].*%S&amp;#039;) then&lt;br /&gt;
			votes[#votes + 1] = comment&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return votes&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local parseVote = (function ()&lt;br /&gt;
	local userPattern = makePagePattern{&lt;br /&gt;
		namespace = escapeNamespace(&amp;#039;User&amp;#039;),&lt;br /&gt;
		page = &amp;#039;(.-)&amp;#039;,&lt;br /&gt;
		brackets = true,&lt;br /&gt;
		escaped = false,&lt;br /&gt;
	} .. &amp;#039;.-$&amp;#039;&lt;br /&gt;
	local userTalkPattern = makePagePattern{&lt;br /&gt;
		namespace = escapeNamespace(&amp;#039;User talk&amp;#039;),&lt;br /&gt;
		page = &amp;#039;(.-)&amp;#039;,&lt;br /&gt;
		brackets = true,&lt;br /&gt;
		escaped = false,&lt;br /&gt;
	} .. &amp;#039;.-$&amp;#039;&lt;br /&gt;
	return function (vote)&lt;br /&gt;
		-- parses a username from an RfX vote.&lt;br /&gt;
		local userStart, userEnd, userMatch = vote:find(userPattern)&lt;br /&gt;
		local talkStart, talkEnd, talkMatch = vote:find(userTalkPattern)&lt;br /&gt;
		local username&lt;br /&gt;
		if userStart and talkStart then&lt;br /&gt;
			if userStart &amp;gt; talkStart then&lt;br /&gt;
				username = userMatch&lt;br /&gt;
			else&lt;br /&gt;
				username = talkMatch&lt;br /&gt;
			end&lt;br /&gt;
		elseif userStart then&lt;br /&gt;
			username = userMatch&lt;br /&gt;
		elseif talkStart then&lt;br /&gt;
			username = talkMatch&lt;br /&gt;
		else&lt;br /&gt;
			return string.format( &amp;quot;&amp;#039;&amp;#039;&amp;#039;Error parsing signature&amp;#039;&amp;#039;&amp;#039;: &amp;#039;&amp;#039;%s&amp;#039;&amp;#039;&amp;quot;, vote )&lt;br /&gt;
		end&lt;br /&gt;
		-- Deal with piped links and links like [[User:Example#top]]&lt;br /&gt;
		username = username:match(&amp;#039;^[^|/#]*&amp;#039;)&lt;br /&gt;
		return username&lt;br /&gt;
	end&lt;br /&gt;
end)()&lt;br /&gt;
&lt;br /&gt;
local function parseVoters(votes)&lt;br /&gt;
	local voters = {}&lt;br /&gt;
	for i, vote in ipairs(votes) do&lt;br /&gt;
		voters[#voters + 1] = parseVote(vote)&lt;br /&gt;
	end&lt;br /&gt;
	return voters&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function dupesExist(...)&lt;br /&gt;
	local exists = {}&lt;br /&gt;
	local tables = {...}&lt;br /&gt;
	for i, usernames in ipairs(tables) do&lt;br /&gt;
		for j, username in ipairs(usernames) do&lt;br /&gt;
			username = lang:ucfirst(username)&lt;br /&gt;
			if exists[username] then&lt;br /&gt;
				return true&lt;br /&gt;
			else&lt;br /&gt;
				exists[username] = true&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
-- Rfx library functions&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
function Rfx.getOpenRfxes()&lt;br /&gt;
	-- Return a table with a list of pages transcluded from&lt;br /&gt;
	-- [[Wikipedia:Requests for adminship]], minus the exceptions&lt;br /&gt;
	-- which are always transcluded there.&lt;br /&gt;
	local rfaText = mw.title.new(&amp;#039;Wikipedia:Requests for adminship&amp;#039;):getContent()&lt;br /&gt;
	local ret = {}&lt;br /&gt;
	local exceptions = {&lt;br /&gt;
		[&amp;#039;Front matter&amp;#039;] = true,&lt;br /&gt;
		[&amp;#039;Header&amp;#039;] = true,&lt;br /&gt;
		[&amp;#039;bureaucratship&amp;#039;] = true,&lt;br /&gt;
	}&lt;br /&gt;
	-- Match things like &amp;quot;{{Wikipedia:Requests for adminship/Example}}&amp;quot;&lt;br /&gt;
	local pattern = makePagePattern{&lt;br /&gt;
		namespace = &amp;#039;(&amp;#039; .. escapeNamespace(&amp;#039;Wikipedia&amp;#039;),&lt;br /&gt;
		page = escapePageName(&amp;#039;Requests for &amp;#039;) .. &amp;#039;%a+/[^}]-)&amp;#039;,&lt;br /&gt;
		braces = true,&lt;br /&gt;
		escaped = false,&lt;br /&gt;
	}&lt;br /&gt;
	for page in rfaText:gmatch(pattern) do&lt;br /&gt;
		local title = mw.title.new(page)&lt;br /&gt;
		if not exceptions[title.subpageText] then&lt;br /&gt;
			table.insert(ret, title.prefixedText)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return ret&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
-- Rfx object&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
function Rfx.new(title)&lt;br /&gt;
	local obj = {}&lt;br /&gt;
	local data = {}&lt;br /&gt;
	local checkSelf = libraryUtil.makeCheckSelfFunction( &amp;#039;Module:Rfx&amp;#039;, &amp;#039;rfx&amp;#039;, obj, &amp;#039;rfx object&amp;#039; )&lt;br /&gt;
	&lt;br /&gt;
	-- Get the title object and check to see whether we are a subpage of WP:RFA or WP:RFB.&lt;br /&gt;
	title = mw.title.new(title)&lt;br /&gt;
	if not title then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	function data:getTitleObject()&lt;br /&gt;
		checkSelf(self, &amp;#039;getTitleObject&amp;#039;)&lt;br /&gt;
		return title&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	if title.namespace == 4 then&lt;br /&gt;
		local rootText = title.rootText&lt;br /&gt;
		if rootText == &amp;#039;Requests for adminship&amp;#039; then&lt;br /&gt;
			data.type = &amp;#039;rfa&amp;#039;&lt;br /&gt;
		elseif rootText == &amp;#039;Requests for bureaucratship&amp;#039; then&lt;br /&gt;
			data.type = &amp;#039;rfb&amp;#039;&lt;br /&gt;
		else&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Get the page content and divide it into sections.&lt;br /&gt;
	local pageText = title:getContent()&lt;br /&gt;
	if not pageText then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	local introText, supportText, opposeText, neutralText = mw.ustring.match(&lt;br /&gt;
		pageText,&lt;br /&gt;
		&amp;#039;^(.-)\n====[^=\n][^\n]-====.-&amp;#039;&lt;br /&gt;
		.. &amp;#039;\n=====%s*[sS]upport%s*=====(.-)&amp;#039;&lt;br /&gt;
		.. &amp;#039;\n=====%s*[oO]ppose%s*=====(.-)&amp;#039;&lt;br /&gt;
		.. &amp;#039;\n=====%s*[nN]eutral%s*=====(.-)$&amp;#039;&lt;br /&gt;
	)&lt;br /&gt;
	if not introText then&lt;br /&gt;
		introText, supportText, opposeText, neutralText = mw.ustring.match(&lt;br /&gt;
			pageText,&lt;br /&gt;
			&amp;quot;^(.-\n&amp;#039;&amp;#039;&amp;#039;[^\n]-%(%d+/%d+/%d+%)[^\n]-&amp;#039;&amp;#039;&amp;#039;)\n.-&amp;quot;&lt;br /&gt;
			.. &amp;quot;\n&amp;#039;&amp;#039;&amp;#039;Support&amp;#039;&amp;#039;&amp;#039;(.-)\n&amp;#039;&amp;#039;&amp;#039;Oppose&amp;#039;&amp;#039;&amp;#039;(.-)\n&amp;#039;&amp;#039;&amp;#039;Neutral&amp;#039;&amp;#039;&amp;#039;(.-)&amp;quot;&lt;br /&gt;
		)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Get vote counts.&lt;br /&gt;
	local supportVotes, opposeVotes, neutralVotes&lt;br /&gt;
	if supportText and opposeText and neutralText then&lt;br /&gt;
		supportVotes = parseVoteBoundaries(supportText)&lt;br /&gt;
		opposeVotes = parseVoteBoundaries(opposeText)&lt;br /&gt;
		neutralVotes = parseVoteBoundaries(neutralText)&lt;br /&gt;
	end&lt;br /&gt;
	local supports, opposes, neutrals&lt;br /&gt;
	if supportVotes and opposeVotes and neutralVotes then&lt;br /&gt;
		supports = #supportVotes&lt;br /&gt;
		data.supports = supports&lt;br /&gt;
		opposes = #opposeVotes&lt;br /&gt;
		data.opposes = opposes&lt;br /&gt;
		neutrals = #neutralVotes&lt;br /&gt;
		data.neutrals = neutrals&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Voter methods and dupe check.&lt;br /&gt;
&lt;br /&gt;
	function data:getSupportUsers()&lt;br /&gt;
		checkSelf(self, &amp;#039;getSupportUsers&amp;#039;)&lt;br /&gt;
		if supportVotes then&lt;br /&gt;
			return parseVoters(supportVotes)&lt;br /&gt;
		else&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	function data:getOpposeUsers()&lt;br /&gt;
		checkSelf(self, &amp;#039;getOpposeUsers&amp;#039;)&lt;br /&gt;
		if opposeVotes then&lt;br /&gt;
			return parseVoters(opposeVotes)&lt;br /&gt;
		else&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	function data:getNeutralUsers()&lt;br /&gt;
		checkSelf(self, &amp;#039;getNeutralUsers&amp;#039;)&lt;br /&gt;
		if neutralVotes then&lt;br /&gt;
			return parseVoters(neutralVotes)&lt;br /&gt;
		else&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	function data:dupesExist()&lt;br /&gt;
		checkSelf(self, &amp;#039;dupesExist&amp;#039;)&lt;br /&gt;
		local supportUsers = self:getSupportUsers()&lt;br /&gt;
		local opposeUsers = self:getOpposeUsers()&lt;br /&gt;
		local neutralUsers = self:getNeutralUsers()&lt;br /&gt;
		if not (supportUsers and opposeUsers and neutralUsers) then&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
		return dupesExist(supportUsers, opposeUsers, neutralUsers)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if supports and opposes then&lt;br /&gt;
		local total = supports + opposes&lt;br /&gt;
		if total &amp;lt;= 0 then&lt;br /&gt;
			data.percent = 0&lt;br /&gt;
		else&lt;br /&gt;
			data.percent = math.floor((supports / total * 100) + 0.5)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if introText then&lt;br /&gt;
		data.endTime = mw.ustring.match(introText, &amp;#039;(%d%d:%d%d, %d+ %w+ %d+) %(UTC%)&amp;#039;)&lt;br /&gt;
		data.user = mw.ustring.match(introText, &amp;#039;===%s*%[%[[_%s]*[wW]ikipedia[_%s]*:[_%s]*[rR]equests[_ ]for[_ ]%w+/.-|[_%s]*(.-)[_%s]*%]%][_%s]*===&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- Methods for seconds left and time left.&lt;br /&gt;
	&lt;br /&gt;
	function data:getSecondsLeft()&lt;br /&gt;
		checkSelf(self, &amp;#039;getSecondsLeft&amp;#039;)&lt;br /&gt;
		local endTime = self.endTime&lt;br /&gt;
		if not endTime then&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
		local now = tonumber(lang:formatDate(&amp;quot;U&amp;quot;))&lt;br /&gt;
		local success, endTimeU = pcall(lang.formatDate, lang, &amp;#039;U&amp;#039;, endTime)&lt;br /&gt;
		if not success then&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
		endTimeU = tonumber(endTimeU)&lt;br /&gt;
		if not endTimeU then&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
		local secondsLeft = endTimeU - now&lt;br /&gt;
		if secondsLeft &amp;lt;= 0 then&lt;br /&gt;
			return 0&lt;br /&gt;
		else&lt;br /&gt;
			return secondsLeft&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	function data:getTimeLeft()&lt;br /&gt;
		checkSelf(self, &amp;#039;getTimeLeft&amp;#039;)&lt;br /&gt;
		local secondsLeft = self:getSecondsLeft()&lt;br /&gt;
		if not secondsLeft then&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
		return mw.ustring.gsub(lang:formatDuration(secondsLeft, {&amp;#039;days&amp;#039;, &amp;#039;hours&amp;#039;}), &amp;#039; and&amp;#039;, &amp;#039;,&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	function data:getReport()&lt;br /&gt;
		-- Gets the URI object for X!&amp;#039;s RfA Analysis tool&lt;br /&gt;
		checkSelf(self, &amp;#039;getReport&amp;#039;)&lt;br /&gt;
		return mw.uri.new(&amp;#039;//tools.wmflabs.org/xtools/rfa/?p=&amp;#039; .. mw.uri.encode(title.prefixedText))&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	function data:getStatus()&lt;br /&gt;
		-- Gets the current status of the RfX. Returns either &amp;quot;successful&amp;quot;, &amp;quot;unsuccessful&amp;quot;,&lt;br /&gt;
		-- &amp;quot;open&amp;quot;, or &amp;quot;pending closure&amp;quot;. Returns nil if the status could not be found.&lt;br /&gt;
		checkSelf( self, &amp;#039;getStatus&amp;#039; )&lt;br /&gt;
		local rfxType = data.type&lt;br /&gt;
		if rfxType == &amp;#039;rfa&amp;#039; then&lt;br /&gt;
			if mw.ustring.match(&lt;br /&gt;
				pageText,&lt;br /&gt;
				&amp;#039;%[%[[%s_]*[cC][aA][tT][eE][gG][oO][rR][yY][%s_]*:[%s_]*[sS]uccessful requests for adminship(.-)[%s_]*%]%]&amp;#039;&lt;br /&gt;
			) then&lt;br /&gt;
				return &amp;#039;successful&amp;#039;&lt;br /&gt;
			elseif mw.ustring.match(&lt;br /&gt;
				pageText,&lt;br /&gt;
				&amp;#039;%[%[[%s_]*[cC][aA][tT][eE][gG][oO][rR][yY][%s_]*:[%s_]*[uU]nsuccessful requests for adminship(.-)[%s_]*%]%]&amp;#039;&lt;br /&gt;
			) then&lt;br /&gt;
				return &amp;#039;unsuccessful&amp;#039;&lt;br /&gt;
			end&lt;br /&gt;
		elseif rfxType == &amp;#039;rfb&amp;#039; then&lt;br /&gt;
			if mw.ustring.match(&lt;br /&gt;
				pageText,&lt;br /&gt;
				&amp;#039;%[%[[%s_]*[cC][aA][tT][eE][gG][oO][rR][yY][%s_]*:[%s_]*[sS]uccessful requests for bureaucratship(.-)[%s_]*%]%]&amp;#039;&lt;br /&gt;
			) then&lt;br /&gt;
				return &amp;#039;successful&amp;#039;&lt;br /&gt;
			elseif mw.ustring.match(&lt;br /&gt;
				pageText,&lt;br /&gt;
				&amp;#039;%[%[[%s_]*[cC][aA][tT][eE][gG][oO][rR][yY][%s_]*:[%s_]*[uU]nsuccessful requests for bureaucratship(.-)[%s_]*%]%]&amp;#039;&lt;br /&gt;
			) then&lt;br /&gt;
				return &amp;#039;unsuccessful&amp;#039;&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		local secondsLeft = self:getSecondsLeft()&lt;br /&gt;
		if secondsLeft and secondsLeft &amp;gt; 0 then&lt;br /&gt;
			return &amp;#039;open&amp;#039;&lt;br /&gt;
		elseif secondsLeft and secondsLeft &amp;lt;= 0 then&lt;br /&gt;
			return &amp;#039;pending closure&amp;#039;&lt;br /&gt;
		else&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- Specify which fields are read-only, and prepare the metatable.&lt;br /&gt;
	local readOnlyFields = {&lt;br /&gt;
		getTitleObject = true,&lt;br /&gt;
		[&amp;#039;type&amp;#039;] = true,&lt;br /&gt;
		getSupportUsers = true,&lt;br /&gt;
		getOpposeUsers = true,&lt;br /&gt;
		getNeutralUsers = true,&lt;br /&gt;
		supports = true,&lt;br /&gt;
		opposes = true,&lt;br /&gt;
		neutrals = true,&lt;br /&gt;
		endTime = true,&lt;br /&gt;
		percent = true,&lt;br /&gt;
		user = true,&lt;br /&gt;
		dupesExist = true,&lt;br /&gt;
		getSecondsLeft = true,&lt;br /&gt;
		getTimeLeft = true,&lt;br /&gt;
		getReport = true,&lt;br /&gt;
		getStatus = true&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	local function pairsfunc( t, k )&lt;br /&gt;
		local v&lt;br /&gt;
		repeat&lt;br /&gt;
			k = next( readOnlyFields, k )&lt;br /&gt;
			if k == nil then&lt;br /&gt;
				return nil&lt;br /&gt;
			end&lt;br /&gt;
			v = t[k]&lt;br /&gt;
		until v ~= nil&lt;br /&gt;
		return k, v&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return setmetatable( obj, {&lt;br /&gt;
		__pairs = function ( t )&lt;br /&gt;
			return pairsfunc, t, nil&lt;br /&gt;
		end,&lt;br /&gt;
		__index = data,&lt;br /&gt;
		__newindex = function( t, key, value )&lt;br /&gt;
			if readOnlyFields[ key ] then&lt;br /&gt;
				error( &amp;#039;index &amp;quot;&amp;#039; .. key .. &amp;#039;&amp;quot; is read-only&amp;#039;, 2 )&lt;br /&gt;
			else&lt;br /&gt;
				rawset( t, key, value )&lt;br /&gt;
			end&lt;br /&gt;
		end,&lt;br /&gt;
		__tostring = function( t )&lt;br /&gt;
			return t:getTitleObject().prefixedText&lt;br /&gt;
		end&lt;br /&gt;
	} )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return Rfx&lt;/div&gt;</summary>
		<author><name>imported&gt;Mr. Stradivarius</name></author>
	</entry>
</feed>