<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://the-democratika.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Module%3ARoad_data%2Futil</id>
	<title>Module:Road data/util - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://the-democratika.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Module%3ARoad_data%2Futil"/>
	<link rel="alternate" type="text/html" href="https://the-democratika.com/wiki/index.php?title=Module:Road_data/util&amp;action=history"/>
	<updated>2026-04-04T20:32:18Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>https://the-democratika.com/wiki/index.php?title=Module:Road_data/util&amp;diff=6725&amp;oldid=prev</id>
		<title>&gt;Isabelle Belato: Changed protection settings for &quot;Module:Road data/util&quot;: Highly visible template; requested at WP:RfPP ([Edit=Require template editor access] (indefinite) [Move=Require template editor access] (indefinite))</title>
		<link rel="alternate" type="text/html" href="https://the-democratika.com/wiki/index.php?title=Module:Road_data/util&amp;diff=6725&amp;oldid=prev"/>
		<updated>2023-05-30T20:52:14Z</updated>

		<summary type="html">&lt;p&gt;Changed protection settings for &amp;quot;&lt;a href=&quot;/wiki/index.php/Module:Road_data/util&quot; title=&quot;Module:Road data/util&quot;&gt;Module:Road data/util&lt;/a&gt;&amp;quot;: &lt;a href=&quot;/wiki/index.php?title=WP:High-risk_templates&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;WP:High-risk templates (page does not exist)&quot;&gt;Highly visible template&lt;/a&gt;; requested at &lt;a href=&quot;/wiki/index.php?title=WP:RfPP&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;WP:RfPP (page does not exist)&quot;&gt;WP:RfPP&lt;/a&gt; ([Edit=Require template editor access] (indefinite) [Move=Require template editor access] (indefinite))&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local util = {}&lt;br /&gt;
&lt;br /&gt;
local insert = table.insert&lt;br /&gt;
local concat = table.concat&lt;br /&gt;
local format = mw.ustring.format&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
-- Add all entries in `arr` into `target`.&lt;br /&gt;
-- An error is raised if `overwrite` is not true&lt;br /&gt;
-- and any key in `arr` is already in `target`.&lt;br /&gt;
function util.addAll(target, arr, overwrite)&lt;br /&gt;
	if type(target) ~= &amp;quot;table&amp;quot; then&lt;br /&gt;
		error(&amp;quot;target is not a table&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	for key,value in pairs(arr) do&lt;br /&gt;
		if overwrite or target[key] == nil then&lt;br /&gt;
			target[key] = value&lt;br /&gt;
		else&lt;br /&gt;
			error(&amp;quot;Duplicate key: &amp;quot; .. tostring(key))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function comp(e1, e2)&lt;br /&gt;
	local t1 = type(e1)&lt;br /&gt;
	local t2 = type(e2)&lt;br /&gt;
	if t1 ~= t2 then return t1 &amp;lt; t2 end&lt;br /&gt;
	if t1 == &amp;quot;function&amp;quot; then&lt;br /&gt;
		error(&amp;quot;Unexpected function type&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	return e1 &amp;lt; e2&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local arrayToStringAux&lt;br /&gt;
arrayToStringAux = function(arr, indent)&lt;br /&gt;
	if type(arr) ~= &amp;quot;table&amp;quot; then&lt;br /&gt;
		error(&amp;quot;arr is not a table&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	if type(indent) ~= &amp;quot;number&amp;quot; then&lt;br /&gt;
		error(&amp;quot;indent is not a number&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	local result = {}&lt;br /&gt;
	local keys = {}&lt;br /&gt;
	for key in pairs(arr) do insert(keys, key) end&lt;br /&gt;
	table.sort(keys, comp)&lt;br /&gt;
	for _,key in ipairs(keys) do&lt;br /&gt;
		local value = arr[key]&lt;br /&gt;
		local keyPrint&lt;br /&gt;
		if type(key) == &amp;quot;string&amp;quot; then&lt;br /&gt;
			keyPrint = format(&amp;quot;\&amp;quot;%s\&amp;quot;&amp;quot;, key)&lt;br /&gt;
		else&lt;br /&gt;
			keyPrint = tostring(key)&lt;br /&gt;
		end&lt;br /&gt;
		local valuePrint&lt;br /&gt;
		if type(value) == &amp;quot;table&amp;quot; then&lt;br /&gt;
			valuePrint = format(&amp;quot;{\n%s\n%s}&amp;quot;,&lt;br /&gt;
				arrayToStringAux(value, indent + 4),&lt;br /&gt;
				string.rep(&amp;quot; &amp;quot;, indent))&lt;br /&gt;
		elseif type(value) == &amp;quot;string&amp;quot; then&lt;br /&gt;
			valuePrint = format(&amp;quot;\&amp;quot;%s\&amp;quot;&amp;quot;, value)&lt;br /&gt;
		else&lt;br /&gt;
			valuePrint = tostring(value)&lt;br /&gt;
		end&lt;br /&gt;
		insert(result, format(&amp;quot;%s[%s] = %s&amp;quot;,&lt;br /&gt;
			string.rep(&amp;quot; &amp;quot;, indent),&lt;br /&gt;
			keyPrint,&lt;br /&gt;
			valuePrint))&lt;br /&gt;
	end&lt;br /&gt;
	return concat(result, &amp;quot;, \n&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Return a string representation of `arr`.&lt;br /&gt;
function util.arrayToString(arr, indent)&lt;br /&gt;
	return arrayToStringAux(arr, indent or 0)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function convert(distance, multiplier, desiredPrec)&lt;br /&gt;
	if type(distance) ~= &amp;quot;string&amp;quot; then&lt;br /&gt;
		error(&amp;quot;distance is not a string&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	if type(multiplier) ~= &amp;quot;number&amp;quot; then&lt;br /&gt;
		error(&amp;quot;multiplier is not a number&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	-- Import math functions.&lt;br /&gt;
	local math = require &amp;quot;Module:Math&amp;quot;&lt;br /&gt;
	-- This function returns the precision of a given string representing a number.&lt;br /&gt;
	local precision = math._precision&lt;br /&gt;
	-- This function returns the order of magnitude of a given string representing a number.&lt;br /&gt;
	local order = math._order&lt;br /&gt;
	-- This function rounds a given number to the given number of digits.&lt;br /&gt;
	local round = math._precision_format&lt;br /&gt;
&lt;br /&gt;
	local prec = desiredPrec or precision(distance)&lt;br /&gt;
	if not desiredPrec then&lt;br /&gt;
		local ord = order(distance)&lt;br /&gt;
		-- Adjust precision based on multiplier, as done in {{convert}}.&lt;br /&gt;
		prec = prec - order(multiplier / 0.2)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local converted = distance * multiplier&lt;br /&gt;
	local magnitude = order(converted)&lt;br /&gt;
	if prec &amp;lt;= -magnitude then&lt;br /&gt;
		-- Ensure the result has at least two significant digits.&lt;br /&gt;
		prec = -magnitude + 1&lt;br /&gt;
	end&lt;br /&gt;
	return round(converted, prec)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[-&lt;br /&gt;
Convert length specified in one unit (mi or km) to length in the other unit.&lt;br /&gt;
@param #map&amp;lt;#string, #string&amp;gt; lengths&lt;br /&gt;
	a map from unit to distance (as a string) in that unit;&lt;br /&gt;
	may contain entry `prec` indicating desired conversion precision&lt;br /&gt;
@param #string blank text to be used if length is unspecified&lt;br /&gt;
@return #table a table containing the conversion result:&lt;br /&gt;
	orig = source unit;&lt;br /&gt;
	comp = target unit;&lt;br /&gt;
	mi = length in miles;&lt;br /&gt;
	ft = converted length in feet;&lt;br /&gt;
	km = length in kilometers;&lt;br /&gt;
	m = converted length in meters;&lt;br /&gt;
	error = error message, if any&lt;br /&gt;
]]&lt;br /&gt;
function util.convertLengths(lengths, blank)&lt;br /&gt;
	-- Import math functions.&lt;br /&gt;
	local math = require &amp;quot;Module:Math&amp;quot;&lt;br /&gt;
	-- In Lua, storing functions locally results in more efficient execution.&lt;br /&gt;
	-- This function rounds a given number to the given number of digits.&lt;br /&gt;
	local round = math._precision_format&lt;br /&gt;
	-- This function returns the precision of a given string representing a number.&lt;br /&gt;
	local precision = math._precision&lt;br /&gt;
&lt;br /&gt;
	local kmPerMile = 1.609344&lt;br /&gt;
	local ftPerMile = 5280&lt;br /&gt;
	-- The length in kilometers as passed to the function.&lt;br /&gt;
	local km = lengths.km&lt;br /&gt;
	-- The length in miles as passed to the function.&lt;br /&gt;
	local mi = lengths.mi&lt;br /&gt;
	-- Precision for the converted length.&lt;br /&gt;
	local prec = lengths.prec&lt;br /&gt;
	local errMsg = {}&lt;br /&gt;
	-- Sanitize inputs.&lt;br /&gt;
	local km_ = tonumber(km)&lt;br /&gt;
	if km and not km_ then&lt;br /&gt;
		insert(errMsg, util.err(&amp;quot;km is not a number&amp;quot;))&lt;br /&gt;
	end&lt;br /&gt;
	local mi_ = tonumber(mi)&lt;br /&gt;
	if mi and not mi_ then&lt;br /&gt;
		insert(errMsg, util.err(&amp;quot;mi is not a number&amp;quot;))&lt;br /&gt;
	end&lt;br /&gt;
	local prec_ = tonumber(prec)&lt;br /&gt;
	if prec and not prec_ then&lt;br /&gt;
		insert(errMsg, util.err(&amp;quot;prec is not a number&amp;quot;))&lt;br /&gt;
	end&lt;br /&gt;
	prec = prec_&lt;br /&gt;
&lt;br /&gt;
	local ft&lt;br /&gt;
	local m&lt;br /&gt;
	local orig = &amp;quot;mi&amp;quot;&lt;br /&gt;
	local comp = &amp;quot;km&amp;quot;&lt;br /&gt;
	if mi and km then&lt;br /&gt;
		insert(errMsg, util.err(&amp;quot;Both mi and km are specified&amp;quot;))&lt;br /&gt;
	elseif mi then&lt;br /&gt;
		-- Length in miles was passed.&lt;br /&gt;
		if mi_ then&lt;br /&gt;
			-- If `mi` is indeed a number, compute and round the length in kilometers.&lt;br /&gt;
			km = convert(mi, kmPerMile, prec)&lt;br /&gt;
			m = convert(mi, kmPerMile * 1000, prec)&lt;br /&gt;
			-- format mi (insert separators as in 1,000)&lt;br /&gt;
			mi = round(mi_, precision(mi))&lt;br /&gt;
		else&lt;br /&gt;
			-- `mi` is not a number.&lt;br /&gt;
			km = blank&lt;br /&gt;
			m = blank&lt;br /&gt;
		end&lt;br /&gt;
	elseif km then&lt;br /&gt;
		-- Length in kilometers was passed.&lt;br /&gt;
		-- Swap units.&lt;br /&gt;
		orig, comp = comp, orig&lt;br /&gt;
		if km_ then&lt;br /&gt;
			-- If `km` is indeed a number, compute and round the length in miles.&lt;br /&gt;
			mi = convert(km, 1 / kmPerMile, prec)&lt;br /&gt;
			ft = convert(km, ftPerMile / kmPerMile, prec)&lt;br /&gt;
			-- format km (insert separators as in 1,000)&lt;br /&gt;
			km = round(km_, precision(km))&lt;br /&gt;
		else&lt;br /&gt;
			-- `km` is not a number.&lt;br /&gt;
			mi = blank&lt;br /&gt;
			ft = blank&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		mi = blank&lt;br /&gt;
		ft = blank&lt;br /&gt;
		km = blank&lt;br /&gt;
		m = blank&lt;br /&gt;
	end&lt;br /&gt;
	local error = concat(errMsg)&lt;br /&gt;
	if error == &amp;quot;&amp;quot; then error = nil end&lt;br /&gt;
	return {mi = mi, ft = ft, km = km, m = m, orig = orig, comp = comp,&lt;br /&gt;
		error = error}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Generates wikitext error messages.&lt;br /&gt;
function util.err(msg)&lt;br /&gt;
	if msg == nil then&lt;br /&gt;
		error(&amp;quot;Unspecified error message&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	return format(&amp;#039;&amp;lt;strong class=&amp;quot;error&amp;quot;&amp;gt;Error: %s&amp;lt;/strong&amp;gt;&amp;#039;, msg)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return util&lt;/div&gt;</summary>
		<author><name>&gt;Isabelle Belato</name></author>
	</entry>
</feed>