<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://xenreference.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Module%3AUtils</id>
	<title>Module:Utils - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://xenreference.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Module%3AUtils"/>
	<link rel="alternate" type="text/html" href="https://xenreference.com/wiki/index.php?title=Module:Utils&amp;action=history"/>
	<updated>2026-06-05T06:02:01Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.44.2</generator>
	<entry>
		<id>https://xenreference.com/wiki/index.php?title=Module:Utils&amp;diff=842&amp;oldid=prev</id>
		<title>Vector: Created page with &quot;local p = {}  local get_args = require(&quot;Module:Arguments&quot;).getArgs local yesno = require(&quot;Module:Yesno&quot;)  -- TODO??? Enforce rule for prefixing module-callable functions with an -- underscore, regardless of whether a wrapper is needed or can be made????  -- Trim a string (remove leading and trailing, but not interior, whitespace) function p.trim(s)    return s:match(&quot;^%s*(.-)%s*$&quot;) end  -- Wrapper function for template access to Module:Yesno function p._yesno(frame)...&quot;</title>
		<link rel="alternate" type="text/html" href="https://xenreference.com/wiki/index.php?title=Module:Utils&amp;diff=842&amp;oldid=prev"/>
		<updated>2025-12-16T05:04:44Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;local p = {}  local get_args = require(&amp;quot;Module:Arguments&amp;quot;).getArgs local yesno = require(&amp;quot;Module:Yesno&amp;quot;)  -- TODO??? Enforce rule for prefixing module-callable functions with an -- underscore, regardless of whether a wrapper is needed or can be made????  -- Trim a string (remove leading and trailing, but not interior, whitespace) function p.trim(s)    return s:match(&amp;quot;^%s*(.-)%s*$&amp;quot;) end  -- Wrapper function for template access to &lt;a href=&quot;/w/Module:Yesno&quot; title=&quot;Module:Yesno&quot;&gt;Module:Yesno&lt;/a&gt; function p._yesno(frame)...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local p = {}&lt;br /&gt;
&lt;br /&gt;
local get_args = require(&amp;quot;Module:Arguments&amp;quot;).getArgs&lt;br /&gt;
local yesno = require(&amp;quot;Module:Yesno&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
-- TODO??? Enforce rule for prefixing module-callable functions with an&lt;br /&gt;
-- underscore, regardless of whether a wrapper is needed or can be made????&lt;br /&gt;
&lt;br /&gt;
-- Trim a string (remove leading and trailing, but not interior, whitespace)&lt;br /&gt;
function p.trim(s)&lt;br /&gt;
   return s:match(&amp;quot;^%s*(.-)%s*$&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Wrapper function for template access to [[Module:Yesno]]&lt;br /&gt;
function p._yesno(frame)&lt;br /&gt;
	return yesno(frame.args[&amp;quot;input&amp;quot;], frame.args[&amp;quot;default&amp;quot;])&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Clamp function&lt;br /&gt;
-- Underscore-prefixed in case a wrapper for a template is ever needed&lt;br /&gt;
function p._clamp(val, min_val, max_val)&lt;br /&gt;
	return math.min(math.max(value, min_val), max_val)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Check if a table contains the given value&lt;br /&gt;
-- Accepts an optional comparison function that accepts two tables, returning&lt;br /&gt;
-- true if value and tbl[i] have the same value.&lt;br /&gt;
function p.table_contains(tbl, value, compare_func)&lt;br /&gt;
	if compare_func ~= nil then&lt;br /&gt;
		-- Use compare function&lt;br /&gt;
		for i = 1, #tbl do&lt;br /&gt;
			if compare_func(value, tbl[i]) then&lt;br /&gt;
				return true&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		-- No compare function&lt;br /&gt;
		for i = 1, #tbl do&lt;br /&gt;
			if value == tbl[i] then&lt;br /&gt;
				return 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;
-- Return the first index with the given value (or nil if not found)&lt;br /&gt;
-- Accepts an optional comparison function that accepts two tables, returning&lt;br /&gt;
-- true if value and v have the same value.&lt;br /&gt;
function p.index_of(array, value, compare_func)&lt;br /&gt;
	if compare_func ~= nil then&lt;br /&gt;
		-- Use compare function&lt;br /&gt;
		for i, v in ipairs(array) do&lt;br /&gt;
			if compare_func(v, value) then&lt;br /&gt;
				return i&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		-- No compare function&lt;br /&gt;
		for i, v in ipairs(array) do&lt;br /&gt;
			if v == value then&lt;br /&gt;
				return i&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return nil&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Check whether the input is a non-empty string&lt;br /&gt;
function p.value_provided(s)&lt;br /&gt;
	return type(s) == &amp;quot;string&amp;quot; and #s &amp;gt; 0&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Evaluate input on error use default; cannot be used with {{#invoke:}}&lt;br /&gt;
function p.eval_num_arg(input, def_value)&lt;br /&gt;
	local result = input&lt;br /&gt;
	if type(input) ~= &amp;quot;number&amp;quot; then&lt;br /&gt;
		result = def_value&lt;br /&gt;
		if type(input) == &amp;quot;string&amp;quot; then&lt;br /&gt;
			-- Check for fraction notation&lt;br /&gt;
			if input:match(&amp;quot;/&amp;quot;) == &amp;quot;/&amp;quot; then&lt;br /&gt;
				local numerator, denominator = input:match(&amp;quot;^%s*([0-9]+)[/?]([0-9]+)%s*$&amp;quot;)&lt;br /&gt;
				result = (tonumber(numerator) or def_value) / (tonumber(denominator) or 1)&lt;br /&gt;
			else&lt;br /&gt;
				result = tonumber(input)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return result&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Return logarithm base b of x&lt;br /&gt;
function p.log(frame)&lt;br /&gt;
	local args = get_args(frame)&lt;br /&gt;
	return p._log(args[1], args[2])&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local LN_2 = math.log(2)&lt;br /&gt;
-- Return logarithm base 2 of x&lt;br /&gt;
function p.log2(x)&lt;br /&gt;
	return math.log(x) / LN_2&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._log(x, b)&lt;br /&gt;
	-- x defaults to 0&lt;br /&gt;
	x = p.eval_num_arg(x, 0)&lt;br /&gt;
	-- b defaults to 2 (&amp;quot;octave&amp;quot;)&lt;br /&gt;
	b = p.eval_num_arg(b, 2)&lt;br /&gt;
	return math.log(x) / math.log(b)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Return greatest common divisor of a and b&lt;br /&gt;
function p.gcd(frame)&lt;br /&gt;
	local args = get_args(frame)&lt;br /&gt;
	return p._gcd(args[1], args[2])&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._gcd(a, b)&lt;br /&gt;
	if b ~= 0 then&lt;br /&gt;
		return p._gcd(b, a % b)&lt;br /&gt;
	else&lt;br /&gt;
		return math.abs(a)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Return x rounded to places decimal places&lt;br /&gt;
function p.round_dec(frame)&lt;br /&gt;
	local args = get_args(frame)&lt;br /&gt;
	return p._round_dec(args[1], args[2])&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._round_dec(x, places)&lt;br /&gt;
	-- x defaults to 0&lt;br /&gt;
	x = p.eval_num_arg(x, 0)&lt;br /&gt;
	-- places defaults to 0&lt;br /&gt;
	places = p.eval_num_arg(places, 0)&lt;br /&gt;
	return math.floor(x * 10 ^ places + 0.5) / 10 ^ places&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Return x rounded to a precision of prec significant figures&lt;br /&gt;
function p.round(frame)&lt;br /&gt;
	local args = get_args(frame)&lt;br /&gt;
	return p._round(args[1], args[2])&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._round(x, prec)&lt;br /&gt;
	-- x defaults to 0&lt;br /&gt;
	x = p.eval_num_arg(x, 0)&lt;br /&gt;
	-- prec defaults to 6&lt;br /&gt;
	prec = p.eval_num_arg(prec, 6)&lt;br /&gt;
	if x == 0 then&lt;br /&gt;
		return 0&lt;br /&gt;
	else&lt;br /&gt;
		return p._round_dec(x, prec - math.floor(p._log(math.abs(x), 10)) - 1)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Cached list of primes for is_prime&lt;br /&gt;
local primes_cache = {&lt;br /&gt;
	[0] = false,&lt;br /&gt;
	[1] = false,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
-- Returns true if integer n is prime; cannot be used with {{#invoke:}}&lt;br /&gt;
function p.is_prime(n)&lt;br /&gt;
	local cached = primes_cache[n]&lt;br /&gt;
	if cached ~= nil then&lt;br /&gt;
		return cached&lt;br /&gt;
	end&lt;br /&gt;
	for i = 2, math.sqrt(n) do&lt;br /&gt;
		if n % i == 0 then&lt;br /&gt;
			primes_cache[n] = false&lt;br /&gt;
			return false&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	primes_cache[n] = true&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Returns prime factorization of integer n &amp;gt; 1; cannot be used with {{#invoke:}}&lt;br /&gt;
-- Note: the order of keys is not specified for Lua tables&lt;br /&gt;
function p.prime_factorization_raw(n)&lt;br /&gt;
	local factors = {}&lt;br /&gt;
	local m = n&lt;br /&gt;
	for i = 2, math.sqrt(n) + 1 do&lt;br /&gt;
		while m % i == 0 do&lt;br /&gt;
			factors[i] = factors[i] or 0&lt;br /&gt;
			factors[i] = factors[i] + 1&lt;br /&gt;
			m = m / i&lt;br /&gt;
		end&lt;br /&gt;
		if m == 1 then&lt;br /&gt;
			break&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if m &amp;gt; 1 then&lt;br /&gt;
		factors[m] = factors[m] or 1&lt;br /&gt;
	end&lt;br /&gt;
	return factors&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Returns prime factorization of integer n &amp;gt; 2 (with wiki markup for exponents)&lt;br /&gt;
function p.prime_factorization(frame)&lt;br /&gt;
	local args = get_args(frame)&lt;br /&gt;
	return p._prime_factorization(p.eval_num_arg(args[1], 12)) -- default to 12&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._prime_factorization(n)&lt;br /&gt;
	if n &amp;lt;= 1 then&lt;br /&gt;
		return &amp;quot;n/a&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	local factors, powers = {}, {}&lt;br /&gt;
	local new_number = n&lt;br /&gt;
	for i = 2, n do&lt;br /&gt;
		if p.is_prime(i) then&lt;br /&gt;
			if new_number % i == 0 then&lt;br /&gt;
				factors[#factors + 1] = i&lt;br /&gt;
				powers[#factors] = 0&lt;br /&gt;
				while new_number % i == 0 do&lt;br /&gt;
					powers[#factors] = powers[#factors] + 1&lt;br /&gt;
					new_number = new_number / i&lt;br /&gt;
				end&lt;br /&gt;
				if powers[#factors] &amp;gt; 1 then&lt;br /&gt;
					powers[#factors] = factors[#factors] .. &amp;quot;&amp;lt;sup&amp;gt;&amp;quot; .. powers[#factors] .. &amp;quot;&amp;lt;/sup&amp;gt;&amp;quot;&lt;br /&gt;
				else&lt;br /&gt;
					powers[#factors] = factors[#factors]&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if new_number == 1 then&lt;br /&gt;
			break&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return table.concat(powers, &amp;quot; × &amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Returns signum(x); cannot be used with {{#invoke:}}&lt;br /&gt;
function p.signum(x)&lt;br /&gt;
	if type(x) ~= &amp;quot;number&amp;quot; then&lt;br /&gt;
		return 0&lt;br /&gt;
	end&lt;br /&gt;
	if x &amp;gt; 0 then&lt;br /&gt;
		return 1&lt;br /&gt;
	end&lt;br /&gt;
	if x &amp;lt; 0 then&lt;br /&gt;
		return -1&lt;br /&gt;
	end&lt;br /&gt;
	return 0&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Returns the next Young diagram of the same size or nil; cannot be used with {{#invoke:}}&lt;br /&gt;
-- Modifies the input table&lt;br /&gt;
function p.next_young_diagram(d)&lt;br /&gt;
	if #d == 0 then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	local i_from = nil&lt;br /&gt;
	local size = 0&lt;br /&gt;
	for i = #d, 1, -1 do&lt;br /&gt;
		if d[i] &amp;gt; 1 then&lt;br /&gt;
			i_from = i&lt;br /&gt;
			break&lt;br /&gt;
		end&lt;br /&gt;
		size = size + d[i]&lt;br /&gt;
	end&lt;br /&gt;
	if i_from == nil then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	d[i_from] = d[i_from] - 1&lt;br /&gt;
	size = size + 1&lt;br /&gt;
	-- repacking the tail&lt;br /&gt;
	local max_d = d[i_from]&lt;br /&gt;
	for i = i_from + 1, #d + 1 do&lt;br /&gt;
		if size &amp;gt;= max_d then&lt;br /&gt;
			d[i] = max_d&lt;br /&gt;
			size = size - max_d&lt;br /&gt;
		elseif size &amp;gt; 0 then&lt;br /&gt;
			d[i] = size&lt;br /&gt;
			size = 0&lt;br /&gt;
		else&lt;br /&gt;
			d[i] = nil&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return d&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- stylua: ignore&lt;br /&gt;
p.primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,&lt;br /&gt;
			   101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,&lt;br /&gt;
			   211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271}&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Vector</name></author>
	</entry>
</feed>