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