<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://mindpowe.red/wiki/index.php?action=history&amp;feed=atom&amp;title=Module%3ARandom</id>
	<title>Module:Random - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://mindpowe.red/wiki/index.php?action=history&amp;feed=atom&amp;title=Module%3ARandom"/>
	<link rel="alternate" type="text/html" href="https://mindpowe.red/wiki/index.php?title=Module:Random&amp;action=history"/>
	<updated>2026-04-06T09:46:31Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.34.2</generator>
	<entry>
		<id>https://mindpowe.red/wiki/index.php?title=Module:Random&amp;diff=4454&amp;oldid=prev</id>
		<title>imported&gt;Mr. Stradivarius: allow newline separators</title>
		<link rel="alternate" type="text/html" href="https://mindpowe.red/wiki/index.php?title=Module:Random&amp;diff=4454&amp;oldid=prev"/>
		<updated>2015-11-11T16:32:54Z</updated>

		<summary type="html">&lt;p&gt;allow newline separators&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;-- This module contains a number of functions that make use of random numbers.&lt;br /&gt;
&lt;br /&gt;
local cfg = {}&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------------&lt;br /&gt;
-- Configuration&lt;br /&gt;
--------------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
-- Set this to true if your wiki has a traffic rate of less than one edit every two minutes or so.&lt;br /&gt;
-- This will prevent the same &amp;quot;random&amp;quot; number being generated many times in a row until a new edit is made&lt;br /&gt;
-- to the wiki. This setting is only relevant if the |same= parameter is set.&lt;br /&gt;
cfg.lowTraffic = false&lt;br /&gt;
&lt;br /&gt;
-- If cfg.lowTraffic is set to true, and the |same= parameter is set, this value is used for the refresh rate of the random seed.&lt;br /&gt;
-- This is the number of seconds until the seed is changed. Getting this right is tricky. If you set it too high, the same number&lt;br /&gt;
-- will be returned many times in a row. If you set it too low, you may get different random numbers appearing on the same page,&lt;br /&gt;
-- particularly for pages that take many seconds to process.&lt;br /&gt;
cfg.seedRefreshRate = 60&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------------&lt;br /&gt;
-- End configuration&lt;br /&gt;
--------------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local p = {} -- For functions available from other Lua modules.&lt;br /&gt;
local l = {} -- For functions not available from other Lua modules, but that need to be accessed using table keys.&lt;br /&gt;
&lt;br /&gt;
local yesno = require('Module:Yesno')&lt;br /&gt;
local makeList = require('Module:List').makeList&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------------&lt;br /&gt;
-- Helper functions&lt;br /&gt;
--------------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local function raiseError(msg)&lt;br /&gt;
	-- This helps to generate a wikitext error. It is the calling function's responsibility as to how to include it in the output.&lt;br /&gt;
	return mw.ustring.format('&amp;lt;b class=&amp;quot;error&amp;quot;&amp;gt;[[Module:Random]] error: %s.&amp;lt;/b&amp;gt;', msg)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------------&lt;br /&gt;
-- random number function&lt;br /&gt;
--------------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local function getBigRandom(l, u)&lt;br /&gt;
	-- Gets a random integer between l and u, and is not limited to RAND_MAX.&lt;br /&gt;
	local r = 0&lt;br /&gt;
	local n = 2^math.random(30) -- Any power of 2.&lt;br /&gt;
	local limit = math.ceil(53 / (math.log(n) / math.log(2)))&lt;br /&gt;
	for i = 1, limit do&lt;br /&gt;
		r = r + math.random(0, n - 1) / (n^i)&lt;br /&gt;
	end&lt;br /&gt;
	return math.floor(r * (u - l + 1)) + l&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function l.number(args)&lt;br /&gt;
	-- Gets a random number.&lt;br /&gt;
	first = tonumber(args[1])&lt;br /&gt;
	second = tonumber(args[2])&lt;br /&gt;
	-- This needs to use if statements as math.random won't accept explicit nil values as arguments.&lt;br /&gt;
	if first then&lt;br /&gt;
		if second then&lt;br /&gt;
			if first &amp;gt; second then -- Second number cannot be less than the first, or it causes an error.&lt;br /&gt;
				first, second = second, first&lt;br /&gt;
			end&lt;br /&gt;
			return getBigRandom(first, second)&lt;br /&gt;
		else&lt;br /&gt;
			return getBigRandom(1, first)&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		return math.random()&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------------&lt;br /&gt;
-- Date function&lt;br /&gt;
--------------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
function l.date(args)&lt;br /&gt;
	-- This function gets random dates, and takes timestamps as positional arguments.&lt;br /&gt;
	-- With no arguments specified, it outputs a random date in the current year.&lt;br /&gt;
	-- With two arguments specified, it outputs a random date between the timestamps.&lt;br /&gt;
	-- With one argument specified, the date is a random date between the unix epoch (1 Jan 1970) and the timestamp.&lt;br /&gt;
	-- The output can be formatted using the &amp;quot;format&amp;quot; argument, which works in the same way as the #time parser function.&lt;br /&gt;
	-- The default format is the standard Wikipedia timestamp.&lt;br /&gt;
	local lang = mw.language.getContentLanguage()&lt;br /&gt;
&lt;br /&gt;
	local function getDate(format, ts)&lt;br /&gt;
		local success, date = pcall(lang.formatDate, lang, format, ts)&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;
	local function getUnixTimestamp(ts)&lt;br /&gt;
		local unixts = getDate('U', ts)&lt;br /&gt;
		if unixts then&lt;br /&gt;
			return tonumber(unixts)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local t1 = args[1]&lt;br /&gt;
	local t2 = args[2]&lt;br /&gt;
	&lt;br /&gt;
	-- Find the start timestamp and the end timestamp.&lt;br /&gt;
	local startTimestamp, endTimestamp&lt;br /&gt;
	if not t1 then&lt;br /&gt;
		-- Find the first and last second in the current year.&lt;br /&gt;
		local currentYear = tonumber(getDate('Y'))&lt;br /&gt;
		local currentYearStartUnix = tonumber(getUnixTimestamp('1 Jan ' .. tostring(currentYear)))&lt;br /&gt;
		local currentYearEndUnix = tonumber(getUnixTimestamp('1 Jan ' .. tostring(currentYear + 1))) - 1&lt;br /&gt;
		startTimestamp = '@' .. tostring(currentYearStartUnix) -- @ is used to denote Unix timestamps with lang:formatDate.&lt;br /&gt;
		endTimestamp = '@' .. tostring(currentYearEndUnix)&lt;br /&gt;
	elseif t1 and not t2 then&lt;br /&gt;
		startTimestamp = '@0' -- the Unix epoch, 1 January 1970&lt;br /&gt;
		endTimestamp = t1&lt;br /&gt;
	elseif t1 and t2 then&lt;br /&gt;
		startTimestamp = t1&lt;br /&gt;
		endTimestamp = t2&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Get Unix timestamps and return errors for bad input (or for bugs in the underlying PHP library, of which there are unfortunately a few)&lt;br /&gt;
	local startTimestampUnix = getUnixTimestamp(startTimestamp)&lt;br /&gt;
	local endTimestampUnix = getUnixTimestamp(endTimestamp)&lt;br /&gt;
	if not startTimestampUnix then&lt;br /&gt;
		return raiseError('&amp;quot;' .. tostring(startTimestamp) .. '&amp;quot; was not recognised as a valid timestamp')&lt;br /&gt;
	elseif not endTimestampUnix then&lt;br /&gt;
		return raiseError('&amp;quot;' .. tostring(endTimestamp) .. '&amp;quot; was not recognised as a valid timestamp')&lt;br /&gt;
	elseif startTimestampUnix &amp;gt; endTimestampUnix then&lt;br /&gt;
		return raiseError('the start date must not be later than the end date (start date: &amp;quot;' .. startTimestamp .. '&amp;quot;, end date: &amp;quot;' .. endTimestamp .. '&amp;quot;)')&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Get a random number between the two Unix timestamps and return it using the specified format.&lt;br /&gt;
	local randomTimestamp = getBigRandom(startTimestampUnix, endTimestampUnix)&lt;br /&gt;
	local dateFormat = args.format or 'H:i, d F Y (T)'&lt;br /&gt;
	local result = getDate(dateFormat, '@' .. tostring(randomTimestamp))&lt;br /&gt;
	if result then&lt;br /&gt;
		return result&lt;br /&gt;
	else&lt;br /&gt;
		return raiseError('&amp;quot;' .. dateFormat .. '&amp;quot; is not a valid date format')&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------------&lt;br /&gt;
-- List functions&lt;br /&gt;
--------------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local function randomizeArray(t, limit)&lt;br /&gt;
	-- Randomizes an array. It works by iterating through the list backwards, each time swapping the entry&lt;br /&gt;
	-- &amp;quot;i&amp;quot; with a random entry. Courtesy of Xinhuan at http://forums.wowace.com/showthread.php?p=279756&lt;br /&gt;
	-- If the limit parameter is set, the array is shortened to that many elements after being randomized.&lt;br /&gt;
	-- The lowest possible value is 0, and the highest possible is the length of the array.&lt;br /&gt;
	local len = #t&lt;br /&gt;
	for i = len, 2, -1 do&lt;br /&gt;
		local r = math.random(i)&lt;br /&gt;
		t[i], t[r] = t[r], t[i]&lt;br /&gt;
	end&lt;br /&gt;
	if limit and limit &amp;lt; len then&lt;br /&gt;
		local ret = {}&lt;br /&gt;
		for i, v in ipairs(t) do&lt;br /&gt;
			if i &amp;gt; limit then&lt;br /&gt;
				break&lt;br /&gt;
			end&lt;br /&gt;
			ret[i] = v&lt;br /&gt;
		end&lt;br /&gt;
		return ret&lt;br /&gt;
	else&lt;br /&gt;
		return t&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function removeBlanks(t)&lt;br /&gt;
	-- Removes blank entries from an array so that it can be used with ipairs.&lt;br /&gt;
	local ret = {}&lt;br /&gt;
	for k, v in pairs(t) do&lt;br /&gt;
		if type(k) == 'number' then&lt;br /&gt;
			table.insert(ret, k)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	table.sort(ret)&lt;br /&gt;
	for i, v in ipairs(ret) do&lt;br /&gt;
		ret[i] = t[v]&lt;br /&gt;
	end&lt;br /&gt;
	return ret&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function makeSeparator(sep)&lt;br /&gt;
	if sep == 'space' then&lt;br /&gt;
		-- Include an easy way to use spaces as separators.&lt;br /&gt;
		return ' '&lt;br /&gt;
	elseif sep == 'newline' then&lt;br /&gt;
		-- Ditto for newlines&lt;br /&gt;
		return '\n'&lt;br /&gt;
	elseif type(sep) == 'string' then&lt;br /&gt;
		-- If the separator is a recognised MediaWiki separator, use that. Otherwise use the value of sep if it is a string.&lt;br /&gt;
		local mwseparators = {'dot', 'pipe', 'comma', 'tpt-languages'}&lt;br /&gt;
		for _, mwsep in ipairs(mwseparators) do&lt;br /&gt;
			if sep == mwsep then&lt;br /&gt;
				return mw.message.new( sep .. '-separator' ):plain()&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return sep&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function makeRandomList(args)&lt;br /&gt;
	local list = removeBlanks(args)&lt;br /&gt;
	list = randomizeArray(list, tonumber(args.limit))&lt;br /&gt;
	return list&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function l.item(args)&lt;br /&gt;
	-- Returns a random item from a numbered list.&lt;br /&gt;
	local list = removeBlanks(args)&lt;br /&gt;
	local len = #list&lt;br /&gt;
	if len &amp;gt;= 1 then&lt;br /&gt;
		return list[math.random(len)]&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function l.list(args)&lt;br /&gt;
	-- Randomizes a list and concatenates the result with a separator.&lt;br /&gt;
	local list = makeRandomList(args)&lt;br /&gt;
	local sep = makeSeparator(args.sep or args.separator)&lt;br /&gt;
	return table.concat(list, sep)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function l.text_list(args)&lt;br /&gt;
	-- Randomizes a list and concatenates the result, text-style. Accepts separator and conjunction arguments.&lt;br /&gt;
	local list = makeRandomList(args)&lt;br /&gt;
	local sep = makeSeparator(args.sep or args.separator)&lt;br /&gt;
	local conj = makeSeparator(args.conj or args.conjunction)&lt;br /&gt;
	return mw.text.listToText(list, sep, conj)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function l.array(args)&lt;br /&gt;
	-- Returns a Lua array, randomized. For use from other Lua modules.&lt;br /&gt;
	return randomizeArray(args.t, args.limit)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------------&lt;br /&gt;
-- HTML list function&lt;br /&gt;
--------------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
function l.html_list(args, listType)&lt;br /&gt;
	-- Randomizes a list and turns it into an HTML list. Uses [[Module:List]].&lt;br /&gt;
	listType = listType or 'bulleted'&lt;br /&gt;
	local listArgs = makeRandomList(args) -- Arguments for [[Module:List]].&lt;br /&gt;
	for k, v in pairs(args) do&lt;br /&gt;
		if type(k) == 'string' then&lt;br /&gt;
			listArgs[k] = v&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return makeList(listType, listArgs)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------------------------------------&lt;br /&gt;
-- The main function. Called from other Lua modules.&lt;br /&gt;
--------------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
function p.main(funcName, args, listType)&lt;br /&gt;
	-- Sets the seed for the random number generator and passes control over to the other functions.&lt;br /&gt;
	local same = yesno(args.same)&lt;br /&gt;
	if not same then&lt;br /&gt;
		-- Generates a different number every time the module is called, even from the same page.&lt;br /&gt;
		-- This is because of the variability of os.clock (the time in seconds that the Lua script has been running for).&lt;br /&gt;
		math.randomseed(mw.site.stats.edits + mw.site.stats.pages + os.time() + math.floor(os.clock() * 1000000000))&lt;br /&gt;
	else&lt;br /&gt;
		if not cfg.lowTraffic then&lt;br /&gt;
			-- Make the seed as random as possible without using anything time-based. This means that the same random number&lt;br /&gt;
			-- will be generated for the same input from the same page - necessary behaviour for some wikicode templates that&lt;br /&gt;
			-- assume bad pseudo-random-number generation.&lt;br /&gt;
			local stats = mw.site.stats&lt;br /&gt;
			local views = stats.views or 0 -- This is not always available, so we need a backup.&lt;br /&gt;
			local seed = views + stats.pages + stats.articles + stats.files + stats.edits + stats.users + stats.activeUsers + stats.admins -- Make this as random as possible without using os.time() or os.clock()&lt;br /&gt;
			math.randomseed(seed)&lt;br /&gt;
		else&lt;br /&gt;
			-- Make the random seed change every n seconds, where n is set by cfg.seedRefreshRate.&lt;br /&gt;
			-- This is useful for low-traffic wikis where new edits may not happen very often.&lt;br /&gt;
			math.randomseed(math.floor(os.time() / cfg.seedRefreshRate))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if type(args) ~= 'table' then&lt;br /&gt;
		error('the second argument to p.main must be a table')&lt;br /&gt;
	end&lt;br /&gt;
	return l[funcName](args, listType)&lt;br /&gt;
end&lt;br /&gt;
	&lt;br /&gt;
--------------------------------------------------------------------------------------&lt;br /&gt;
-- Process arguments from #invoke&lt;br /&gt;
--------------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local function makeWrapper(funcName, listType)&lt;br /&gt;
	-- This function provides a wrapper for argument-processing from #invoke.&lt;br /&gt;
	-- listType is only used with p.html_list, and is nil the rest of the time.&lt;br /&gt;
	return function (frame)&lt;br /&gt;
		-- If called via #invoke, use the args passed into the invoking template, or the args passed to #invoke if any exist.&lt;br /&gt;
		-- Otherwise assume args are being passed directly in from the debug console or from another Lua module.&lt;br /&gt;
		local origArgs&lt;br /&gt;
		if frame == mw.getCurrentFrame() then&lt;br /&gt;
			origArgs = frame:getParent().args&lt;br /&gt;
			for k, v in pairs(frame.args) do&lt;br /&gt;
				origArgs = frame.args&lt;br /&gt;
				break&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			origArgs = frame&lt;br /&gt;
		end&lt;br /&gt;
		-- Trim whitespace and remove blank arguments.&lt;br /&gt;
		local args = {}&lt;br /&gt;
		for k, v in pairs(origArgs) do&lt;br /&gt;
			if type(v) == 'string' then&lt;br /&gt;
				v = mw.text.trim(v)&lt;br /&gt;
			end&lt;br /&gt;
			if v ~= '' then&lt;br /&gt;
				args[k] = v&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return p.main(funcName, args, listType)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Process arguments for HTML list functions.&lt;br /&gt;
local htmlListFuncs = {&lt;br /&gt;
	bulleted_list           = 'bulleted',&lt;br /&gt;
	unbulleted_list         = 'unbulleted',&lt;br /&gt;
	horizontal_list         = 'horizontal',&lt;br /&gt;
	ordered_list            = 'ordered',&lt;br /&gt;
	horizontal_ordered_list = 'horizontal_ordered'&lt;br /&gt;
}&lt;br /&gt;
for funcName, listType in pairs(htmlListFuncs) do&lt;br /&gt;
	p[funcName] = makeWrapper('html_list', listType)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Process arguments for other functions.&lt;br /&gt;
local otherFuncs = {'number', 'date', 'item', 'list', 'text_list'}&lt;br /&gt;
for _, funcName in ipairs(otherFuncs) do&lt;br /&gt;
	p[funcName] = makeWrapper(funcName)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>imported&gt;Mr. Stradivarius</name></author>
		
	</entry>
</feed>