From Wikipedia, the free encyclopedia

-- This module contains a number of functions that make use of random numbers.



local cfg = {}



--------------------------------------------------------------------------------------

-- Configuration

--------------------------------------------------------------------------------------



-- Set this to true if your wiki has a traffic rate of less than one edit every two minutes or so.

-- This will prevent the same "random" number being generated many times in a row until a new edit is made

-- to the wiki. This setting is only relevant if the |same= parameter is set.

cfg.lowTraffic = false



-- 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.

-- 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

-- 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,

-- particularly for pages that take many seconds to process.

cfg.seedRefreshRate = 60



--------------------------------------------------------------------------------------

-- End configuration

--------------------------------------------------------------------------------------



local p = {} -- For functions available from other Lua modules.

local l = {} -- For functions not available from other Lua modules, but that need to be accessed using table keys.



local yesno = require('Module:Yesno')

local makeList = require('Module:List').makeList



--------------------------------------------------------------------------------------

-- Helper functions

--------------------------------------------------------------------------------------



local function raiseError(msg)

	-- This helps to generate a wikitext error. It is the calling function's responsibility as to how to include it in the output.

	return mw.ustring.format('<b class="error">[[Module:Random]] error: %s.</b>', msg)

end



--------------------------------------------------------------------------------------

-- random number function

--------------------------------------------------------------------------------------



local function getBigRandom(l, u)

	-- Gets a random integer between l and u, and is not limited to RAND_MAX.

	local r = 0

	local n = 2^math.random(30) -- Any power of 2.

	local limit = math.ceil(53 / (math.log(n) / math.log(2)))

	for i = 1, limit do

		r = r + math.random(0, n - 1) / (n^i)

	end

	return math.floor(r * (u - l + 1)) + l

end



function l.number(args)

	-- Gets a random number.

	first = tonumber(args1])

	second = tonumber(args2])

	-- This needs to use if statements as math.random won't accept explicit nil values as arguments.

	if first then

		if second then

			if first > second then -- Second number cannot be less than the first, or it causes an error.

				first, second = second, first

			end

			return getBigRandom(first, second)

		else

			return getBigRandom(1, first)

		end

	else

		return math.random()

	end

end



--------------------------------------------------------------------------------------

-- Date function

--------------------------------------------------------------------------------------



function l.date(args)

	-- This function gets random dates, and takes timestamps as positional arguments.

	-- With no arguments specified, it outputs a random date in the current year.

	-- With two arguments specified, it outputs a random date between the timestamps.

	-- With one argument specified, the date is a random date between the unix epoch (1 Jan 1970) and the timestamp.

	-- The output can be formatted using the "format" argument, which works in the same way as the #time parser function.

	-- The default format is the standard Wikipedia timestamp.

	local lang = mw.language.getContentLanguage()



	local function getDate(format, ts)

		local success, date = pcall(lang.formatDate, lang, format, ts)

		if success then

			return date

		end

	end



	local function getUnixTimestamp(ts)

		local unixts = getDate('U', ts)

		if unixts then

			return tonumber(unixts)

		end

	end



	local t1 = args1

	local t2 = args2

	

	-- Find the start timestamp and the end timestamp.

	local startTimestamp, endTimestamp

	if not t1 then

		-- Find the first and last second in the current year.

		local currentYear = tonumber(getDate('Y'))

		local currentYearStartUnix = tonumber(getUnixTimestamp('1 Jan ' .. tostring(currentYear)))

		local currentYearEndUnix = tonumber(getUnixTimestamp('1 Jan ' .. tostring(currentYear + 1))) - 1

		startTimestamp = '@' .. tostring(currentYearStartUnix) -- @ is used to denote Unix timestamps with lang:formatDate.

		endTimestamp = '@' .. tostring(currentYearEndUnix)

	elseif not t2 then

		startTimestamp = '@0' -- the Unix epoch, 1 January 1970

		endTimestamp = t1

	else

		startTimestamp = t1

		endTimestamp = t2

	end



	-- Get Unix timestamps and return errors for bad input (or for bugs in the underlying PHP library, of which there are unfortunately a few)

	local startTimestampUnix = getUnixTimestamp(startTimestamp)

	local endTimestampUnix = getUnixTimestamp(endTimestamp)

	if not startTimestampUnix then

		return raiseError('"' .. tostring(startTimestamp) .. '" was not recognised as a valid timestamp')

	elseif not endTimestampUnix then

		return raiseError('"' .. tostring(endTimestamp) .. '" was not recognised as a valid timestamp')

	elseif startTimestampUnix > endTimestampUnix then

		return raiseError('the start date must not be later than the end date (start date: "' .. startTimestamp .. '", end date: "' .. endTimestamp .. '")')

	end



	-- Get a random number between the two Unix timestamps and return it using the specified format.

	local randomTimestamp = getBigRandom(startTimestampUnix, endTimestampUnix)

	local dateFormat = args.format or 'H:i, d F Y (T)'

	local result = getDate(dateFormat, '@' .. tostring(randomTimestamp))

	if result then

		return result

	else

		return raiseError('"' .. dateFormat .. '" is not a valid date format')

	end

end



--------------------------------------------------------------------------------------

-- List functions

--------------------------------------------------------------------------------------



local function randomizeArray(t, limit)

	-- Randomizes an array. It works by iterating through the list backwards, each time swapping the entry

	-- "i" with a random entry. Courtesy of Xinhuan at http://forums.wowace.com/showthread.php?p=279756

	-- If the limit parameter is set, the array is shortened to that many elements after being randomized.

	-- The lowest possible value is 0, and the highest possible is the length of the array.

	local len = #t

	for i = len, 2, -1 do

		local r = math.random(i)

		ti], tr = tr], ti

	end

	if limit and limit < len then

		local ret = {}

		for i, v in ipairs(t) do

			if i > limit then

				break

			end

			reti = v

		end

		return ret

	else

		return t

	end

end



local function removeBlanks(t)

	-- Removes blank entries from an array so that it can be used with ipairs.

	local ret = {}

	for k, v in pairs(t) do

		if type(k) == 'number' then

			table.insert(ret, k)

		end

	end

	table.sort(ret)

	for i, v in ipairs(ret) do

		reti = tv

	end

	return ret

end



local function makeSeparator(sep)

	if sep == 'space' then

		-- Include an easy way to use spaces as separators.

		return ' '

	elseif sep == 'newline' then

		-- Ditto for newlines

		return '\n'

	elseif type(sep) == 'string' then

		-- If the separator is a recognised MediaWiki separator, use that. Otherwise use the value of sep if it is a string.

		local mwseparators = {'dot', 'pipe', 'comma', 'tpt-languages'}

		for _, mwsep in ipairs(mwseparators) do

			if sep == mwsep then

				return mw.message.new( sep .. '-separator' ):plain()

			end

		end

		return sep

	end

end



local function makeRandomList(args)

	local list = removeBlanks(args)

	list = randomizeArray(list, tonumber(args.limit))

	return list

end



function l.item(args)

	-- Returns a random item from a numbered list.

	local list = removeBlanks(args)

	local len = #list

	if len >= 1 then

		return listmath.random(len)]

	end

end



function l.list(args)

	-- Randomizes a list and concatenates the result with a separator.

	local list = makeRandomList(args)

	local sep = makeSeparator(args.sep or args.separator)

	return table.concat(list, sep)

end



function l.text_list(args)

	-- Randomizes a list and concatenates the result, text-style. Accepts separator and conjunction arguments.

	local list = makeRandomList(args)

	local sep = makeSeparator(args.sep or args.separator)

	local conj = makeSeparator(args.conj or args.conjunction)

	return mw.text.listToText(list, sep, conj)

end



function l.array(args)

	-- Returns a Lua array, randomized. For use from other Lua modules.

	return randomizeArray(args.t, args.limit)

end



--------------------------------------------------------------------------------------

-- HTML list function

--------------------------------------------------------------------------------------



function l.html_list(args, listType)

	-- Randomizes a list and turns it into an HTML list. Uses [[Module:List]].

	listType = listType or 'bulleted'

	local listArgs = makeRandomList(args) -- Arguments for [[Module:List]].

	for k, v in pairs(args) do

		if type(k) == 'string' then

			listArgsk = v

		end

	end

	return makeList(listType, listArgs)

end



--------------------------------------------------------------------------------------

-- The main function. Called from other Lua modules.

--------------------------------------------------------------------------------------



function p.main(funcName, args, listType)

	-- Sets the seed for the random number generator and passes control over to the other functions.

	local same = yesno(args.same)

	if not same then

		-- Generates a different number every time the module is called, even from the same page.

		-- This is because of the variability of os.clock (the time in seconds that the Lua script has been running for).

		math.randomseed(mw.site.stats.edits + mw.site.stats.pages + os.time() + math.floor(os.clock() * 1000000000))

	elseif not cfg.lowTraffic then

		-- Make the seed as random as possible without using anything time-based. This means that the same random number

		-- will be generated for the same input from the same page - necessary behaviour for some wikicode templates that

		-- assume bad pseudo-random-number generation.

		local stats = mw.site.stats

		local views = stats.views or 0 -- This is not always available, so we need a backup.

		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()

		math.randomseed(seed)

	else

		-- Make the random seed change every n seconds, where n is set by cfg.seedRefreshRate.

		-- This is useful for low-traffic wikis where new edits may not happen very often.

		math.randomseed(math.floor(os.time() / cfg.seedRefreshRate))

	end

	assert(type(args) == 'table', 'the second argument to p.main must be a table')

	return lfuncName](args, listType)

end

	

--------------------------------------------------------------------------------------

-- Process arguments from #invoke

--------------------------------------------------------------------------------------



local function makeWrapper(funcName, listType)

	-- This function provides a wrapper for argument-processing from #invoke.

	-- listType is only used with p.html_list, and is nil the rest of the time.

	return function (frame)

		-- If called via #invoke, use the args passed into the invoking template, or the args passed to #invoke if any exist.

		-- Otherwise assume args are being passed directly in from the debug console or from another Lua module.

		local origArgs

		if frame == mw.getCurrentFrame() then

			origArgs = frame:getParent().args

			for k, v in pairs(frame.args) do

				origArgs = frame.args

				break

			end

		else

			origArgs = frame

		end

		-- Trim whitespace and remove blank arguments.

		local args = {}

		for k, v in pairs(origArgs) do

			if type(v) == 'string' then

				v = mw.text.trim(v)

			end

			if v ~= '' then

				argsk = v

			end

		end

		return p.main(funcName, args, listType)

	end

end



-- Process arguments for HTML list functions.

local htmlListFuncs = {

	bulleted_list           = 'bulleted',

	unbulleted_list         = 'unbulleted',

	horizontal_list         = 'horizontal',

	ordered_list            = 'ordered',

	horizontal_ordered_list = 'horizontal_ordered'

}

for funcName, listType in pairs(htmlListFuncs) do

	pfuncName = makeWrapper('html_list', listType)

end



-- Process arguments for other functions.

local otherFuncs = {'number', 'date', 'item', 'list', 'text_list'}

for _, funcName in ipairs(otherFuncs) do

	pfuncName = makeWrapper(funcName)

end



return p
From Wikipedia, the free encyclopedia

-- This module contains a number of functions that make use of random numbers.



local cfg = {}



--------------------------------------------------------------------------------------

-- Configuration

--------------------------------------------------------------------------------------



-- Set this to true if your wiki has a traffic rate of less than one edit every two minutes or so.

-- This will prevent the same "random" number being generated many times in a row until a new edit is made

-- to the wiki. This setting is only relevant if the |same= parameter is set.

cfg.lowTraffic = false



-- 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.

-- 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

-- 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,

-- particularly for pages that take many seconds to process.

cfg.seedRefreshRate = 60



--------------------------------------------------------------------------------------

-- End configuration

--------------------------------------------------------------------------------------



local p = {} -- For functions available from other Lua modules.

local l = {} -- For functions not available from other Lua modules, but that need to be accessed using table keys.



local yesno = require('Module:Yesno')

local makeList = require('Module:List').makeList



--------------------------------------------------------------------------------------

-- Helper functions

--------------------------------------------------------------------------------------



local function raiseError(msg)

	-- This helps to generate a wikitext error. It is the calling function's responsibility as to how to include it in the output.

	return mw.ustring.format('<b class="error">[[Module:Random]] error: %s.</b>', msg)

end



--------------------------------------------------------------------------------------

-- random number function

--------------------------------------------------------------------------------------



local function getBigRandom(l, u)

	-- Gets a random integer between l and u, and is not limited to RAND_MAX.

	local r = 0

	local n = 2^math.random(30) -- Any power of 2.

	local limit = math.ceil(53 / (math.log(n) / math.log(2)))

	for i = 1, limit do

		r = r + math.random(0, n - 1) / (n^i)

	end

	return math.floor(r * (u - l + 1)) + l

end



function l.number(args)

	-- Gets a random number.

	first = tonumber(args1])

	second = tonumber(args2])

	-- This needs to use if statements as math.random won't accept explicit nil values as arguments.

	if first then

		if second then

			if first > second then -- Second number cannot be less than the first, or it causes an error.

				first, second = second, first

			end

			return getBigRandom(first, second)

		else

			return getBigRandom(1, first)

		end

	else

		return math.random()

	end

end



--------------------------------------------------------------------------------------

-- Date function

--------------------------------------------------------------------------------------



function l.date(args)

	-- This function gets random dates, and takes timestamps as positional arguments.

	-- With no arguments specified, it outputs a random date in the current year.

	-- With two arguments specified, it outputs a random date between the timestamps.

	-- With one argument specified, the date is a random date between the unix epoch (1 Jan 1970) and the timestamp.

	-- The output can be formatted using the "format" argument, which works in the same way as the #time parser function.

	-- The default format is the standard Wikipedia timestamp.

	local lang = mw.language.getContentLanguage()



	local function getDate(format, ts)

		local success, date = pcall(lang.formatDate, lang, format, ts)

		if success then

			return date

		end

	end



	local function getUnixTimestamp(ts)

		local unixts = getDate('U', ts)

		if unixts then

			return tonumber(unixts)

		end

	end



	local t1 = args1

	local t2 = args2

	

	-- Find the start timestamp and the end timestamp.

	local startTimestamp, endTimestamp

	if not t1 then

		-- Find the first and last second in the current year.

		local currentYear = tonumber(getDate('Y'))

		local currentYearStartUnix = tonumber(getUnixTimestamp('1 Jan ' .. tostring(currentYear)))

		local currentYearEndUnix = tonumber(getUnixTimestamp('1 Jan ' .. tostring(currentYear + 1))) - 1

		startTimestamp = '@' .. tostring(currentYearStartUnix) -- @ is used to denote Unix timestamps with lang:formatDate.

		endTimestamp = '@' .. tostring(currentYearEndUnix)

	elseif not t2 then

		startTimestamp = '@0' -- the Unix epoch, 1 January 1970

		endTimestamp = t1

	else

		startTimestamp = t1

		endTimestamp = t2

	end



	-- Get Unix timestamps and return errors for bad input (or for bugs in the underlying PHP library, of which there are unfortunately a few)

	local startTimestampUnix = getUnixTimestamp(startTimestamp)

	local endTimestampUnix = getUnixTimestamp(endTimestamp)

	if not startTimestampUnix then

		return raiseError('"' .. tostring(startTimestamp) .. '" was not recognised as a valid timestamp')

	elseif not endTimestampUnix then

		return raiseError('"' .. tostring(endTimestamp) .. '" was not recognised as a valid timestamp')

	elseif startTimestampUnix > endTimestampUnix then

		return raiseError('the start date must not be later than the end date (start date: "' .. startTimestamp .. '", end date: "' .. endTimestamp .. '")')

	end



	-- Get a random number between the two Unix timestamps and return it using the specified format.

	local randomTimestamp = getBigRandom(startTimestampUnix, endTimestampUnix)

	local dateFormat = args.format or 'H:i, d F Y (T)'

	local result = getDate(dateFormat, '@' .. tostring(randomTimestamp))

	if result then

		return result

	else

		return raiseError('"' .. dateFormat .. '" is not a valid date format')

	end

end



--------------------------------------------------------------------------------------

-- List functions

--------------------------------------------------------------------------------------



local function randomizeArray(t, limit)

	-- Randomizes an array. It works by iterating through the list backwards, each time swapping the entry

	-- "i" with a random entry. Courtesy of Xinhuan at http://forums.wowace.com/showthread.php?p=279756

	-- If the limit parameter is set, the array is shortened to that many elements after being randomized.

	-- The lowest possible value is 0, and the highest possible is the length of the array.

	local len = #t

	for i = len, 2, -1 do

		local r = math.random(i)

		ti], tr = tr], ti

	end

	if limit and limit < len then

		local ret = {}

		for i, v in ipairs(t) do

			if i > limit then

				break

			end

			reti = v

		end

		return ret

	else

		return t

	end

end



local function removeBlanks(t)

	-- Removes blank entries from an array so that it can be used with ipairs.

	local ret = {}

	for k, v in pairs(t) do

		if type(k) == 'number' then

			table.insert(ret, k)

		end

	end

	table.sort(ret)

	for i, v in ipairs(ret) do

		reti = tv

	end

	return ret

end



local function makeSeparator(sep)

	if sep == 'space' then

		-- Include an easy way to use spaces as separators.

		return ' '

	elseif sep == 'newline' then

		-- Ditto for newlines

		return '\n'

	elseif type(sep) == 'string' then

		-- If the separator is a recognised MediaWiki separator, use that. Otherwise use the value of sep if it is a string.

		local mwseparators = {'dot', 'pipe', 'comma', 'tpt-languages'}

		for _, mwsep in ipairs(mwseparators) do

			if sep == mwsep then

				return mw.message.new( sep .. '-separator' ):plain()

			end

		end

		return sep

	end

end



local function makeRandomList(args)

	local list = removeBlanks(args)

	list = randomizeArray(list, tonumber(args.limit))

	return list

end



function l.item(args)

	-- Returns a random item from a numbered list.

	local list = removeBlanks(args)

	local len = #list

	if len >= 1 then

		return listmath.random(len)]

	end

end



function l.list(args)

	-- Randomizes a list and concatenates the result with a separator.

	local list = makeRandomList(args)

	local sep = makeSeparator(args.sep or args.separator)

	return table.concat(list, sep)

end



function l.text_list(args)

	-- Randomizes a list and concatenates the result, text-style. Accepts separator and conjunction arguments.

	local list = makeRandomList(args)

	local sep = makeSeparator(args.sep or args.separator)

	local conj = makeSeparator(args.conj or args.conjunction)

	return mw.text.listToText(list, sep, conj)

end



function l.array(args)

	-- Returns a Lua array, randomized. For use from other Lua modules.

	return randomizeArray(args.t, args.limit)

end



--------------------------------------------------------------------------------------

-- HTML list function

--------------------------------------------------------------------------------------



function l.html_list(args, listType)

	-- Randomizes a list and turns it into an HTML list. Uses [[Module:List]].

	listType = listType or 'bulleted'

	local listArgs = makeRandomList(args) -- Arguments for [[Module:List]].

	for k, v in pairs(args) do

		if type(k) == 'string' then

			listArgsk = v

		end

	end

	return makeList(listType, listArgs)

end



--------------------------------------------------------------------------------------

-- The main function. Called from other Lua modules.

--------------------------------------------------------------------------------------



function p.main(funcName, args, listType)

	-- Sets the seed for the random number generator and passes control over to the other functions.

	local same = yesno(args.same)

	if not same then

		-- Generates a different number every time the module is called, even from the same page.

		-- This is because of the variability of os.clock (the time in seconds that the Lua script has been running for).

		math.randomseed(mw.site.stats.edits + mw.site.stats.pages + os.time() + math.floor(os.clock() * 1000000000))

	elseif not cfg.lowTraffic then

		-- Make the seed as random as possible without using anything time-based. This means that the same random number

		-- will be generated for the same input from the same page - necessary behaviour for some wikicode templates that

		-- assume bad pseudo-random-number generation.

		local stats = mw.site.stats

		local views = stats.views or 0 -- This is not always available, so we need a backup.

		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()

		math.randomseed(seed)

	else

		-- Make the random seed change every n seconds, where n is set by cfg.seedRefreshRate.

		-- This is useful for low-traffic wikis where new edits may not happen very often.

		math.randomseed(math.floor(os.time() / cfg.seedRefreshRate))

	end

	assert(type(args) == 'table', 'the second argument to p.main must be a table')

	return lfuncName](args, listType)

end

	

--------------------------------------------------------------------------------------

-- Process arguments from #invoke

--------------------------------------------------------------------------------------



local function makeWrapper(funcName, listType)

	-- This function provides a wrapper for argument-processing from #invoke.

	-- listType is only used with p.html_list, and is nil the rest of the time.

	return function (frame)

		-- If called via #invoke, use the args passed into the invoking template, or the args passed to #invoke if any exist.

		-- Otherwise assume args are being passed directly in from the debug console or from another Lua module.

		local origArgs

		if frame == mw.getCurrentFrame() then

			origArgs = frame:getParent().args

			for k, v in pairs(frame.args) do

				origArgs = frame.args

				break

			end

		else

			origArgs = frame

		end

		-- Trim whitespace and remove blank arguments.

		local args = {}

		for k, v in pairs(origArgs) do

			if type(v) == 'string' then

				v = mw.text.trim(v)

			end

			if v ~= '' then

				argsk = v

			end

		end

		return p.main(funcName, args, listType)

	end

end



-- Process arguments for HTML list functions.

local htmlListFuncs = {

	bulleted_list           = 'bulleted',

	unbulleted_list         = 'unbulleted',

	horizontal_list         = 'horizontal',

	ordered_list            = 'ordered',

	horizontal_ordered_list = 'horizontal_ordered'

}

for funcName, listType in pairs(htmlListFuncs) do

	pfuncName = makeWrapper('html_list', listType)

end



-- Process arguments for other functions.

local otherFuncs = {'number', 'date', 'item', 'list', 'text_list'}

for _, funcName in ipairs(otherFuncs) do

	pfuncName = makeWrapper(funcName)

end



return p

Videos

Youtube | Vimeo | Bing

Websites

Google | Yahoo | Bing

Encyclopedia

Google | Yahoo | Bing

Facebook