<?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%3ASignpost_poll</id>
	<title>Module:Signpost poll - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://stockhub.co/index.php?action=history&amp;feed=atom&amp;title=Module%3ASignpost_poll"/>
	<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Signpost_poll&amp;action=history"/>
	<updated>2026-05-24T17:20:02Z</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:Signpost_poll&amp;diff=146790&amp;oldid=prev</id>
		<title>imported&gt;Pppery: Finish replacing module being deleted</title>
		<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Signpost_poll&amp;diff=146790&amp;oldid=prev"/>
		<updated>2019-05-27T16:59:22Z</updated>

		<summary type="html">&lt;p&gt;Finish replacing module being deleted&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;-- This module implements polls used in articles of the Signpost.&lt;br /&gt;
&lt;br /&gt;
local CONFIG_MODULE = &amp;#039;Module:Signpost poll/config&amp;#039;&lt;br /&gt;
&lt;br /&gt;
local yesno = require(&amp;#039;Module:Yesno&amp;#039;)&lt;br /&gt;
local lang = mw.language.getContentLanguage()&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
-- Message method&lt;br /&gt;
-- This method is available in every class, so it is defined separately.&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local function message(self, key, params, isPreprocessed)&lt;br /&gt;
	local msg = self.cfg.msg[key]&lt;br /&gt;
	if params and #params &amp;gt; 0 then&lt;br /&gt;
		msg = mw.message.newRawMessage(msg, params):plain()&lt;br /&gt;
	end&lt;br /&gt;
	if isPreprocessed then&lt;br /&gt;
		msg = self.frame:preprocess(msg)&lt;br /&gt;
	end&lt;br /&gt;
	return msg&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
-- Option class&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local Option = {}&lt;br /&gt;
Option.__index = Option&lt;br /&gt;
Option.message = message&lt;br /&gt;
&lt;br /&gt;
function Option.new(t)&lt;br /&gt;
	local self = setmetatable({}, Option)&lt;br /&gt;
	self.cfg = t.cfg&lt;br /&gt;
	self.frame = t.frame&lt;br /&gt;
	self.nOption = t.nOption&lt;br /&gt;
	self.votePage = t.votePage&lt;br /&gt;
	self.preload = t.preload&lt;br /&gt;
	self.text = t.text&lt;br /&gt;
	self.voteText = t.voteText&lt;br /&gt;
	self.color = t.color&lt;br /&gt;
	return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Option:getCount()&lt;br /&gt;
	if self.count then&lt;br /&gt;
		return self.count&lt;br /&gt;
	else&lt;br /&gt;
		self.count = mw.getCurrentFrame():expandTemplate{title=&amp;quot;String count&amp;quot;,args={&lt;br /&gt;
			page = self.votePage,&lt;br /&gt;
			search = self:getVoteText(n)&lt;br /&gt;
		}}&lt;br /&gt;
		return self.count&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Option:setVoteTotal(n)&lt;br /&gt;
	self.total = n&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Option:getVoteTotal()&lt;br /&gt;
	return self.total or error(&amp;#039;total number of votes has not been set&amp;#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Option:getPercentage()&lt;br /&gt;
	if self.percentage then&lt;br /&gt;
		return self.percentage&lt;br /&gt;
	else&lt;br /&gt;
		self.percentage = self:getCount() / self:getVoteTotal() * 100&lt;br /&gt;
		return self.percentage&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Option:getColor()&lt;br /&gt;
	-- Get the default color for option n&lt;br /&gt;
	if self.color then&lt;br /&gt;
		return self.color&lt;br /&gt;
	end&lt;br /&gt;
	local colors = self.cfg.colors&lt;br /&gt;
	local color = colors[self.nOption]&lt;br /&gt;
	if color then&lt;br /&gt;
		self.color = color&lt;br /&gt;
	else&lt;br /&gt;
		-- Loop to find the length of colors. We can&amp;#039;t use the # operator as&lt;br /&gt;
		-- a metatable is set by mw.loadData. This is bad for polls with&lt;br /&gt;
		-- more options than there are colors in the config, as we would loop&lt;br /&gt;
		-- for every single option object. This will likely never be a problem&lt;br /&gt;
		-- in practice, however.&lt;br /&gt;
		local nColors = 0&lt;br /&gt;
		for i in ipairs(colors) do&lt;br /&gt;
			nColors = i&lt;br /&gt;
		end&lt;br /&gt;
		-- colors[nColors] is necessary as Lua arrays are indexed starting at&lt;br /&gt;
		-- 1, and n % self.nColors might sometimes equal 0.&lt;br /&gt;
		self.color = colors[self.nOption % nColors] or colors[nColors]&lt;br /&gt;
	end&lt;br /&gt;
	return self.color&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Option:getVoteText()&lt;br /&gt;
	self.voteText = self.voteText or self:message(&lt;br /&gt;
		&amp;#039;vote-default&amp;#039;,&lt;br /&gt;
		{self.nOption},&lt;br /&gt;
		true&lt;br /&gt;
	)&lt;br /&gt;
	return self.voteText&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Option:makeVoteURL()&lt;br /&gt;
	local url = mw.uri.fullUrl(&lt;br /&gt;
		self.votePage,&lt;br /&gt;
		{&lt;br /&gt;
			action = &amp;#039;edit&amp;#039;,&lt;br /&gt;
			section = &amp;#039;new&amp;#039;,&lt;br /&gt;
			nosummary = &amp;#039;true&amp;#039;,&lt;br /&gt;
			preload = self.preload,&lt;br /&gt;
			[&amp;#039;preloadparams[]&amp;#039;] = self:getVoteText()&lt;br /&gt;
		}&lt;br /&gt;
	)&lt;br /&gt;
	return tostring(url)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Option:renderButton()&lt;br /&gt;
	local button = mw.html.create(&amp;#039;span&amp;#039;)&lt;br /&gt;
		:addClass(&amp;#039;mw-ui-button mw-ui-progressive&amp;#039;)&lt;br /&gt;
		:attr(&amp;#039;role&amp;#039;, &amp;#039;button&amp;#039;)&lt;br /&gt;
		:attr(&amp;#039;aria-disabled&amp;#039;, &amp;#039;false&amp;#039;)&lt;br /&gt;
		:wikitext(self.text)&lt;br /&gt;
	local wrapper = mw.html.create(&amp;#039;span&amp;#039;)&lt;br /&gt;
		:addClass(&amp;#039;plainlinks&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;margin&amp;#039;, &amp;#039;0 4px&amp;#039;)&lt;br /&gt;
		:wikitext(string.format(&lt;br /&gt;
			&amp;#039;[%s %s]&amp;#039;,&lt;br /&gt;
			self:makeVoteURL(),&lt;br /&gt;
			tostring(button)&lt;br /&gt;
		))&lt;br /&gt;
	return wrapper&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Option:renderLegendRow()&lt;br /&gt;
	local legend = mw.html.create(&amp;#039;div&amp;#039;)&lt;br /&gt;
	legend&lt;br /&gt;
		:css(&amp;#039;margin&amp;#039;, &amp;#039;4px&amp;#039;)&lt;br /&gt;
		:tag(&amp;#039;span&amp;#039;)&lt;br /&gt;
			:css(&amp;#039;display&amp;#039;, &amp;#039;inline-block&amp;#039;)&lt;br /&gt;
			:css(&amp;#039;width&amp;#039;, &amp;#039;1.5em&amp;#039;)&lt;br /&gt;
			:css(&amp;#039;height&amp;#039;, &amp;#039;1.5em&amp;#039;)&lt;br /&gt;
			:css(&amp;#039;margin&amp;#039;, &amp;#039;1px 0&amp;#039;)&lt;br /&gt;
			:css(&amp;#039;border&amp;#039;, &amp;#039;1px solid black&amp;#039;)&lt;br /&gt;
			:css(&amp;#039;background-color&amp;#039;, self:getColor())&lt;br /&gt;
			:css(&amp;#039;text-align&amp;#039;, &amp;#039;center&amp;#039;)&lt;br /&gt;
			:wikitext(&amp;#039;&amp;amp;nbsp;&amp;#039;)&lt;br /&gt;
			:done()&lt;br /&gt;
		:wikitext(&amp;#039;&amp;amp;nbsp;&amp;#039;)&lt;br /&gt;
		:wikitext(self:message(&amp;#039;legend-option-text&amp;#039;, {&lt;br /&gt;
			self.text,&lt;br /&gt;
			self:getCount(),&lt;br /&gt;
			string.format(&amp;#039;%.0f&amp;#039;, self:getPercentage())&lt;br /&gt;
		}, true))&lt;br /&gt;
	return legend&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
-- Poll class&lt;br /&gt;
-------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local Poll = {}&lt;br /&gt;
Poll.__index = Poll&lt;br /&gt;
Poll.message = message&lt;br /&gt;
&lt;br /&gt;
function Poll.new(args, cfg, frame)&lt;br /&gt;
	local self = setmetatable({}, Poll)&lt;br /&gt;
	self.cfg = cfg or mw.loadData(CONFIG_MODULE)&lt;br /&gt;
	self.frame = frame or mw.getCurrentFrame()&lt;br /&gt;
&lt;br /&gt;
	-- Set required fields&lt;br /&gt;
	self.question = assert(args.question, self:message(&amp;#039;no-question-error&amp;#039;))&lt;br /&gt;
	self.votePage = assert(args.votepage, self:message(&amp;#039;no-votepage-error&amp;#039;))&lt;br /&gt;
&lt;br /&gt;
	-- Set optional fields&lt;br /&gt;
	self.headerText = args.header or self:message(&amp;#039;header-text&amp;#039;)&lt;br /&gt;
	self.icon = args.icon or self:message(&amp;#039;icon-default&amp;#039;)&lt;br /&gt;
	self.overlay = args.overlay or self:message(&amp;#039;overlay-default&amp;#039;)&lt;br /&gt;
	self.minimum = tonumber(args.minimum) or self:message(&amp;#039;minimum-default&amp;#039;)&lt;br /&gt;
	self.expiry = args.expiry&lt;br /&gt;
	self.lineBreak = args[&amp;#039;break&amp;#039;]&lt;br /&gt;
&lt;br /&gt;
	-- Set options&lt;br /&gt;
	self.options = {}&lt;br /&gt;
	do&lt;br /&gt;
		local preload = self:message(&amp;#039;preload-page&amp;#039;)&lt;br /&gt;
		local i = 1&lt;br /&gt;
		while true do&lt;br /&gt;
			local key = &amp;#039;option&amp;#039; .. tostring(i)&lt;br /&gt;
			local text = args[key]&lt;br /&gt;
			if not text then&lt;br /&gt;
				break&lt;br /&gt;
			end&lt;br /&gt;
			table.insert(self.options, Option.new{&lt;br /&gt;
				nOption = i,&lt;br /&gt;
				text = text,&lt;br /&gt;
				voteText = args[key .. &amp;#039;vote&amp;#039;],&lt;br /&gt;
				color = args[key .. &amp;#039;color&amp;#039;],&lt;br /&gt;
				cfg = self.cfg,&lt;br /&gt;
				frame = self.frame,&lt;br /&gt;
				votePage = self.votePage,&lt;br /&gt;
				preload = preload&lt;br /&gt;
			})&lt;br /&gt;
			i = i + 1&lt;br /&gt;
		end&lt;br /&gt;
		if #self.options &amp;lt; 2 then&lt;br /&gt;
			error(self:message(&amp;#039;not-enough-options-error&amp;#039;))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Check for duplicate vote text&lt;br /&gt;
	do&lt;br /&gt;
		local votes = {}&lt;br /&gt;
		for option in self:iterateOptions() do&lt;br /&gt;
			if votes[option:getVoteText()] then&lt;br /&gt;
				error(self:message(&lt;br /&gt;
					&amp;#039;duplicate-vote-text-error&amp;#039;,&lt;br /&gt;
					{votes[option:getVoteText()], option.nOption},&lt;br /&gt;
					true&lt;br /&gt;
				))&lt;br /&gt;
			else&lt;br /&gt;
				votes[option:getVoteText()] = option.nOption&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Prompt users to create the vote page if it doesn&amp;#039;t exist.&lt;br /&gt;
	do&lt;br /&gt;
		local success, votePageContent = pcall(function ()&lt;br /&gt;
			return mw.title.new(self.votePage):getContent()&lt;br /&gt;
		end)&lt;br /&gt;
		if not success or not votePageContent then&lt;br /&gt;
			local createVotePageUrl = mw.uri.fullUrl(&lt;br /&gt;
				self.votePage,&lt;br /&gt;
				{&lt;br /&gt;
					action = &amp;#039;edit&amp;#039;,&lt;br /&gt;
					preload = self:message(&amp;#039;vote-page-preload-default&amp;#039;),&lt;br /&gt;
					[&amp;#039;preloadparams[]&amp;#039;] = mw.title.getCurrentTitle().prefixedText,&lt;br /&gt;
					summary = self:message(&amp;#039;vote-page-create-summary&amp;#039;),&lt;br /&gt;
					editintro = self:message(&amp;#039;vote-page-create-editintro&amp;#039;)&lt;br /&gt;
				}&lt;br /&gt;
			)&lt;br /&gt;
			error(self:message(&lt;br /&gt;
				&amp;#039;votepage-nonexistent-error&amp;#039;,&lt;br /&gt;
				{tostring(createVotePageUrl)}&lt;br /&gt;
			), 0)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Find total number of votes&lt;br /&gt;
	do&lt;br /&gt;
		local total = 0&lt;br /&gt;
		for option in self:iterateOptions() do&lt;br /&gt;
			total = total + option:getCount()&lt;br /&gt;
		end&lt;br /&gt;
		for option in self:iterateOptions() do&lt;br /&gt;
			option:setVoteTotal(total)&lt;br /&gt;
		end&lt;br /&gt;
		self.voteTotal = total&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return self&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Static methods&lt;br /&gt;
&lt;br /&gt;
function Poll.getUnixDate(date)&lt;br /&gt;
	date = lang:formatDate(&amp;#039;U&amp;#039;, date)&lt;br /&gt;
	return tonumber(date)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Normal methods&lt;br /&gt;
&lt;br /&gt;
function Poll:iterateOptions()&lt;br /&gt;
	local i = 0&lt;br /&gt;
	local n = #self.options&lt;br /&gt;
	return function ()&lt;br /&gt;
		i = i + 1&lt;br /&gt;
		if i &amp;lt;= n then&lt;br /&gt;
			return self.options[i]&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Poll:renderHeader()&lt;br /&gt;
	local headerDiv = mw.html.create(&amp;#039;div&amp;#039;)&lt;br /&gt;
	headerDiv&lt;br /&gt;
		:css(&amp;#039;border-top&amp;#039;, &amp;#039;1px solid #CCC&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;font-family&amp;#039;, &amp;#039;Georgia, Palatino, Palatino Linotype, Times, Times New Roman, serif&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;color&amp;#039;, &amp;#039;#333&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;padding&amp;#039;, &amp;#039;5px 0&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;line-height&amp;#039;, &amp;#039;120%&amp;#039;)&lt;br /&gt;
		:wikitext(string.format(&lt;br /&gt;
			&amp;#039;[[File:%s|right|30px|link=]]&amp;#039;,&lt;br /&gt;
			self.icon&lt;br /&gt;
		))&lt;br /&gt;
		:tag(&amp;#039;span&amp;#039;)&lt;br /&gt;
			:css(&amp;#039;text-transform&amp;#039;, &amp;#039;uppercase&amp;#039;)&lt;br /&gt;
			:css(&amp;#039;color&amp;#039;, &amp;#039;#999&amp;#039;)&lt;br /&gt;
			:css(&amp;#039;font-size&amp;#039;, &amp;#039;105%&amp;#039;)&lt;br /&gt;
			:css(&amp;#039;font-weight&amp;#039;, &amp;#039;bold&amp;#039;)&lt;br /&gt;
			:wikitext(self.headerText)&lt;br /&gt;
	return headerDiv&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Poll:renderQuestion()&lt;br /&gt;
	local question = mw.html.create(&amp;#039;div&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;margin-top&amp;#039;, &amp;#039;10px&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;margin-bottom&amp;#039;, &amp;#039;10px&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;line-height&amp;#039;, &amp;#039;100%&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;font-size&amp;#039;, &amp;#039;95%&amp;#039;)&lt;br /&gt;
		:wikitext(self.question)&lt;br /&gt;
	return question&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Poll:renderVisualization()&lt;br /&gt;
	local overlayWidth = &amp;#039;253px&amp;#039;&lt;br /&gt;
	local vzn = mw.html.create(&amp;#039;div&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;height&amp;#039;, &amp;#039;250px&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;border-spacing&amp;#039;, &amp;#039;0&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;width&amp;#039;, overlayWidth)&lt;br /&gt;
		:css(&amp;#039;margin-left&amp;#039;, &amp;#039;auto&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;margin-right&amp;#039;, &amp;#039;auto&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
	-- Overlay&lt;br /&gt;
	vzn&lt;br /&gt;
		:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
			:css(&amp;#039;position&amp;#039;, &amp;#039;absolute&amp;#039;)&lt;br /&gt;
			:css(&amp;#039;z-index&amp;#039;, &amp;#039;2&amp;#039;)&lt;br /&gt;
			:css(&amp;#039;padding&amp;#039;, &amp;#039;0&amp;#039;)&lt;br /&gt;
			:css(&amp;#039;margin&amp;#039;, &amp;#039;0&amp;#039;)&lt;br /&gt;
			:wikitext(string.format(&lt;br /&gt;
				&amp;#039;[[File:%s|%s|link=]] &amp;amp;nbsp;&amp;#039;,&lt;br /&gt;
				self.overlay,&lt;br /&gt;
				overlayWidth&lt;br /&gt;
			))&lt;br /&gt;
&lt;br /&gt;
	-- Option colors&lt;br /&gt;
	for option in self:iterateOptions() do&lt;br /&gt;
		vzn:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
			:css(&amp;#039;background&amp;#039;, option:getColor())&lt;br /&gt;
			:css(&amp;#039;padding&amp;#039;, &amp;#039;0&amp;#039;)&lt;br /&gt;
			:css(&amp;#039;margin&amp;#039;, &amp;#039;0&amp;#039;)&lt;br /&gt;
			:css(&amp;#039;width&amp;#039;, &amp;#039;250px&amp;#039;)&lt;br /&gt;
			:css(&amp;#039;height&amp;#039;, string.format(&lt;br /&gt;
				&amp;#039;%.3f%%&amp;#039;, -- Round to 3 decimal places and add a percent sign&lt;br /&gt;
				option:getPercentage()&lt;br /&gt;
			))&lt;br /&gt;
			:wikitext(&amp;#039;&amp;amp;nbsp;&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return vzn&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Poll:renderLegend()&lt;br /&gt;
	local legend = mw.html.create(&amp;#039;div&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;margin-top&amp;#039;, &amp;#039;3px&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;display&amp;#039;, &amp;#039;flex&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;justify-content&amp;#039;, &amp;#039;center&amp;#039;)&lt;br /&gt;
	local centered = legend:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
	for option in self:iterateOptions() do&lt;br /&gt;
		centered:node(option:renderLegendRow())&lt;br /&gt;
	end&lt;br /&gt;
	return legend&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Poll:hasLineBreaks()&lt;br /&gt;
	-- Try to auto-detect whether we should have line breaks&lt;br /&gt;
	if self.lineBreak then&lt;br /&gt;
		return yesno(self.lineBreak) or true&lt;br /&gt;
	end&lt;br /&gt;
	local nOptions = #self.options&lt;br /&gt;
	if nOptions &amp;gt; 3 then&lt;br /&gt;
		return true&lt;br /&gt;
	end&lt;br /&gt;
	local wordCount = 0&lt;br /&gt;
	for option in self:iterateOptions() do&lt;br /&gt;
		wordCount = wordCount + mw.ustring.len(option.text)&lt;br /&gt;
	end&lt;br /&gt;
	if nOptions == 3 then&lt;br /&gt;
		return wordCount &amp;gt;= 12&lt;br /&gt;
	else&lt;br /&gt;
		return wordCount &amp;gt;= 15&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Poll:renderButtons()&lt;br /&gt;
	local hasBreaks = self:hasLineBreaks()&lt;br /&gt;
	local buttons = mw.html.create(&amp;#039;div&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;margin-top&amp;#039;, &amp;#039;5px&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;display&amp;#039;, &amp;#039;flex&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;justify-content&amp;#039;, &amp;#039;center&amp;#039;)&lt;br /&gt;
	local centered = buttons:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
	if not hasBreaks then&lt;br /&gt;
		centered:css(&amp;#039;text-align&amp;#039;, &amp;#039;center&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
	for option in self:iterateOptions() do&lt;br /&gt;
		local button&lt;br /&gt;
		if hasBreaks then&lt;br /&gt;
			button = centered:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
				:css(&amp;#039;margin&amp;#039;, &amp;#039;4px 0&amp;#039;)&lt;br /&gt;
		else&lt;br /&gt;
			button = centered&lt;br /&gt;
		end&lt;br /&gt;
		button:node(option:renderButton())&lt;br /&gt;
	end&lt;br /&gt;
	return buttons&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Poll:renderWarning(s)&lt;br /&gt;
	local warning = mw.html.create(&amp;#039;div&amp;#039;)&lt;br /&gt;
	warning&lt;br /&gt;
		:css(&amp;#039;line-height&amp;#039;, &amp;#039;90%&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;width&amp;#039;, &amp;#039;100%&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;margin-top&amp;#039;, &amp;#039;5px&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;text-align&amp;#039;, &amp;#039;center&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;color&amp;#039;, &amp;#039;red&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;font-size&amp;#039;, &amp;#039;85%&amp;#039;)&lt;br /&gt;
		:wikitext(s)&lt;br /&gt;
	return warning&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Poll:hasMinimumVoteCount()&lt;br /&gt;
	return self.voteTotal &amp;gt;= self.minimum&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Poll:isOpen()&lt;br /&gt;
	if self.expiry then&lt;br /&gt;
		return self.getUnixDate() &amp;lt; self.getUnixDate(self.expiry)&lt;br /&gt;
	else&lt;br /&gt;
		return true&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Poll:__tostring()&lt;br /&gt;
	local root = mw.html.create(&amp;#039;div&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;width&amp;#039;, &amp;#039;270px&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;float&amp;#039;, &amp;#039;right&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;clear&amp;#039;, &amp;#039;right&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;background&amp;#039;, &amp;#039;none&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;margin-bottom&amp;#039;, &amp;#039;10px&amp;#039;)&lt;br /&gt;
		:css(&amp;#039;margin-left&amp;#039;, &amp;#039;10px&amp;#039;)&lt;br /&gt;
		:addClass(&amp;#039;signpost-sidebar&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
	root:node(self:renderHeader())&lt;br /&gt;
	root:node(self:renderQuestion())&lt;br /&gt;
&lt;br /&gt;
	-- Visualization and legend&lt;br /&gt;
	if self:hasMinimumVoteCount() then&lt;br /&gt;
		root:node(self:renderVisualization())&lt;br /&gt;
		root:node(self:renderLegend())&lt;br /&gt;
	else&lt;br /&gt;
		root:node(self:renderWarning(self:message(&lt;br /&gt;
			&amp;#039;not-enough-votes-warning&amp;#039;,&lt;br /&gt;
			{self.minimum - self.voteTotal},&lt;br /&gt;
			true&lt;br /&gt;
		)))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Buttons&lt;br /&gt;
	if self:isOpen() then&lt;br /&gt;
		root:node(self:renderButtons())&lt;br /&gt;
	else&lt;br /&gt;
		root:node(self:renderWarning(self:message(&amp;#039;poll-closed-warning&amp;#039;)))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return tostring(root)&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._main(args, cfg, frame)&lt;br /&gt;
	return tostring(Poll.new(args, cfg, frame))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.main(frame, cfg)&lt;br /&gt;
	cfg = cfg or mw.loadData(CONFIG_MODULE)&lt;br /&gt;
	local args = require(&amp;#039;Module:Arguments&amp;#039;).getArgs(frame, {&lt;br /&gt;
		wrappers = cfg.wrappers&lt;br /&gt;
	})&lt;br /&gt;
	return p._main(args, cfg, frame)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>imported&gt;Pppery</name></author>
	</entry>
</feed>