<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://maruneko.autumns.page/mediawiki/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://maruneko.autumns.page/mediawiki/index.php?action=history&amp;feed=atom&amp;title=Module%3AVal"/>
	<link rel="alternate" type="text/html" href="https://maruneko.autumns.page/mediawiki/index.php?title=Module:Val&amp;action=history"/>
	<updated>2026-04-04T17:22:49Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.41.0</generator>
	<entry>
		<id>https://maruneko.autumns.page/mediawiki/index.php?title=Module:Val&amp;diff=4309&amp;oldid=prev</id>
		<title>Rox: 1 revision imported</title>
		<link rel="alternate" type="text/html" href="https://maruneko.autumns.page/mediawiki/index.php?title=Module:Val&amp;diff=4309&amp;oldid=prev"/>
		<updated>2023-07-05T21:24:20Z</updated>

		<summary type="html">&lt;p&gt;1 revision imported&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 16:24, 5 July 2023&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;4&quot; class=&quot;diff-notice&quot; lang=&quot;en&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(No difference)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;!-- diff cache key jth_wiki:diff:1.41:old-4308:rev-4309 --&gt;
&lt;/table&gt;</summary>
		<author><name>Rox</name></author>
	</entry>
	<entry>
		<id>https://maruneko.autumns.page/mediawiki/index.php?title=Module:Val&amp;diff=4308&amp;oldid=prev</id>
		<title>Wikipedia&gt;Johnuniq: use i18n from Module:Val/sandbox added by User:Moroboshi</title>
		<link rel="alternate" type="text/html" href="https://maruneko.autumns.page/mediawiki/index.php?title=Module:Val&amp;diff=4308&amp;oldid=prev"/>
		<updated>2022-06-30T03:19:56Z</updated>

		<summary type="html">&lt;p&gt;use i18n from &lt;a href=&quot;/mediawiki/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;/mediawiki/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;a href=&quot;https://maruneko.autumns.page/mediawiki/index.php?title=Module:Val&amp;amp;diff=4308&amp;amp;oldid=748&quot;&gt;Show changes&lt;/a&gt;</summary>
		<author><name>Wikipedia&gt;Johnuniq</name></author>
	</entry>
	<entry>
		<id>https://maruneko.autumns.page/mediawiki/index.php?title=Module:Val&amp;diff=748&amp;oldid=prev</id>
		<title>imported&gt;Rox: 1 revision imported</title>
		<link rel="alternate" type="text/html" href="https://maruneko.autumns.page/mediawiki/index.php?title=Module:Val&amp;diff=748&amp;oldid=prev"/>
		<updated>2021-03-11T22:42:11Z</updated>

		<summary type="html">&lt;p&gt;1 revision imported&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 17:42, 11 March 2021&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;4&quot; class=&quot;diff-notice&quot; lang=&quot;en&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(No difference)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;!-- diff cache key jth_wiki:diff:1.41:old-747:rev-748 --&gt;
&lt;/table&gt;</summary>
		<author><name>imported&gt;Rox</name></author>
	</entry>
	<entry>
		<id>https://maruneko.autumns.page/mediawiki/index.php?title=Module:Val&amp;diff=747&amp;oldid=prev</id>
		<title>Wikipedia&gt;Johnuniq: update from sandbox; val/sandbox will call convert/sandbox</title>
		<link rel="alternate" type="text/html" href="https://maruneko.autumns.page/mediawiki/index.php?title=Module:Val&amp;diff=747&amp;oldid=prev"/>
		<updated>2019-05-03T03:16:41Z</updated>

		<summary type="html">&lt;p&gt;update from sandbox; val/sandbox will call convert/sandbox&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 data_module = 'Module:Val/units'&lt;br /&gt;
local convert_module = 'Module:Convert'&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;lt;span id=&amp;quot;FormattingError&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;'&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 = ''&lt;br /&gt;
	else&lt;br /&gt;
		category = '[[Category:Pages with incorrect formatting templates use]]'&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;lt;sup class=&amp;quot;noprint Inline-Template&amp;quot; style=&amp;quot;white-space:nowrap;&amp;quot;&amp;gt;' ..&lt;br /&gt;
			'[[Template:Val|&amp;lt;span title=&amp;quot;' ..&lt;br /&gt;
			msg:gsub('&amp;quot;', '&amp;amp;quot;') ..&lt;br /&gt;
			'&amp;quot;&amp;gt;warning&amp;lt;/span&amp;gt;]]&amp;lt;/sup&amp;gt;'&lt;br /&gt;
	else&lt;br /&gt;
		body = '&amp;lt;strong class=&amp;quot;error&amp;quot;&amp;gt;' ..&lt;br /&gt;
			'Error in &amp;amp;#123;&amp;amp;#123;[[Template:val|val]]&amp;amp;#125;&amp;amp;#125;: ' ..&lt;br /&gt;
			msg ..&lt;br /&gt;
			'&amp;lt;/strong&amp;gt;'&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;amp;nbsp;' 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 'e' argument.&lt;br /&gt;
	-- Input commas are removed so 1,234 is the same as 1234.&lt;br /&gt;
	local which = index&lt;br /&gt;
	local function fail(msg)&lt;br /&gt;
		local description&lt;br /&gt;
		if which == 'e' then&lt;br /&gt;
			description = 'exponent parameter (&amp;lt;b&amp;gt;e&amp;lt;/b&amp;gt;)'&lt;br /&gt;
		else&lt;br /&gt;
			description = 'parameter ' .. which&lt;br /&gt;
		end&lt;br /&gt;
		return description .. ' ' .. (msg or 'is not a valid number') .. '.'&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) == 'number' 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('cannot use a range if the first parameter includes &amp;quot;e&amp;quot;')&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('needs a range in parameter 2')&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('does not accept a range')&lt;br /&gt;
	end&lt;br /&gt;
	if numbers.has_ranges and type(index) == 'number' and (index % 2 == 0) then&lt;br /&gt;
		return fail('should be a range')&lt;br /&gt;
	end&lt;br /&gt;
	if index == 'e' 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('cannot be used if the first parameter includes &amp;quot;e&amp;quot;')&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 ~= '' then&lt;br /&gt;
		arg = arg:gsub(',', '')&lt;br /&gt;
		if arg:sub(1, 1) == '(' and arg:sub(-1) == ')' 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('^(.+)[Ee](.+)$')&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('cannot use e notation')&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		local isnegative, propersign, prefix&lt;br /&gt;
		local minus = '−'&lt;br /&gt;
		prefix, arg = arg:match('^(.-)([%d.]+)$')&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) == '.' then&lt;br /&gt;
			arg = '0' .. arg&lt;br /&gt;
		end&lt;br /&gt;
		if prefix == '' then&lt;br /&gt;
			-- Ignore.&lt;br /&gt;
		elseif prefix == '±' then&lt;br /&gt;
			-- Display for first number, ignore for others.&lt;br /&gt;
			if index == 1 then&lt;br /&gt;
				propersign = '±'&lt;br /&gt;
			end&lt;br /&gt;
		elseif prefix == '+' then&lt;br /&gt;
			propersign = '+'&lt;br /&gt;
		elseif prefix == '-' 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 ''&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 = 'e'&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 == 'e' then&lt;br /&gt;
			break&lt;br /&gt;
		end&lt;br /&gt;
		if index &amp;gt; 19 then&lt;br /&gt;
			return 'too many parameters'&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if numbers.has_ranges and (#numbers % 2 == 0) then&lt;br /&gt;
		return 'need a number after the last parameter because it is a range.'&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 'pi'.&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('pi', math.pi)&lt;br /&gt;
	for _, op in ipairs({ '/', '^' }) do&lt;br /&gt;
		local a, b = n:match('^(.-)' .. op .. '(.*)$')&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 == '/' then&lt;br /&gt;
					return a / b&lt;br /&gt;
				elseif op == '^' 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('Unit &amp;quot;' .. ucode .. '&amp;quot; has invalid scale &amp;quot;' .. text .. '&amp;quot;')&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('\n' .. ucode .. '  ', 1, true)&lt;br /&gt;
	if pos then&lt;br /&gt;
		local endline = definitions:find('%s*\n', 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('%s%s+', '\t')&lt;br /&gt;
			for item in (text .. '\t'):gmatch('(%S.-)\t') do&lt;br /&gt;
				if item == 'ALIAS' then&lt;br /&gt;
					result.alias = true&lt;br /&gt;
				elseif item == 'ANGLE' then&lt;br /&gt;
					result.isangle = true&lt;br /&gt;
					result.nospace = true&lt;br /&gt;
				elseif item == 'NOSPACE' then&lt;br /&gt;
					result.nospace = true&lt;br /&gt;
				elseif item == 'SI' 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('^%[%[([^|]+)|(.+)%]%]$')&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 == 'mc' .. s or ucode == 'mu' .. s then&lt;br /&gt;
					result.ucode = 'µ' .. 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 'year' 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 = '[[' .. result.link .. '|' .. result.symbol .. ']]'&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 ''&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('[*./]') and '(' .. text .. ')' 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 '') ..&lt;br /&gt;
				'/' .. 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;amp;nbsp;' .. 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'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 == '' 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] = ''&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 = 'y',&lt;br /&gt;
		z = 'z',&lt;br /&gt;
		a = 'a',&lt;br /&gt;
		f = 'f',&lt;br /&gt;
		p = 'p',&lt;br /&gt;
		n = 'n',&lt;br /&gt;
		u = 'µ',&lt;br /&gt;
		['µ'] = 'µ',&lt;br /&gt;
		m = 'm',&lt;br /&gt;
		c = 'c',&lt;br /&gt;
		d = 'd',&lt;br /&gt;
		da = 'da',&lt;br /&gt;
		h = 'h',&lt;br /&gt;
		k = 'k',&lt;br /&gt;
		M = 'M',&lt;br /&gt;
		G = 'G',&lt;br /&gt;
		T = 'T',&lt;br /&gt;
		P = 'P',&lt;br /&gt;
		E = 'E',&lt;br /&gt;
		Z = 'Z',&lt;br /&gt;
		Y = 'Y',&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) == 'string' and unit.symbol ~= '')&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'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 == 'convert' then&lt;br /&gt;
				unit.show = not lookup(unit.alias and unit.symbol or ucode).unknown&lt;br /&gt;
				unit.show_text = 'CONVERT'&lt;br /&gt;
			elseif mode == 'unknown' then&lt;br /&gt;
				unit.show = lookup(unit.alias and unit.symbol or ucode).unknown&lt;br /&gt;
				unit.show_text = 'UNKNOWN'&lt;br /&gt;
			elseif not unit.alias then&lt;br /&gt;
				-- Show convert's scale in square brackets ('[1]' for an unknown unit).&lt;br /&gt;
				-- Don't show scale for an alias because it'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='on'}).scaled_value&lt;br /&gt;
				if type(scale) == 'number' then&lt;br /&gt;
					scale = string.format('%.5g', scale):gsub('e%+?(%-?)0*(%d+)', 'e%1%2')&lt;br /&gt;
				else&lt;br /&gt;
					scale = '?'&lt;br /&gt;
				end&lt;br /&gt;
				unit.show = true&lt;br /&gt;
				unit.show_text = '[' .. scale .. ']'&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	for line in definitions:gmatch('([^\n]*)\n') do&lt;br /&gt;
		local pos, _ = line:find('  ', 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, '\n' .. line .. '\n')&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 = '[[' .. unit.link .. '|' .. unit.display .. ']]'&lt;br /&gt;
				end&lt;br /&gt;
				if unit.isangle then&lt;br /&gt;
					unit.nospace = nil  -- don't show redundant flag&lt;br /&gt;
				end&lt;br /&gt;
				for _, f in ipairs({&lt;br /&gt;
						{ 'alias', 'ALIAS' },&lt;br /&gt;
						{ 'isangle', 'ANGLE' },&lt;br /&gt;
						{ 'nospace', 'NOSPACE' },&lt;br /&gt;
						{ 'si', 'SI' },&lt;br /&gt;
						{ 'scale_text', unit.scale_text },&lt;br /&gt;
						{ 'show', 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('^%u+$') then&lt;br /&gt;
							t = '&amp;lt;small&amp;gt;' .. t .. '&amp;lt;/small&amp;gt;'&lt;br /&gt;
						end&lt;br /&gt;
						if flags then&lt;br /&gt;
							flags = flags .. ' ' .. 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 .. ' • ' .. flags&lt;br /&gt;
				end&lt;br /&gt;
				add(ucode .. ' = ' .. text .. '&amp;lt;br /&amp;gt;')&lt;br /&gt;
			else&lt;br /&gt;
				add(line .. ' ◆ &amp;lt;b&amp;gt;invalid definition&amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt;')&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, '\n')&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local delimit_groups = require('Module:Gapnum').groups&lt;br /&gt;
local function delimit(sign, numstr, fmt)&lt;br /&gt;
	-- Return sign and numstr (unsigned digits or '.' only) after formatting.&lt;br /&gt;
	-- Four-digit integers are not formatted with gaps.&lt;br /&gt;
	fmt = (fmt or ''):lower()&lt;br /&gt;
	if fmt == 'none' or (fmt == '' and #numstr == 4 and numstr:match('^%d+$')) 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 == 'commas' then&lt;br /&gt;
		result = sign .. table.concat(ipart, ',')&lt;br /&gt;
		if dpart then&lt;br /&gt;
			result = result .. '.' .. 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;lt;span style=&amp;quot;margin-left:.25em;&amp;quot;&amp;gt;' .. v .. '&amp;lt;/span&amp;gt;')&lt;br /&gt;
		end&lt;br /&gt;
		if dpart then&lt;br /&gt;
			table.insert(groups, '.' .. (table.remove(dpart, 1) or ''))&lt;br /&gt;
			for _, v in ipairs(dpart) do&lt;br /&gt;
				table.insert(groups, '&amp;lt;span style=&amp;quot;margin-left:.25em;&amp;quot;&amp;gt;' .. v .. '&amp;lt;/span&amp;gt;')&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 == 'l' or align == 'left' then&lt;br /&gt;
		align = 'left'&lt;br /&gt;
	elseif align == 'c' or align == 'center' then&lt;br /&gt;
		align = 'center'&lt;br /&gt;
	else&lt;br /&gt;
		align = 'right'&lt;br /&gt;
	end&lt;br /&gt;
	return '&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:' ..&lt;br /&gt;
		align .. ';&amp;quot;&amp;gt;' .. sup .. '&amp;lt;br /&amp;gt;' .. sub .. '&amp;lt;/span&amp;gt;'&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 ''&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 = ''&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('+', uncU, fmt) .. (upper.errend or '')&lt;br /&gt;
			uncL = delimit('−', uncL, fmt) .. (lower.errend or '')&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 '') ..&lt;br /&gt;
				'&amp;lt;span style=&amp;quot;margin-left:0.3em;&amp;quot;&amp;gt;' ..&lt;br /&gt;
				sup_sub(uncU, uncL, options.align) ..&lt;br /&gt;
				'&amp;lt;/span&amp;gt;'&lt;br /&gt;
		else&lt;br /&gt;
			if upper.parens then&lt;br /&gt;
				text = '(' .. uncU .. ')'  -- old template did not delimit&lt;br /&gt;
			else&lt;br /&gt;
				text = (angle or '') ..&lt;br /&gt;
					'&amp;lt;span style=&amp;quot;margin-left:0.3em;margin-right:0.15em;&amp;quot;&amp;gt;±&amp;lt;/span&amp;gt;' ..&lt;br /&gt;
					delimit('', 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 .. '/sandbox'&lt;br /&gt;
		convert_module = convert_module .. '/sandbox'&lt;br /&gt;
	end&lt;br /&gt;
	local action = options.action&lt;br /&gt;
	if action then&lt;br /&gt;
		if action == 'list' 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('invalid action &amp;quot;' .. action .. '&amp;quot;.', 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 == 'off' or (sortable == nil and novalue) then&lt;br /&gt;
		want_sort = false&lt;br /&gt;
	elseif sortable == 'debug' then&lt;br /&gt;
		-- Same as sortable = 'on' but the sort key is displayed.&lt;br /&gt;
	else&lt;br /&gt;
		sortable = 'on'&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 'if' 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 = '' }&lt;br /&gt;
		if want_sort then&lt;br /&gt;
			sortkey = convert_lookup('dummy', 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 '' 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 '')&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 = ''&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		if values.numbers.isrepeat then&lt;br /&gt;
			final_unit = ''&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 = '(' .. n_text .. ')'&lt;br /&gt;
		end&lt;br /&gt;
		e_text = '10&amp;lt;sup&amp;gt;' .. delimit(e_10.sign, e_10.clean, fmt) .. '&amp;lt;/sup&amp;gt;'&lt;br /&gt;
		if number.clean then&lt;br /&gt;
			e_text = '&amp;lt;span style=&amp;quot;margin-left:0.25em;margin-right:0.15em;&amp;quot;&amp;gt;×&amp;lt;/span&amp;gt;' .. e_text&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		e_text = ''&lt;br /&gt;
	end&lt;br /&gt;
	local result =&lt;br /&gt;
		(sortkey or '') ..&lt;br /&gt;
		(options.prefix or '') ..&lt;br /&gt;
		n_text ..&lt;br /&gt;
		e_text ..&lt;br /&gt;
		final_unit ..&lt;br /&gt;
		(options.suffix or '')&lt;br /&gt;
	if result ~= '' then&lt;br /&gt;
		result = '&amp;lt;span class=&amp;quot;nowrap&amp;quot;&amp;gt;' .. result .. '&amp;lt;/span&amp;gt;'&lt;br /&gt;
	end&lt;br /&gt;
	return result .. (options.warning or '')&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;
		['end'] = true,&lt;br /&gt;
		errend = true,&lt;br /&gt;
		['+errend'] = true,&lt;br /&gt;
		['-errend'] = true,&lt;br /&gt;
		fmt = true,&lt;br /&gt;
		['long scale'] = 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) == 'string' and not whitelist[k] then&lt;br /&gt;
			local warning = 'Val parameter &amp;quot;' .. k .. '=' .. v .. '&amp;quot; is not supported'&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('Val parameter 4 ignored', 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('Module:Arguments').getArgs&lt;br /&gt;
	local args = getArgs(frame, {wrappers = { 'Template:Val' }})&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('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.', nocat)&lt;br /&gt;
	end&lt;br /&gt;
	if args.up and args.upl then&lt;br /&gt;
		return valerror('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.', 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['end']&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, 'nend', 'end')&lt;br /&gt;
		setfield(2, 'errend', '+errend')&lt;br /&gt;
		setfield(3, 'errend', '-errend')&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['long scale']) == 'on',&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(), 'sandbox', 1, true) ~= nil,&lt;br /&gt;
			sortable = args.sortable or (args.debug == 'yes' and 'debug' 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>Wikipedia&gt;Johnuniq</name></author>
	</entry>
</feed>