<?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%3AVal</id>
	<title>Module:Val - 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%3AVal"/>
	<link rel="alternate" type="text/html" href="https://the-democratika.com/wiki/index.php?title=Module:Val&amp;action=history"/>
	<updated>2026-04-04T11:12:42Z</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:Val&amp;diff=7128&amp;oldid=prev</id>
		<title>&gt;Johnuniq: use i18n from Module:Val/sandbox added by User:Moroboshi</title>
		<link rel="alternate" type="text/html" href="https://the-democratika.com/wiki/index.php?title=Module:Val&amp;diff=7128&amp;oldid=prev"/>
		<updated>2022-06-30T03:19:56Z</updated>

		<summary type="html">&lt;p&gt;use i18n from &lt;a href=&quot;/wiki/index.php?title=Module:Val/sandbox&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;Module:Val/sandbox (page does not exist)&quot;&gt;Module:Val/sandbox&lt;/a&gt; added by &lt;a href=&quot;/wiki/index.php?title=User:Moroboshi&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;User:Moroboshi (page does not exist)&quot;&gt;User:Moroboshi&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;-- For Template:Val, output a number and optional unit.&lt;br /&gt;
-- Format options include scientific and uncertainty notations.&lt;br /&gt;
&lt;br /&gt;
local numdot = &amp;#039;.&amp;#039;  -- decimal mark (use &amp;#039;,&amp;#039; for Italian)&lt;br /&gt;
local numsep = &amp;#039;,&amp;#039;  -- group separator (use &amp;#039; &amp;#039; for Italian)&lt;br /&gt;
local mtext = {&lt;br /&gt;
	-- Message and other text that should be localized.&lt;br /&gt;
	[&amp;#039;mt-bad-exponent&amp;#039;] =       &amp;#039;exponent parameter (&amp;lt;b&amp;gt;e&amp;lt;/b&amp;gt;)&amp;#039;,&lt;br /&gt;
	[&amp;#039;mt-parameter&amp;#039;] =          &amp;#039;parameter &amp;#039;,&lt;br /&gt;
	[&amp;#039;mt-not-number&amp;#039;] =         &amp;#039;is not a valid number&amp;#039;,&lt;br /&gt;
	[&amp;#039;mt-cannot-range&amp;#039;] =       &amp;#039;cannot use a range if the first parameter includes &amp;quot;e&amp;quot;&amp;#039;,&lt;br /&gt;
	[&amp;#039;mt-need-range&amp;#039;] =         &amp;#039;needs a range in parameter 2&amp;#039;,&lt;br /&gt;
	[&amp;#039;mt-should-range&amp;#039;] =       &amp;#039;should be a range&amp;#039;,&lt;br /&gt;
	[&amp;#039;mt-cannot-with-e&amp;#039;] =      &amp;#039;cannot be used if the first parameter includes &amp;quot;e&amp;quot;&amp;#039;,&lt;br /&gt;
	[&amp;#039;mt-not-range&amp;#039;] =          &amp;#039;does not accept a range&amp;#039;,&lt;br /&gt;
	[&amp;#039;mt-cannot-e&amp;#039;] =           &amp;#039;cannot use e notation&amp;#039;,&lt;br /&gt;
	[&amp;#039;mt-too-many-parameter&amp;#039;] = &amp;#039;too many parameters&amp;#039;,&lt;br /&gt;
	[&amp;#039;mt-need-number&amp;#039;] =        &amp;#039;need a number after the last parameter because it is a range.&amp;#039;,&lt;br /&gt;
	[&amp;#039;mt-ignore-parameter4&amp;#039;] =  &amp;#039;Val parameter 4 ignored&amp;#039;,&lt;br /&gt;
	[&amp;#039;mt-val-not-supported&amp;#039;] =  &amp;#039;Val parameter &amp;quot;%s=%s&amp;quot; is not supported&amp;#039;,&lt;br /&gt;
	[&amp;#039;mt-invalid-scale&amp;#039;] =      &amp;#039;Unit &amp;quot;%s&amp;quot; has invalid scale &amp;quot;%s&amp;quot;&amp;#039;,&lt;br /&gt;
	[&amp;#039;mt-both-u-ul&amp;#039;] =          &amp;#039;unit (&amp;lt;b&amp;gt;u&amp;lt;/b&amp;gt;) and unit with link (&amp;lt;b&amp;gt;ul&amp;lt;/b&amp;gt;) are both specified, only one is allowed.&amp;#039;,&lt;br /&gt;
	[&amp;#039;mt-both-up-upl&amp;#039;] =        &amp;#039;unit per (&amp;lt;b&amp;gt;up&amp;lt;/b&amp;gt;) and unit per with link (&amp;lt;b&amp;gt;upl&amp;lt;/b&amp;gt;) are both specified, only one is allowed.&amp;#039;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local data_module = &amp;#039;Module:Val/units&amp;#039;&lt;br /&gt;
local convert_module = &amp;#039;Module:Convert&amp;#039;&lt;br /&gt;
&lt;br /&gt;
local function valerror(msg, nocat, iswarning)&lt;br /&gt;
	-- Return formatted message text for an error or warning.&lt;br /&gt;
	-- Can append &amp;quot;#FormattingError&amp;quot; to URL of a page with a problem to find it.&lt;br /&gt;
	local anchor = &amp;#039;&amp;lt;span id=&amp;quot;FormattingError&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
	local body, category&lt;br /&gt;
	if nocat or mw.title.getCurrentTitle():inNamespaces(1, 2, 3, 5) then&lt;br /&gt;
		-- No category in Talk, User, User_talk, or Wikipedia_talk.&lt;br /&gt;
		category = &amp;#039;&amp;#039;&lt;br /&gt;
	else&lt;br /&gt;
		category = &amp;#039;[[Category:Pages with incorrect formatting templates use]]&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	iswarning = false  -- problems are infrequent so try showing large error so editor will notice&lt;br /&gt;
	if iswarning then&lt;br /&gt;
		body = &amp;#039;&amp;lt;sup class=&amp;quot;noprint Inline-Template&amp;quot; style=&amp;quot;white-space:nowrap;&amp;quot;&amp;gt;&amp;#039; ..&lt;br /&gt;
			&amp;#039;[[Template:Val|&amp;lt;span title=&amp;quot;&amp;#039; ..&lt;br /&gt;
			msg:gsub(&amp;#039;&amp;quot;&amp;#039;, &amp;#039;&amp;amp;quot;&amp;#039;) ..&lt;br /&gt;
			&amp;#039;&amp;quot;&amp;gt;warning&amp;lt;/span&amp;gt;]]&amp;lt;/sup&amp;gt;&amp;#039;&lt;br /&gt;
	else&lt;br /&gt;
		body = &amp;#039;&amp;lt;strong class=&amp;quot;error&amp;quot;&amp;gt;&amp;#039; ..&lt;br /&gt;
			&amp;#039;Error in &amp;amp;#123;&amp;amp;#123;[[Template:val|val]]&amp;amp;#125;&amp;amp;#125;: &amp;#039; ..&lt;br /&gt;
			msg ..&lt;br /&gt;
			&amp;#039;&amp;lt;/strong&amp;gt;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	return anchor .. body .. category&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local range_types = {&lt;br /&gt;
	-- No need for &amp;#039;&amp;amp;nbsp;&amp;#039; because nowrap applies to all output.&lt;br /&gt;
	[&amp;quot;,&amp;quot;]   = &amp;quot;, &amp;quot;,&lt;br /&gt;
	[&amp;quot;by&amp;quot;]  = &amp;quot; by &amp;quot;,&lt;br /&gt;
	[&amp;quot;-&amp;quot;]   = &amp;quot;–&amp;quot;,&lt;br /&gt;
	[&amp;quot;–&amp;quot;]   = &amp;quot;–&amp;quot;,&lt;br /&gt;
	[&amp;quot;and&amp;quot;] = &amp;quot; and &amp;quot;,&lt;br /&gt;
	[&amp;quot;or&amp;quot;]  = &amp;quot; or &amp;quot; ,&lt;br /&gt;
	[&amp;quot;to&amp;quot;]  = &amp;quot; to &amp;quot; ,&lt;br /&gt;
	[&amp;quot;x&amp;quot;]   = &amp;quot; × &amp;quot;,&lt;br /&gt;
	[&amp;quot;×&amp;quot;]   = &amp;quot; × &amp;quot;,&lt;br /&gt;
	[&amp;quot;/&amp;quot;]   = &amp;quot;/&amp;quot;,&lt;br /&gt;
}&lt;br /&gt;
local range_repeat_unit = {&lt;br /&gt;
	-- WP:UNIT wants unit repeated when a &amp;quot;multiply&amp;quot; range is used.&lt;br /&gt;
	[&amp;quot;x&amp;quot;]   = true,&lt;br /&gt;
	[&amp;quot;×&amp;quot;]   = true,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local function extract_item(index, numbers, arg)&lt;br /&gt;
	-- Extract an item from arg and store the result in numbers[index].&lt;br /&gt;
	-- If no argument or if argument is valid, return nil (no error);&lt;br /&gt;
	-- otherwise, return an error message.&lt;br /&gt;
	-- The stored result is:&lt;br /&gt;
	-- * a table for a number (empty if there was no specified number); or&lt;br /&gt;
	-- * a string for range text&lt;br /&gt;
	-- Input like 1e3 is regarded as invalid for all except argument 1&lt;br /&gt;
	-- which accepts e notation as an alternative to the &amp;#039;e&amp;#039; argument.&lt;br /&gt;
	-- Input group separators are removed.&lt;br /&gt;
	local which = index&lt;br /&gt;
	local function fail(msg)&lt;br /&gt;
		local description&lt;br /&gt;
		if which == &amp;#039;e&amp;#039; then&lt;br /&gt;
			description = mtext[&amp;#039;mt-bad-exponent&amp;#039;]&lt;br /&gt;
		else&lt;br /&gt;
			description = mtext[&amp;#039;mt-parameter&amp;#039;] .. which&lt;br /&gt;
		end&lt;br /&gt;
		return description .. &amp;#039; &amp;#039; .. (msg or mtext[&amp;#039;mt-not-number&amp;#039;]) .. &amp;#039;.&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	local result = {}&lt;br /&gt;
	local range = range_types[arg]&lt;br /&gt;
	if range then&lt;br /&gt;
		if type(index) == &amp;#039;number&amp;#039; and (index % 2 == 0) then&lt;br /&gt;
			if index == 2 then&lt;br /&gt;
				if numbers[1] and numbers[1].exp then&lt;br /&gt;
					return fail(mtext[&amp;#039;mt-cannot-range&amp;#039;])&lt;br /&gt;
				end&lt;br /&gt;
				numbers.has_ranges = true&lt;br /&gt;
			else&lt;br /&gt;
				if not numbers.has_ranges then&lt;br /&gt;
					return fail(mtext[&amp;#039;mt-need-range&amp;#039;])&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			numbers[index] = range&lt;br /&gt;
			if range_repeat_unit[arg] then&lt;br /&gt;
				-- Any &amp;quot;repeat&amp;quot; range forces unit (if any) to be repeated for all items.&lt;br /&gt;
				numbers.isrepeat = true&lt;br /&gt;
			end&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
		return fail(mtext[&amp;#039;mt-not-range&amp;#039;])&lt;br /&gt;
	end&lt;br /&gt;
	if numbers.has_ranges and type(index) == &amp;#039;number&amp;#039; and (index % 2 == 0) then&lt;br /&gt;
		return fail(mtext[&amp;#039;mt-should-range&amp;#039;])&lt;br /&gt;
	end&lt;br /&gt;
	if index == &amp;#039;e&amp;#039; then&lt;br /&gt;
		local e = numbers[1] and numbers[1].exp&lt;br /&gt;
		if e then&lt;br /&gt;
			if arg then&lt;br /&gt;
				return fail(mtext[&amp;#039;mt-cannot-with-e&amp;#039;])&lt;br /&gt;
			end&lt;br /&gt;
			arg = e&lt;br /&gt;
			which = 1&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if arg and arg ~= &amp;#039;&amp;#039; then&lt;br /&gt;
		arg = arg:gsub(numsep, &amp;#039;&amp;#039;)&lt;br /&gt;
		if numdot ~= &amp;#039;.&amp;#039; then&lt;br /&gt;
			arg = arg:gsub(numdot, &amp;#039;.&amp;#039;)&lt;br /&gt;
		end&lt;br /&gt;
		if arg:sub(1, 1) == &amp;#039;(&amp;#039; and arg:sub(-1) == &amp;#039;)&amp;#039; then&lt;br /&gt;
			result.parens = true&lt;br /&gt;
			arg = arg:sub(2, -2)&lt;br /&gt;
		end&lt;br /&gt;
		local a, b = arg:match(&amp;#039;^(.+)[Ee](.+)$&amp;#039;)&lt;br /&gt;
		if a then&lt;br /&gt;
			if index == 1 then&lt;br /&gt;
				arg = a&lt;br /&gt;
				result.exp = b&lt;br /&gt;
			else&lt;br /&gt;
				return fail(mtext[&amp;#039;mt-cannot-e&amp;#039;])&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		local isnegative, propersign, prefix&lt;br /&gt;
		local minus = &amp;#039;−&amp;#039;&lt;br /&gt;
		prefix, arg = arg:match(&amp;#039;^(.-)([%d.]+)$&amp;#039;)&lt;br /&gt;
		local value = tonumber(arg)&lt;br /&gt;
		if not value then&lt;br /&gt;
			return fail()&lt;br /&gt;
		end&lt;br /&gt;
		if arg:sub(1, 1) == &amp;#039;.&amp;#039; then&lt;br /&gt;
			arg = &amp;#039;0&amp;#039; .. arg&lt;br /&gt;
		end&lt;br /&gt;
		if prefix == &amp;#039;&amp;#039; then&lt;br /&gt;
			-- Ignore.&lt;br /&gt;
		elseif prefix == &amp;#039;±&amp;#039; then&lt;br /&gt;
			-- Display for first number, ignore for others.&lt;br /&gt;
			if index == 1 then&lt;br /&gt;
				propersign = &amp;#039;±&amp;#039;&lt;br /&gt;
			end&lt;br /&gt;
		elseif prefix == &amp;#039;+&amp;#039; then&lt;br /&gt;
			propersign = &amp;#039;+&amp;#039;&lt;br /&gt;
		elseif prefix == &amp;#039;-&amp;#039; or prefix == minus then&lt;br /&gt;
			propersign = minus&lt;br /&gt;
			isnegative = true&lt;br /&gt;
		else&lt;br /&gt;
			return fail()&lt;br /&gt;
		end&lt;br /&gt;
		result.clean = arg&lt;br /&gt;
		result.sign = propersign or &amp;#039;&amp;#039;&lt;br /&gt;
		result.value = isnegative and -value or value&lt;br /&gt;
	end&lt;br /&gt;
	numbers[index] = result&lt;br /&gt;
	return nil  -- no error&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function get_args(numbers, args)&lt;br /&gt;
	-- Extract arguments and store the results in numbers.&lt;br /&gt;
	-- Return nothing (no error) if ok; otherwise, return an error message.&lt;br /&gt;
	for index = 1, 99 do&lt;br /&gt;
		local which = index&lt;br /&gt;
		local arg = args[which]  -- has been trimmed&lt;br /&gt;
		if not arg then&lt;br /&gt;
			which = &amp;#039;e&amp;#039;&lt;br /&gt;
			arg = args[which]&lt;br /&gt;
		end&lt;br /&gt;
		local msg = extract_item(which, numbers, arg)&lt;br /&gt;
		if msg then&lt;br /&gt;
			return msg&lt;br /&gt;
		end&lt;br /&gt;
		if which == &amp;#039;e&amp;#039; then&lt;br /&gt;
			break&lt;br /&gt;
		end&lt;br /&gt;
		if index &amp;gt; 19 then&lt;br /&gt;
			return mtext[&amp;#039;mt-too-many-parameter&amp;#039;]&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if numbers.has_ranges and (#numbers % 2 == 0) then&lt;br /&gt;
		return mtext[&amp;#039;mt-need-number&amp;#039;]&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function get_scale(text, ucode)&lt;br /&gt;
	-- Return the value of text as a number, or throw an error.&lt;br /&gt;
	-- This supports extremely basic expressions of the form:&lt;br /&gt;
	--   a / b&lt;br /&gt;
	--   a ^ b&lt;br /&gt;
	-- where a and b are numbers or &amp;#039;pi&amp;#039;.&lt;br /&gt;
	local n = tonumber(text)&lt;br /&gt;
	if n then&lt;br /&gt;
		return n&lt;br /&gt;
	end&lt;br /&gt;
	n = text:gsub(&amp;#039;pi&amp;#039;, math.pi)&lt;br /&gt;
	for _, op in ipairs({ &amp;#039;/&amp;#039;, &amp;#039;^&amp;#039; }) do&lt;br /&gt;
		local a, b = n:match(&amp;#039;^(.-)&amp;#039; .. op .. &amp;#039;(.*)$&amp;#039;)&lt;br /&gt;
		if a then&lt;br /&gt;
			a = tonumber(a)&lt;br /&gt;
			b = tonumber(b)&lt;br /&gt;
			if a and b then&lt;br /&gt;
				if op == &amp;#039;/&amp;#039; then&lt;br /&gt;
					return a / b&lt;br /&gt;
				elseif op == &amp;#039;^&amp;#039; then&lt;br /&gt;
					return a ^ b&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			break&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	error(string.format(mtext[&amp;#039;mt-invalid-scale&amp;#039;], ucode, text))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function get_builtin_unit(ucode, definitions)&lt;br /&gt;
	-- Return table of information for the specified built-in unit, or nil if not known.&lt;br /&gt;
	-- Each defined unit code must be followed by two spaces (not tab characters).&lt;br /&gt;
	local _, pos = definitions:find(&amp;#039;\n&amp;#039; .. ucode .. &amp;#039;  &amp;#039;, 1, true)&lt;br /&gt;
	if pos then&lt;br /&gt;
		local endline = definitions:find(&amp;#039;%s*\n&amp;#039;, pos)&lt;br /&gt;
		if endline then&lt;br /&gt;
			local result = {}&lt;br /&gt;
			local n = 0&lt;br /&gt;
			local text = definitions:sub(pos + 1, endline - 1):gsub(&amp;#039;%s%s+&amp;#039;, &amp;#039;\t&amp;#039;)&lt;br /&gt;
			for item in (text .. &amp;#039;\t&amp;#039;):gmatch(&amp;#039;(%S.-)\t&amp;#039;) do&lt;br /&gt;
				if item == &amp;#039;ALIAS&amp;#039; then&lt;br /&gt;
					result.alias = true&lt;br /&gt;
				elseif item == &amp;#039;ANGLE&amp;#039; then&lt;br /&gt;
					result.isangle = true&lt;br /&gt;
					result.nospace = true&lt;br /&gt;
				elseif item == &amp;#039;NOSPACE&amp;#039; then&lt;br /&gt;
					result.nospace = true&lt;br /&gt;
				elseif item == &amp;#039;SI&amp;#039; then&lt;br /&gt;
					result.si = true&lt;br /&gt;
				else&lt;br /&gt;
					n = n + 1&lt;br /&gt;
					if n == 1 then&lt;br /&gt;
						local link, symbol = item:match(&amp;#039;^%[%[([^|]+)|(.+)%]%]$&amp;#039;)&lt;br /&gt;
						if link then&lt;br /&gt;
							result.symbol = symbol&lt;br /&gt;
							result.link = link&lt;br /&gt;
							n = 2&lt;br /&gt;
						else&lt;br /&gt;
							result.symbol = item&lt;br /&gt;
						end&lt;br /&gt;
					elseif n == 2 then&lt;br /&gt;
						result.link = item&lt;br /&gt;
					elseif n == 3 then&lt;br /&gt;
						result.scale_text = item&lt;br /&gt;
						result.scale = get_scale(item, ucode)&lt;br /&gt;
					else&lt;br /&gt;
						result.more_ignored = item&lt;br /&gt;
						break&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			if result.si then&lt;br /&gt;
				local s = result.symbol&lt;br /&gt;
				if ucode == &amp;#039;mc&amp;#039; .. s or ucode == &amp;#039;mu&amp;#039; .. s then&lt;br /&gt;
					result.ucode = &amp;#039;µ&amp;#039; .. s  -- unit code for convert should be this&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			if n &amp;gt;= 2 or (n &amp;gt;= 1 and result.alias) then&lt;br /&gt;
				return result&lt;br /&gt;
			end&lt;br /&gt;
			-- Ignore invalid definition, treating it as a comment.&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function convert_lookup(ucode, value, scaled_top, want_link, si, options)&lt;br /&gt;
	local lookup = require(convert_module)._unit&lt;br /&gt;
	return lookup(ucode, {&lt;br /&gt;
			value = value,&lt;br /&gt;
			scaled_top = scaled_top,&lt;br /&gt;
			link = want_link,&lt;br /&gt;
			si = si,&lt;br /&gt;
			sort = options.sortable,&lt;br /&gt;
		})&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function get_unit(ucode, value, scaled_top, options)&lt;br /&gt;
	local want_link = options.want_link&lt;br /&gt;
	if scaled_top then&lt;br /&gt;
		want_link = options.want_per_link&lt;br /&gt;
	end&lt;br /&gt;
	local data = mw.loadData(data_module)&lt;br /&gt;
	local result = options.want_longscale and&lt;br /&gt;
		get_builtin_unit(ucode, data.builtin_units_long_scale) or&lt;br /&gt;
		get_builtin_unit(ucode, data.builtin_units)&lt;br /&gt;
	local si, use_convert&lt;br /&gt;
	if result then&lt;br /&gt;
		if result.alias then&lt;br /&gt;
			ucode = result.symbol&lt;br /&gt;
			use_convert = true&lt;br /&gt;
		end&lt;br /&gt;
		if result.scale then&lt;br /&gt;
			-- Setting si means convert will use the unit as given, and the sort key&lt;br /&gt;
			-- will be calculated from the value without any extra scaling that may&lt;br /&gt;
			-- occur if convert found the unit code. For example, if val defines the&lt;br /&gt;
			-- unit &amp;#039;year&amp;#039; with a scale and if si were not set, convert would also apply&lt;br /&gt;
			-- its own scale because convert knows that a year is 31,557,600 seconds.&lt;br /&gt;
			si = { result.symbol, result.link }&lt;br /&gt;
			value = value * result.scale&lt;br /&gt;
		end&lt;br /&gt;
		if result.si then&lt;br /&gt;
			ucode = result.ucode or ucode&lt;br /&gt;
			si = { result.symbol, result.link }&lt;br /&gt;
			use_convert = true&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		result = {}&lt;br /&gt;
		use_convert = true&lt;br /&gt;
	end&lt;br /&gt;
	local convert_unit = convert_lookup(ucode, value, scaled_top, want_link, si, options)&lt;br /&gt;
	result.sortkey = convert_unit.sortspan&lt;br /&gt;
	if use_convert then&lt;br /&gt;
		result.text = convert_unit.text&lt;br /&gt;
		result.scaled_top = convert_unit.scaled_value&lt;br /&gt;
	else&lt;br /&gt;
		if want_link then&lt;br /&gt;
			result.text = &amp;#039;[[&amp;#039; .. result.link .. &amp;#039;|&amp;#039; .. result.symbol .. &amp;#039;]]&amp;#039;&lt;br /&gt;
		else&lt;br /&gt;
			result.text = result.symbol&lt;br /&gt;
		end&lt;br /&gt;
		result.scaled_top = value&lt;br /&gt;
	end&lt;br /&gt;
	return result&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function makeunit(value, options)&lt;br /&gt;
	-- Return table of information for the requested unit and options, or&lt;br /&gt;
	-- return nil if no unit.&lt;br /&gt;
	options = options or {}&lt;br /&gt;
	local unit&lt;br /&gt;
	local ucode = options.u&lt;br /&gt;
	local percode = options.per&lt;br /&gt;
	if ucode then&lt;br /&gt;
		unit = get_unit(ucode, value, nil, options)&lt;br /&gt;
	elseif percode then&lt;br /&gt;
		unit = { nospace = true, scaled_top = value }&lt;br /&gt;
	else&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	local text = unit.text or &amp;#039;&amp;#039;&lt;br /&gt;
	local sortkey = unit.sortkey&lt;br /&gt;
	if percode then&lt;br /&gt;
		local function bracketed(code, text)&lt;br /&gt;
			return code:find(&amp;#039;[*./]&amp;#039;) and &amp;#039;(&amp;#039; .. text .. &amp;#039;)&amp;#039; or text&lt;br /&gt;
		end&lt;br /&gt;
		local perunit = get_unit(percode, 1, unit.scaled_top, options)&lt;br /&gt;
		text = (ucode and bracketed(ucode, text) or &amp;#039;&amp;#039;) ..&lt;br /&gt;
				&amp;#039;/&amp;#039; .. bracketed(percode, perunit.text)&lt;br /&gt;
		sortkey = perunit.sortkey&lt;br /&gt;
	end&lt;br /&gt;
	if not (unit.nospace or options.nospace) then&lt;br /&gt;
		text = &amp;#039;&amp;amp;nbsp;&amp;#039; .. text&lt;br /&gt;
	end&lt;br /&gt;
	return { text = text, isangle = unit.isangle, sortkey = sortkey }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function list_units(mode)&lt;br /&gt;
	-- Return wikitext to list the built-in units.&lt;br /&gt;
	-- A unit code should not contain wikimarkup so don&amp;#039;t bother escaping.&lt;br /&gt;
	local data = mw.loadData(data_module)&lt;br /&gt;
	local definitions = data.builtin_units .. data.builtin_units_long_scale&lt;br /&gt;
	local last_was_blank = true&lt;br /&gt;
	local n = 0&lt;br /&gt;
	local result = {}&lt;br /&gt;
	local function add(line)&lt;br /&gt;
		if line == &amp;#039;&amp;#039; then&lt;br /&gt;
			last_was_blank = true&lt;br /&gt;
		else&lt;br /&gt;
			if last_was_blank and n &amp;gt; 0 then&lt;br /&gt;
				n = n + 1&lt;br /&gt;
				result[n] = &amp;#039;&amp;#039;&lt;br /&gt;
			end&lt;br /&gt;
			last_was_blank = false&lt;br /&gt;
			n = n + 1&lt;br /&gt;
			result[n] = line&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local si_prefixes = {&lt;br /&gt;
		-- These are the prefixes recognized by convert; u is accepted for micro.&lt;br /&gt;
		y = &amp;#039;y&amp;#039;,&lt;br /&gt;
		z = &amp;#039;z&amp;#039;,&lt;br /&gt;
		a = &amp;#039;a&amp;#039;,&lt;br /&gt;
		f = &amp;#039;f&amp;#039;,&lt;br /&gt;
		p = &amp;#039;p&amp;#039;,&lt;br /&gt;
		n = &amp;#039;n&amp;#039;,&lt;br /&gt;
		u = &amp;#039;µ&amp;#039;,&lt;br /&gt;
		[&amp;#039;µ&amp;#039;] = &amp;#039;µ&amp;#039;,&lt;br /&gt;
		m = &amp;#039;m&amp;#039;,&lt;br /&gt;
		c = &amp;#039;c&amp;#039;,&lt;br /&gt;
		d = &amp;#039;d&amp;#039;,&lt;br /&gt;
		da = &amp;#039;da&amp;#039;,&lt;br /&gt;
		h = &amp;#039;h&amp;#039;,&lt;br /&gt;
		k = &amp;#039;k&amp;#039;,&lt;br /&gt;
		M = &amp;#039;M&amp;#039;,&lt;br /&gt;
		G = &amp;#039;G&amp;#039;,&lt;br /&gt;
		T = &amp;#039;T&amp;#039;,&lt;br /&gt;
		P = &amp;#039;P&amp;#039;,&lt;br /&gt;
		E = &amp;#039;E&amp;#039;,&lt;br /&gt;
		Z = &amp;#039;Z&amp;#039;,&lt;br /&gt;
		Y = &amp;#039;Y&amp;#039;,&lt;br /&gt;
	}&lt;br /&gt;
	local function is_valid(ucode, unit)&lt;br /&gt;
		if unit and not unit.more_ignored then&lt;br /&gt;
			assert(type(unit.symbol) == &amp;#039;string&amp;#039; and unit.symbol ~= &amp;#039;&amp;#039;)&lt;br /&gt;
			if unit.alias then&lt;br /&gt;
				if unit.link or unit.scale_text or unit.si then&lt;br /&gt;
					return false&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			if unit.si then&lt;br /&gt;
				if unit.scale_text then&lt;br /&gt;
					return false&lt;br /&gt;
				end&lt;br /&gt;
				ucode = unit.ucode or ucode&lt;br /&gt;
				local base = unit.symbol&lt;br /&gt;
				if ucode == base then&lt;br /&gt;
					unit.display = base&lt;br /&gt;
					return true&lt;br /&gt;
				end&lt;br /&gt;
				local plen = #ucode - #base&lt;br /&gt;
				if plen &amp;gt; 0 then&lt;br /&gt;
					local prefix = si_prefixes[ucode:sub(1, plen)]&lt;br /&gt;
					if prefix and ucode:sub(plen + 1) == base then&lt;br /&gt;
						unit.display = prefix .. base&lt;br /&gt;
						return true&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				unit.display = unit.symbol&lt;br /&gt;
				return true&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	local lookup = require(convert_module)._unit&lt;br /&gt;
	local function show_convert(ucode, unit)&lt;br /&gt;
		-- If a built-in unit defines a scale or sets the SI flag, any unit defined in&lt;br /&gt;
		-- convert is not used (the scale or SI prefix&amp;#039;s scale is used for a sort key).&lt;br /&gt;
		-- If there is no scale or SI flag, and the unit is not defined in convert,&lt;br /&gt;
		-- the sort key may not be correct; this allows such units to be identified.&lt;br /&gt;
		if not (unit.si or unit.scale_text) then&lt;br /&gt;
			if mode == &amp;#039;convert&amp;#039; then&lt;br /&gt;
				unit.show = not lookup(unit.alias and unit.symbol or ucode).unknown&lt;br /&gt;
				unit.show_text = &amp;#039;CONVERT&amp;#039;&lt;br /&gt;
			elseif mode == &amp;#039;unknown&amp;#039; then&lt;br /&gt;
				unit.show = lookup(unit.alias and unit.symbol or ucode).unknown&lt;br /&gt;
				unit.show_text = &amp;#039;UNKNOWN&amp;#039;&lt;br /&gt;
			elseif not unit.alias then&lt;br /&gt;
				-- Show convert&amp;#039;s scale in square brackets (&amp;#039;[1]&amp;#039; for an unknown unit).&lt;br /&gt;
				-- Don&amp;#039;t show scale for an alias because it&amp;#039;s misleading for temperature&lt;br /&gt;
				-- and an alias is probably not useful for anything else.&lt;br /&gt;
				local scale = lookup(ucode, {value=1, sort=&amp;#039;on&amp;#039;}).scaled_value&lt;br /&gt;
				if type(scale) == &amp;#039;number&amp;#039; then&lt;br /&gt;
					scale = string.format(&amp;#039;%.5g&amp;#039;, scale):gsub(&amp;#039;e%+?(%-?)0*(%d+)&amp;#039;, &amp;#039;e%1%2&amp;#039;)&lt;br /&gt;
				else&lt;br /&gt;
					scale = &amp;#039;?&amp;#039;&lt;br /&gt;
				end&lt;br /&gt;
				unit.show = true&lt;br /&gt;
				unit.show_text = &amp;#039;[&amp;#039; .. scale .. &amp;#039;]&amp;#039;&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	for line in definitions:gmatch(&amp;#039;([^\n]*)\n&amp;#039;) do&lt;br /&gt;
		local pos, _ = line:find(&amp;#039;  &amp;#039;, 1, true)&lt;br /&gt;
		if pos then&lt;br /&gt;
			local ucode = line:sub(1, pos - 1)&lt;br /&gt;
			local unit = get_builtin_unit(ucode, &amp;#039;\n&amp;#039; .. line .. &amp;#039;\n&amp;#039;)&lt;br /&gt;
			if is_valid(ucode, unit) then&lt;br /&gt;
				show_convert(ucode, unit)&lt;br /&gt;
				local flags, text&lt;br /&gt;
				if unit.alias then&lt;br /&gt;
					text = unit.symbol&lt;br /&gt;
				else&lt;br /&gt;
					text = &amp;#039;[[&amp;#039; .. unit.link .. &amp;#039;|&amp;#039; .. unit.display .. &amp;#039;]]&amp;#039;&lt;br /&gt;
				end&lt;br /&gt;
				if unit.isangle then&lt;br /&gt;
					unit.nospace = nil  -- don&amp;#039;t show redundant flag&lt;br /&gt;
				end&lt;br /&gt;
				for _, f in ipairs({&lt;br /&gt;
						{ &amp;#039;alias&amp;#039;, &amp;#039;ALIAS&amp;#039; },&lt;br /&gt;
						{ &amp;#039;isangle&amp;#039;, &amp;#039;ANGLE&amp;#039; },&lt;br /&gt;
						{ &amp;#039;nospace&amp;#039;, &amp;#039;NOSPACE&amp;#039; },&lt;br /&gt;
						{ &amp;#039;si&amp;#039;, &amp;#039;SI&amp;#039; },&lt;br /&gt;
						{ &amp;#039;scale_text&amp;#039;, unit.scale_text },&lt;br /&gt;
						{ &amp;#039;show&amp;#039;, unit.show_text },&lt;br /&gt;
					}) do&lt;br /&gt;
					if unit[f[1]] then&lt;br /&gt;
						local t = f[2]&lt;br /&gt;
						if t:match(&amp;#039;^%u+$&amp;#039;) then&lt;br /&gt;
							t = &amp;#039;&amp;lt;small&amp;gt;&amp;#039; .. t .. &amp;#039;&amp;lt;/small&amp;gt;&amp;#039;&lt;br /&gt;
						end&lt;br /&gt;
						if flags then&lt;br /&gt;
							flags = flags .. &amp;#039; &amp;#039; .. t&lt;br /&gt;
						else&lt;br /&gt;
							flags = t&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
				if flags then&lt;br /&gt;
					text = text .. &amp;#039; • &amp;#039; .. flags&lt;br /&gt;
				end&lt;br /&gt;
				add(ucode .. &amp;#039; = &amp;#039; .. text .. &amp;#039;&amp;lt;br /&amp;gt;&amp;#039;)&lt;br /&gt;
			else&lt;br /&gt;
				add(line .. &amp;#039; ◆ &amp;lt;b&amp;gt;invalid definition&amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;&amp;#039;)&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			add(line)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return table.concat(result, &amp;#039;\n&amp;#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local delimit_groups = require(&amp;#039;Module:Gapnum&amp;#039;).groups&lt;br /&gt;
local function delimit(sign, numstr, fmt)&lt;br /&gt;
	-- Return sign and numstr (unsigned digits or numdot only) after formatting.&lt;br /&gt;
	-- Four-digit integers are not formatted with gaps.&lt;br /&gt;
	fmt = (fmt or &amp;#039;&amp;#039;):lower()&lt;br /&gt;
	if fmt == &amp;#039;none&amp;#039; or (fmt == &amp;#039;&amp;#039; and #numstr == 4 and numstr:match(&amp;#039;^%d+$&amp;#039;)) then&lt;br /&gt;
		return sign .. numstr&lt;br /&gt;
	end&lt;br /&gt;
	-- Group number by integer and decimal parts.&lt;br /&gt;
	-- If there is no decimal part, delimit_groups returns only one table.&lt;br /&gt;
	local ipart, dpart = delimit_groups(numstr)&lt;br /&gt;
	local result&lt;br /&gt;
	if fmt == &amp;#039;commas&amp;#039; then&lt;br /&gt;
		result = sign .. table.concat(ipart, numsep)&lt;br /&gt;
		if dpart then&lt;br /&gt;
			result = result .. numdot .. table.concat(dpart)&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		-- Delimit with a small gap by default.&lt;br /&gt;
		local groups = {}&lt;br /&gt;
		groups[1] = table.remove(ipart, 1)&lt;br /&gt;
		for _, v in ipairs(ipart) do&lt;br /&gt;
			table.insert(groups, &amp;#039;&amp;lt;span style=&amp;quot;margin-left:.25em;&amp;quot;&amp;gt;&amp;#039; .. v .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;)&lt;br /&gt;
		end&lt;br /&gt;
		if dpart then&lt;br /&gt;
			table.insert(groups, numdot .. (table.remove(dpart, 1) or &amp;#039;&amp;#039;))&lt;br /&gt;
			for _, v in ipairs(dpart) do&lt;br /&gt;
				table.insert(groups, &amp;#039;&amp;lt;span style=&amp;quot;margin-left:.25em;&amp;quot;&amp;gt;&amp;#039; .. v .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		result = sign .. table.concat(groups)&lt;br /&gt;
	end&lt;br /&gt;
	return result&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function sup_sub(sup, sub, align)&lt;br /&gt;
	-- Return the same result as Module:Su except val defaults to align=right.&lt;br /&gt;
	if align == &amp;#039;l&amp;#039; or align == &amp;#039;left&amp;#039; then&lt;br /&gt;
		align = &amp;#039;left&amp;#039;&lt;br /&gt;
	elseif align == &amp;#039;c&amp;#039; or align == &amp;#039;center&amp;#039; then&lt;br /&gt;
		align = &amp;#039;center&amp;#039;&lt;br /&gt;
	else&lt;br /&gt;
		align = &amp;#039;right&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	return &amp;#039;&amp;lt;span style=&amp;quot;display:inline-block;margin-bottom:-0.3em;vertical-align:-0.4em;line-height:1.2em;font-size:85%;text-align:&amp;#039; ..&lt;br /&gt;
		align .. &amp;#039;;&amp;quot;&amp;gt;&amp;#039; .. sup .. &amp;#039;&amp;lt;br /&amp;gt;&amp;#039; .. sub .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function range_text(items, unit_table, options)&lt;br /&gt;
	local fmt = options.fmt&lt;br /&gt;
	local nend = items.nend or &amp;#039;&amp;#039;&lt;br /&gt;
	if items.isrepeat or unit_table.isangle then&lt;br /&gt;
		nend = nend .. unit_table.text&lt;br /&gt;
	end&lt;br /&gt;
	local text = &amp;#039;&amp;#039;&lt;br /&gt;
	for i = 1, #items do&lt;br /&gt;
		if i % 2 == 0 then&lt;br /&gt;
			text = text .. items[i]&lt;br /&gt;
		else&lt;br /&gt;
			text = text .. delimit(items[i].sign, items[i].clean, fmt) .. nend&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return text&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function uncertainty_text(uncertainty, unit_table, options)&lt;br /&gt;
	local angle, text, need_parens&lt;br /&gt;
	if unit_table.isangle then&lt;br /&gt;
		angle = unit_table.text&lt;br /&gt;
	end&lt;br /&gt;
	local upper = uncertainty.upper or {}&lt;br /&gt;
	local lower = uncertainty.lower or {}&lt;br /&gt;
	local uncU = upper.clean&lt;br /&gt;
	if uncU then&lt;br /&gt;
		local fmt = options.fmt&lt;br /&gt;
		local uncL = lower.clean&lt;br /&gt;
		if uncL then&lt;br /&gt;
			uncU = delimit(&amp;#039;+&amp;#039;, uncU, fmt) .. (upper.errend or &amp;#039;&amp;#039;)&lt;br /&gt;
			uncL = delimit(&amp;#039;−&amp;#039;, uncL, fmt) .. (lower.errend or &amp;#039;&amp;#039;)&lt;br /&gt;
			if angle then&lt;br /&gt;
				uncU = uncU .. angle&lt;br /&gt;
				uncL = uncL .. angle&lt;br /&gt;
			end&lt;br /&gt;
			text = (angle or &amp;#039;&amp;#039;) ..&lt;br /&gt;
				&amp;#039;&amp;lt;span style=&amp;quot;margin-left:0.3em;&amp;quot;&amp;gt;&amp;#039; ..&lt;br /&gt;
				sup_sub(uncU, uncL, options.align) ..&lt;br /&gt;
				&amp;#039;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
		else&lt;br /&gt;
			if upper.parens then&lt;br /&gt;
				text = &amp;#039;(&amp;#039; .. uncU .. &amp;#039;)&amp;#039;  -- old template did not delimit&lt;br /&gt;
			else&lt;br /&gt;
				text = (angle or &amp;#039;&amp;#039;) ..&lt;br /&gt;
					&amp;#039;&amp;lt;span style=&amp;quot;margin-left:0.3em;margin-right:0.15em;&amp;quot;&amp;gt;±&amp;lt;/span&amp;gt;&amp;#039; ..&lt;br /&gt;
					delimit(&amp;#039;&amp;#039;, uncU, fmt)&lt;br /&gt;
				need_parens = true&lt;br /&gt;
			end&lt;br /&gt;
			if uncertainty.errend then&lt;br /&gt;
				text = text .. uncertainty.errend&lt;br /&gt;
			end&lt;br /&gt;
			if angle then&lt;br /&gt;
				text = text .. angle&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		if angle then&lt;br /&gt;
			text = angle&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return text, need_parens&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function _main(values, unit_spec, options)&lt;br /&gt;
	if options.sandbox then&lt;br /&gt;
		data_module = data_module .. &amp;#039;/sandbox&amp;#039;&lt;br /&gt;
		convert_module = convert_module .. &amp;#039;/sandbox&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	local action = options.action&lt;br /&gt;
	if action then&lt;br /&gt;
		if action == &amp;#039;list&amp;#039; then&lt;br /&gt;
			-- Kludge: am using the align parameter (a=xxx) for type of list.&lt;br /&gt;
			return list_units(options.align)&lt;br /&gt;
		end&lt;br /&gt;
		return valerror(&amp;#039;invalid action &amp;quot;&amp;#039; .. action .. &amp;#039;&amp;quot;.&amp;#039;, options.nocat)&lt;br /&gt;
	end&lt;br /&gt;
	local number = values.number or (values.numbers and values.numbers[1]) or {}&lt;br /&gt;
	local e_10 = options.e or {}&lt;br /&gt;
	local novalue = (number.value == nil and e_10.clean == nil)&lt;br /&gt;
	local fmt = options.fmt&lt;br /&gt;
	local want_sort = true&lt;br /&gt;
	local sortable = options.sortable&lt;br /&gt;
	if sortable == &amp;#039;off&amp;#039; or (sortable == nil and novalue) then&lt;br /&gt;
		want_sort = false&lt;br /&gt;
	elseif sortable == &amp;#039;debug&amp;#039; then&lt;br /&gt;
		-- Same as sortable = &amp;#039;on&amp;#039; but the sort key is displayed.&lt;br /&gt;
	else&lt;br /&gt;
		sortable = &amp;#039;on&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	local sort_value = 1&lt;br /&gt;
	if want_sort then&lt;br /&gt;
		sort_value = number.value or 1&lt;br /&gt;
		if e_10.value and sort_value ~= 0 then&lt;br /&gt;
			-- The &amp;#039;if&amp;#039; avoids {{val|0|e=1234}} giving an invalid sort_value due to overflow.&lt;br /&gt;
			sort_value = sort_value * 10^e_10.value&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local unit_table = makeunit(sort_value, {&lt;br /&gt;
						u = unit_spec.u,&lt;br /&gt;
						want_link = unit_spec.want_link,&lt;br /&gt;
						per = unit_spec.per,&lt;br /&gt;
						want_per_link = unit_spec.want_per_link,&lt;br /&gt;
						nospace = novalue,&lt;br /&gt;
						want_longscale = unit_spec.want_longscale,&lt;br /&gt;
						sortable = sortable,&lt;br /&gt;
					})&lt;br /&gt;
	local sortkey&lt;br /&gt;
	if unit_table then&lt;br /&gt;
		if want_sort then&lt;br /&gt;
			sortkey = unit_table.sortkey&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		unit_table = { text = &amp;#039;&amp;#039; }&lt;br /&gt;
		if want_sort then&lt;br /&gt;
			sortkey = convert_lookup(&amp;#039;dummy&amp;#039;, sort_value, nil, nil, nil, { sortable = sortable }).sortspan&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local final_unit = unit_table.isangle and &amp;#039;&amp;#039; or unit_table.text&lt;br /&gt;
	local e_text, n_text, need_parens&lt;br /&gt;
	local uncertainty = values.uncertainty&lt;br /&gt;
	if uncertainty then&lt;br /&gt;
		if number.clean then&lt;br /&gt;
			n_text = delimit(number.sign, number.clean, fmt) .. (number.nend or &amp;#039;&amp;#039;)&lt;br /&gt;
			local text&lt;br /&gt;
			text, need_parens = uncertainty_text(uncertainty, unit_table, options)&lt;br /&gt;
			if text then&lt;br /&gt;
				n_text = n_text .. text&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			n_text = &amp;#039;&amp;#039;&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		if values.numbers.isrepeat then&lt;br /&gt;
			final_unit = &amp;#039;&amp;#039;&lt;br /&gt;
		end&lt;br /&gt;
		n_text = range_text(values.numbers, unit_table, options)&lt;br /&gt;
		need_parens = true&lt;br /&gt;
	end&lt;br /&gt;
	if e_10.clean then&lt;br /&gt;
		if need_parens then&lt;br /&gt;
			n_text = &amp;#039;(&amp;#039; .. n_text .. &amp;#039;)&amp;#039;&lt;br /&gt;
		end&lt;br /&gt;
		e_text = &amp;#039;10&amp;lt;sup&amp;gt;&amp;#039; .. delimit(e_10.sign, e_10.clean, fmt) .. &amp;#039;&amp;lt;/sup&amp;gt;&amp;#039;&lt;br /&gt;
		if number.clean then&lt;br /&gt;
			e_text = &amp;#039;&amp;lt;span style=&amp;quot;margin-left:0.25em;margin-right:0.15em;&amp;quot;&amp;gt;×&amp;lt;/span&amp;gt;&amp;#039; .. e_text&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		e_text = &amp;#039;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	local result =&lt;br /&gt;
		(sortkey or &amp;#039;&amp;#039;) ..&lt;br /&gt;
		(options.prefix or &amp;#039;&amp;#039;) ..&lt;br /&gt;
		n_text ..&lt;br /&gt;
		e_text ..&lt;br /&gt;
		final_unit ..&lt;br /&gt;
		(options.suffix or &amp;#039;&amp;#039;)&lt;br /&gt;
	if result ~= &amp;#039;&amp;#039; then&lt;br /&gt;
		result = &amp;#039;&amp;lt;span class=&amp;quot;nowrap&amp;quot;&amp;gt;&amp;#039; .. result .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	return result .. (options.warning or &amp;#039;&amp;#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function check_parameters(args, has_ranges, nocat)&lt;br /&gt;
	-- Return warning text for the first problem parameter found, or nothing if ok.&lt;br /&gt;
	local whitelist = {&lt;br /&gt;
		a = true,&lt;br /&gt;
		action = true,&lt;br /&gt;
		debug = true,&lt;br /&gt;
		e = true,&lt;br /&gt;
		[&amp;#039;end&amp;#039;] = true,&lt;br /&gt;
		errend = true,&lt;br /&gt;
		[&amp;#039;+errend&amp;#039;] = true,&lt;br /&gt;
		[&amp;#039;-errend&amp;#039;] = true,&lt;br /&gt;
		fmt = true,&lt;br /&gt;
		[&amp;#039;long scale&amp;#039;] = true,&lt;br /&gt;
		long_scale = true,&lt;br /&gt;
		longscale = true,&lt;br /&gt;
		nocategory = true,&lt;br /&gt;
		p = true,&lt;br /&gt;
		s = true,&lt;br /&gt;
		sortable = true,&lt;br /&gt;
		u = true,&lt;br /&gt;
		ul = true,&lt;br /&gt;
		up = true,&lt;br /&gt;
		upl = true,&lt;br /&gt;
	}&lt;br /&gt;
	for k, v in pairs(args) do&lt;br /&gt;
		if type(k) == &amp;#039;string&amp;#039; and not whitelist[k] then&lt;br /&gt;
			local warning = string.format(mtext[&amp;#039;mt-val-not-supported&amp;#039;], k, v)&lt;br /&gt;
			return valerror(warning, nocat, true)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if not has_ranges and args[4] then&lt;br /&gt;
		return valerror(mtext[&amp;#039;mt-ignore-parameter4&amp;#039;], nocat, true)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function main(frame)&lt;br /&gt;
	local getArgs = require(&amp;#039;Module:Arguments&amp;#039;).getArgs&lt;br /&gt;
	local args = getArgs(frame, {wrappers = { &amp;#039;Template:Val&amp;#039; }})&lt;br /&gt;
	local nocat = args.nocategory&lt;br /&gt;
	local numbers = {}  -- table of number tables, perhaps with range text&lt;br /&gt;
	local msg = get_args(numbers, args)&lt;br /&gt;
	if msg then&lt;br /&gt;
		return valerror(msg, nocat)&lt;br /&gt;
	end&lt;br /&gt;
	if args.u and args.ul then&lt;br /&gt;
		return valerror(mtext[&amp;#039;mt-both-u-ul&amp;#039;], nocat)&lt;br /&gt;
	end&lt;br /&gt;
	if args.up and args.upl then&lt;br /&gt;
		return valerror(mtext[&amp;#039;mt-both-up-upl&amp;#039;], nocat)&lt;br /&gt;
	end&lt;br /&gt;
	local values&lt;br /&gt;
	if numbers.has_ranges then&lt;br /&gt;
		-- Multiple values with range separators but no uncertainty.&lt;br /&gt;
		numbers.nend = args[&amp;#039;end&amp;#039;]&lt;br /&gt;
		values = {&lt;br /&gt;
			numbers = numbers,&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		-- A single value with optional uncertainty.&lt;br /&gt;
		local function setfield(i, dst, src)&lt;br /&gt;
			local v = args[src]&lt;br /&gt;
			if v then&lt;br /&gt;
				if numbers[i] then&lt;br /&gt;
					numbers[i][dst] = v&lt;br /&gt;
				else&lt;br /&gt;
					numbers[i] = { [dst] = v }&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		setfield(1, &amp;#039;nend&amp;#039;, &amp;#039;end&amp;#039;)&lt;br /&gt;
		setfield(2, &amp;#039;errend&amp;#039;, &amp;#039;+errend&amp;#039;)&lt;br /&gt;
		setfield(3, &amp;#039;errend&amp;#039;, &amp;#039;-errend&amp;#039;)&lt;br /&gt;
		values = {&lt;br /&gt;
			number = numbers[1],&lt;br /&gt;
			uncertainty = {&lt;br /&gt;
				upper = numbers[2],&lt;br /&gt;
				lower = numbers[3],&lt;br /&gt;
				errend = args.errend,&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	end&lt;br /&gt;
	local unit_spec = {&lt;br /&gt;
			u = args.ul or args.u,&lt;br /&gt;
			want_link = args.ul ~= nil,&lt;br /&gt;
			per = args.upl or args.up,&lt;br /&gt;
			want_per_link = args.upl ~= nil,&lt;br /&gt;
			want_longscale = (args.longscale or args.long_scale or args[&amp;#039;long scale&amp;#039;]) == &amp;#039;on&amp;#039;,&lt;br /&gt;
		}&lt;br /&gt;
	local options = {&lt;br /&gt;
			action = args.action,&lt;br /&gt;
			align = args.a,&lt;br /&gt;
			e = numbers.e,&lt;br /&gt;
			fmt = args.fmt,&lt;br /&gt;
			nocat = nocat,&lt;br /&gt;
			prefix = args.p,&lt;br /&gt;
			sandbox = string.find(frame:getTitle(), &amp;#039;sandbox&amp;#039;, 1, true) ~= nil,&lt;br /&gt;
			sortable = args.sortable or (args.debug == &amp;#039;yes&amp;#039; and &amp;#039;debug&amp;#039; or nil),&lt;br /&gt;
			suffix = args.s,&lt;br /&gt;
			warning = check_parameters(args, numbers.has_ranges, nocat),&lt;br /&gt;
		}&lt;br /&gt;
	return _main(values, unit_spec, options)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return { main = main, _main = _main }&lt;/div&gt;</summary>
		<author><name>&gt;Johnuniq</name></author>
	</entry>
</feed>