<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ko">
	<id>https://devhrxoobm.itwiki.kr/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Maintenance+script</id>
	<title>IT 위키 - 사용자 기여 [ko]</title>
	<link rel="self" type="application/atom+xml" href="https://devhrxoobm.itwiki.kr/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Maintenance+script"/>
	<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/w/%ED%8A%B9%EC%88%98:%EA%B8%B0%EC%97%AC/Maintenance_script"/>
	<updated>2026-09-17T11:08:58Z</updated>
	<subtitle>사용자 기여</subtitle>
	<generator>MediaWiki 1.45.1</generator>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EB%AA%A8%EB%93%88:ConvertNumeric&amp;diff=62832</id>
		<title>모듈:ConvertNumeric</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EB%AA%A8%EB%93%88:ConvertNumeric&amp;diff=62832"/>
		<updated>2026-07-05T15:19:48Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: 한국어 위키백과 https://ko.wikipedia.org/wiki/모듈:ConvertNumeric에서 모듈 가져옴&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;-- Module for converting between different representations of numbers. See talk page for user documentation.&lt;br /&gt;
-- For unit tests see: [[Module:ConvertNumeric/testcases]]&lt;br /&gt;
-- When editing, preview with: [[Module_talk:ConvertNumeric/testcases]]&lt;br /&gt;
-- First, edit [[Module:ConvertNumeric/sandbox]], then preview with [[Module_talk:ConvertNumeric/sandbox/testcases]]&lt;br /&gt;
require(&#039;strict&#039;)&lt;br /&gt;
&lt;br /&gt;
local ones_position = {&lt;br /&gt;
	[0] = &#039;zero&#039;,&lt;br /&gt;
	[1] = &#039;one&#039;,&lt;br /&gt;
	[2] = &#039;two&#039;,&lt;br /&gt;
	[3] = &#039;three&#039;,&lt;br /&gt;
	[4] = &#039;four&#039;,&lt;br /&gt;
	[5] = &#039;five&#039;,&lt;br /&gt;
	[6] = &#039;six&#039;,&lt;br /&gt;
	[7] = &#039;seven&#039;,&lt;br /&gt;
	[8] = &#039;eight&#039;,&lt;br /&gt;
	[9] = &#039;nine&#039;,&lt;br /&gt;
	[10] = &#039;ten&#039;,&lt;br /&gt;
	[11] = &#039;eleven&#039;,&lt;br /&gt;
	[12] = &#039;twelve&#039;,&lt;br /&gt;
	[13] = &#039;thirteen&#039;,&lt;br /&gt;
	[14] = &#039;fourteen&#039;,&lt;br /&gt;
	[15] = &#039;fifteen&#039;,&lt;br /&gt;
	[16] = &#039;sixteen&#039;,&lt;br /&gt;
	[17] = &#039;seventeen&#039;,&lt;br /&gt;
	[18] = &#039;eighteen&#039;,&lt;br /&gt;
	[19] = &#039;nineteen&#039;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local ones_position_ord = {&lt;br /&gt;
	[0] = &#039;zeroth&#039;,&lt;br /&gt;
	[1] = &#039;first&#039;,&lt;br /&gt;
	[2] = &#039;second&#039;,&lt;br /&gt;
	[3] = &#039;third&#039;,&lt;br /&gt;
	[4] = &#039;fourth&#039;,&lt;br /&gt;
	[5] = &#039;fifth&#039;,&lt;br /&gt;
	[6] = &#039;sixth&#039;,&lt;br /&gt;
	[7] = &#039;seventh&#039;,&lt;br /&gt;
	[8] = &#039;eighth&#039;,&lt;br /&gt;
	[9] = &#039;ninth&#039;,&lt;br /&gt;
	[10] = &#039;tenth&#039;,&lt;br /&gt;
	[11] = &#039;eleventh&#039;,&lt;br /&gt;
	[12] = &#039;twelfth&#039;,&lt;br /&gt;
	[13] = &#039;thirteenth&#039;,&lt;br /&gt;
	[14] = &#039;fourteenth&#039;,&lt;br /&gt;
	[15] = &#039;fifteenth&#039;,&lt;br /&gt;
	[16] = &#039;sixteenth&#039;,&lt;br /&gt;
	[17] = &#039;seventeenth&#039;,&lt;br /&gt;
	[18] = &#039;eighteenth&#039;,&lt;br /&gt;
	[19] = &#039;nineteenth&#039;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local ones_position_plural = {&lt;br /&gt;
	[0] = &#039;zeros&#039;,&lt;br /&gt;
	[1] = &#039;ones&#039;,&lt;br /&gt;
	[2] = &#039;twos&#039;,&lt;br /&gt;
	[3] = &#039;threes&#039;,&lt;br /&gt;
	[4] = &#039;fours&#039;,&lt;br /&gt;
	[5] = &#039;fives&#039;,&lt;br /&gt;
	[6] = &#039;sixes&#039;,&lt;br /&gt;
	[7] = &#039;sevens&#039;,&lt;br /&gt;
	[8] = &#039;eights&#039;,&lt;br /&gt;
	[9] = &#039;nines&#039;,&lt;br /&gt;
	[10] = &#039;tens&#039;,&lt;br /&gt;
	[11] = &#039;elevens&#039;,&lt;br /&gt;
	[12] = &#039;twelves&#039;,&lt;br /&gt;
	[13] = &#039;thirteens&#039;,&lt;br /&gt;
	[14] = &#039;fourteens&#039;,&lt;br /&gt;
	[15] = &#039;fifteens&#039;,&lt;br /&gt;
	[16] = &#039;sixteens&#039;,&lt;br /&gt;
	[17] = &#039;seventeens&#039;,&lt;br /&gt;
	[18] = &#039;eighteens&#039;,&lt;br /&gt;
	[19] = &#039;nineteens&#039;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local tens_position = {&lt;br /&gt;
	[2] = &#039;twenty&#039;,&lt;br /&gt;
	[3] = &#039;thirty&#039;,&lt;br /&gt;
	[4] = &#039;forty&#039;,&lt;br /&gt;
	[5] = &#039;fifty&#039;,&lt;br /&gt;
	[6] = &#039;sixty&#039;,&lt;br /&gt;
	[7] = &#039;seventy&#039;,&lt;br /&gt;
	[8] = &#039;eighty&#039;,&lt;br /&gt;
	[9] = &#039;ninety&#039;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local tens_position_ord = {&lt;br /&gt;
	[2] = &#039;twentieth&#039;,&lt;br /&gt;
	[3] = &#039;thirtieth&#039;,&lt;br /&gt;
	[4] = &#039;fortieth&#039;,&lt;br /&gt;
	[5] = &#039;fiftieth&#039;,&lt;br /&gt;
	[6] = &#039;sixtieth&#039;,&lt;br /&gt;
	[7] = &#039;seventieth&#039;,&lt;br /&gt;
	[8] = &#039;eightieth&#039;,&lt;br /&gt;
	[9] = &#039;ninetieth&#039;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local tens_position_plural = {&lt;br /&gt;
	[2] = &#039;twenties&#039;,&lt;br /&gt;
	[3] = &#039;thirties&#039;,&lt;br /&gt;
	[4] = &#039;forties&#039;,&lt;br /&gt;
	[5] = &#039;fifties&#039;,&lt;br /&gt;
	[6] = &#039;sixties&#039;,&lt;br /&gt;
	[7] = &#039;seventies&#039;,&lt;br /&gt;
	[8] = &#039;eighties&#039;,&lt;br /&gt;
	[9] = &#039;nineties&#039;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local groups = {&lt;br /&gt;
	[1] = &#039;thousand&#039;,&lt;br /&gt;
	[2] = &#039;million&#039;,&lt;br /&gt;
	[3] = &#039;billion&#039;,&lt;br /&gt;
	[4] = &#039;trillion&#039;,&lt;br /&gt;
	[5] = &#039;quadrillion&#039;,&lt;br /&gt;
	[6] = &#039;quintillion&#039;,&lt;br /&gt;
	[7] = &#039;sextillion&#039;,&lt;br /&gt;
	[8] = &#039;septillion&#039;,&lt;br /&gt;
	[9] = &#039;octillion&#039;,&lt;br /&gt;
	[10] = &#039;nonillion&#039;,&lt;br /&gt;
	[11] = &#039;decillion&#039;,&lt;br /&gt;
	[12] = &#039;undecillion&#039;,&lt;br /&gt;
	[13] = &#039;duodecillion&#039;,&lt;br /&gt;
	[14] = &#039;tredecillion&#039;,&lt;br /&gt;
	[15] = &#039;quattuordecillion&#039;,&lt;br /&gt;
	[16] = &#039;quindecillion&#039;,&lt;br /&gt;
	[17] = &#039;sexdecillion&#039;,&lt;br /&gt;
	[18] = &#039;septendecillion&#039;,&lt;br /&gt;
	[19] = &#039;octodecillion&#039;,&lt;br /&gt;
	[20] = &#039;novemdecillion&#039;,&lt;br /&gt;
	[21] = &#039;vigintillion&#039;,&lt;br /&gt;
	[22] = &#039;unvigintillion&#039;,&lt;br /&gt;
	[23] = &#039;duovigintillion&#039;,&lt;br /&gt;
	[24] = &#039;tresvigintillion&#039;,&lt;br /&gt;
	[25] = &#039;quattuorvigintillion&#039;,&lt;br /&gt;
	[26] = &#039;quinquavigintillion&#039;,&lt;br /&gt;
	[27] = &#039;sesvigintillion&#039;,&lt;br /&gt;
	[28] = &#039;septemvigintillion&#039;,&lt;br /&gt;
	[29] = &#039;octovigintillion&#039;,&lt;br /&gt;
	[30] = &#039;novemvigintillion&#039;,&lt;br /&gt;
	[31] = &#039;trigintillion&#039;,&lt;br /&gt;
	[32] = &#039;untrigintillion&#039;,&lt;br /&gt;
	[33] = &#039;duotrigintillion&#039;,&lt;br /&gt;
	[34] = &#039;trestrigintillion&#039;,&lt;br /&gt;
	[35] = &#039;quattuortrigintillion&#039;,&lt;br /&gt;
	[36] = &#039;quinquatrigintillion&#039;,&lt;br /&gt;
	[37] = &#039;sestrigintillion&#039;,&lt;br /&gt;
	[38] = &#039;septentrigintillion&#039;,&lt;br /&gt;
	[39] = &#039;octotrigintillion&#039;,&lt;br /&gt;
	[40] = &#039;noventrigintillion&#039;,&lt;br /&gt;
	[41] = &#039;quadragintillion&#039;,&lt;br /&gt;
	[51] = &#039;quinquagintillion&#039;,&lt;br /&gt;
	[61] = &#039;sexagintillion&#039;,&lt;br /&gt;
	[71] = &#039;septuagintillion&#039;,&lt;br /&gt;
	[81] = &#039;octogintillion&#039;,&lt;br /&gt;
	[91] = &#039;nonagintillion&#039;,&lt;br /&gt;
	[101] = &#039;centillion&#039;,&lt;br /&gt;
	[102] = &#039;uncentillion&#039;,&lt;br /&gt;
	[103] = &#039;duocentillion&#039;,&lt;br /&gt;
	[104] = &#039;trescentillion&#039;,&lt;br /&gt;
	[111] = &#039;decicentillion&#039;,&lt;br /&gt;
	[112] = &#039;undecicentillion&#039;,&lt;br /&gt;
	[121] = &#039;viginticentillion&#039;,&lt;br /&gt;
	[122] = &#039;unviginticentillion&#039;,&lt;br /&gt;
	[131] = &#039;trigintacentillion&#039;,&lt;br /&gt;
	[141] = &#039;quadragintacentillion&#039;,&lt;br /&gt;
	[151] = &#039;quinquagintacentillion&#039;,&lt;br /&gt;
	[161] = &#039;sexagintacentillion&#039;,&lt;br /&gt;
	[171] = &#039;septuagintacentillion&#039;,&lt;br /&gt;
	[181] = &#039;octogintacentillion&#039;,&lt;br /&gt;
	[191] = &#039;nonagintacentillion&#039;,&lt;br /&gt;
	[201] = &#039;ducentillion&#039;,&lt;br /&gt;
	[301] = &#039;trecentillion&#039;,&lt;br /&gt;
	[401] = &#039;quadringentillion&#039;,&lt;br /&gt;
	[501] = &#039;quingentillion&#039;,&lt;br /&gt;
	[601] = &#039;sescentillion&#039;,&lt;br /&gt;
	[701] = &#039;septingentillion&#039;,&lt;br /&gt;
	[801] = &#039;octingentillion&#039;,&lt;br /&gt;
	[901] = &#039;nongentillion&#039;,&lt;br /&gt;
	[1001] = &#039;millinillion&#039;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local roman_numerals = {&lt;br /&gt;
	I = 1,&lt;br /&gt;
	V = 5,&lt;br /&gt;
	X = 10,&lt;br /&gt;
	L = 50,&lt;br /&gt;
	C = 100,&lt;br /&gt;
	D = 500,&lt;br /&gt;
	M = 1000&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local engord_tens_end  = {&lt;br /&gt;
	[&#039;twentieth&#039;]	= 20,&lt;br /&gt;
	[&#039;thirtieth&#039;]	= 30,&lt;br /&gt;
	[&#039;fortieth&#039;]	= 40,&lt;br /&gt;
	[&#039;fiftieth&#039;]	= 50,&lt;br /&gt;
	[&#039;sixtieth&#039;]	= 60,&lt;br /&gt;
	[&#039;seventieth&#039;]	= 70,&lt;br /&gt;
	[&#039;eightieth&#039;]	= 80,&lt;br /&gt;
	[&#039;ninetieth&#039;]	= 90,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local eng_tens_cont = {&lt;br /&gt;
	[&#039;twenty&#039;]	= 20,&lt;br /&gt;
	[&#039;thirty&#039;]	= 30,&lt;br /&gt;
	[&#039;forty&#039;]	= 40,&lt;br /&gt;
	[&#039;fifty&#039;]	= 50,&lt;br /&gt;
	[&#039;sixty&#039;]	= 60,&lt;br /&gt;
	[&#039;seventy&#039;]	= 70,&lt;br /&gt;
	[&#039;eighty&#039;]	= 80,&lt;br /&gt;
	[&#039;ninety&#039;]	= 90,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
-- Converts a given valid roman numeral (and some invalid roman numerals) to a number. Returns { -1, errorstring } on error.&lt;br /&gt;
local function roman_to_numeral(roman)&lt;br /&gt;
	if type(roman) ~= &amp;quot;string&amp;quot; then return -1, &amp;quot;roman numeral not a string&amp;quot; end&lt;br /&gt;
	local rev = roman:reverse()&lt;br /&gt;
	local raising = true&lt;br /&gt;
	local last = 0&lt;br /&gt;
	local result = 0&lt;br /&gt;
	for i = 1, #rev do&lt;br /&gt;
		local c = rev:sub(i, i)&lt;br /&gt;
		local next = roman_numerals[c]&lt;br /&gt;
		if next == nil then return -1, &amp;quot;roman numeral contains illegal character &amp;quot; .. c end&lt;br /&gt;
		if next &amp;gt; last then&lt;br /&gt;
			result = result + next&lt;br /&gt;
			raising = true&lt;br /&gt;
		elseif next &amp;lt; last then&lt;br /&gt;
			result = result - next&lt;br /&gt;
			raising = false&lt;br /&gt;
		elseif raising then&lt;br /&gt;
			result = result + next&lt;br /&gt;
		else&lt;br /&gt;
			result = result - next&lt;br /&gt;
		end&lt;br /&gt;
		last = next&lt;br /&gt;
	end&lt;br /&gt;
	return result&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Converts a given integer between 0 and 100 to English text (e.g. 47 -&amp;gt; forty-seven).&lt;br /&gt;
local function numeral_to_english_less_100(num, ordinal, plural, zero)&lt;br /&gt;
	local terminal_ones, terminal_tens&lt;br /&gt;
	if ordinal then&lt;br /&gt;
		terminal_ones = ones_position_ord&lt;br /&gt;
		terminal_tens = tens_position_ord&lt;br /&gt;
	elseif plural then&lt;br /&gt;
		terminal_ones = ones_position_plural&lt;br /&gt;
		terminal_tens = tens_position_plural&lt;br /&gt;
	else&lt;br /&gt;
		terminal_ones = ones_position&lt;br /&gt;
		terminal_tens = tens_position&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if num == 0 and zero ~= nil then&lt;br /&gt;
		return zero&lt;br /&gt;
	elseif num &amp;lt; 20 then&lt;br /&gt;
		return terminal_ones[num]&lt;br /&gt;
	elseif num % 10 == 0 then&lt;br /&gt;
		return terminal_tens[num / 10]&lt;br /&gt;
	else&lt;br /&gt;
		return tens_position[math.floor(num / 10)] .. &#039;-&#039; .. terminal_ones[num % 10]&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function standard_suffix(ordinal, plural)&lt;br /&gt;
	if ordinal then return &#039;th&#039; end&lt;br /&gt;
	if plural then return &#039;s&#039; end&lt;br /&gt;
	return &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Converts a given integer (in string form) between 0 and 1000 to English text (e.g. 47 -&amp;gt; forty-seven).&lt;br /&gt;
local function numeral_to_english_less_1000(num, use_and, ordinal, plural, zero)&lt;br /&gt;
	num = tonumber(num)&lt;br /&gt;
	if num &amp;lt; 100 then&lt;br /&gt;
		return numeral_to_english_less_100(num, ordinal, plural, zero)&lt;br /&gt;
	elseif num % 100 == 0 then&lt;br /&gt;
		return ones_position[num/100] .. &#039; hundred&#039; .. standard_suffix(ordinal, plural)&lt;br /&gt;
	else&lt;br /&gt;
		return ones_position[math.floor(num/100)] .. &#039; hundred &#039; .. (use_and and &#039;and &#039; or &#039;&#039;) .. numeral_to_english_less_100(num % 100, ordinal, plural, zero)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Converts an ordinal in English text from &#039;zeroth&#039; to &#039;ninety-ninth&#039; inclusive to a number [0–99], else -1.&lt;br /&gt;
local function english_to_ordinal(english)&lt;br /&gt;
	local eng = string.lower(english or &#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
	local engord_lt20 = {} -- ones_position_ord{} keys &amp;amp; values swapped&lt;br /&gt;
	for k, v in pairs( ones_position_ord ) do&lt;br /&gt;
		engord_lt20[v] = k&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if engord_lt20[eng] then&lt;br /&gt;
		return engord_lt20[eng] -- e.g. first -&amp;gt; 1&lt;br /&gt;
	elseif engord_tens_end[eng] then&lt;br /&gt;
		return engord_tens_end[eng] -- e.g. ninetieth -&amp;gt; 90&lt;br /&gt;
	else&lt;br /&gt;
		local tens, ones = string.match(eng, &#039;^([a-z]+)[%s%-]+([a-z]+)$&#039;)&lt;br /&gt;
		if tens and ones then&lt;br /&gt;
			local tens_cont = eng_tens_cont[tens]&lt;br /&gt;
			local ones_end  = engord_lt20[ones]&lt;br /&gt;
			if tens_cont and ones_end then&lt;br /&gt;
				return tens_cont + ones_end -- e.g. ninety-ninth -&amp;gt; 99&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return -1 -- Failed&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Converts a number in English text from &#039;zero&#039; to &#039;ninety-nine&#039; inclusive to a number [0–99], else -1.&lt;br /&gt;
local function english_to_numeral(english)&lt;br /&gt;
	local eng = string.lower(english or &#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
	local eng_lt20 = { [&#039;single&#039;] = 1 } -- ones_position{} keys &amp;amp; values swapped&lt;br /&gt;
	for k, v in pairs( ones_position ) do&lt;br /&gt;
		eng_lt20[v] = k&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if eng_lt20[eng] then&lt;br /&gt;
		return eng_lt20[eng] -- e.g. one -&amp;gt; 1&lt;br /&gt;
	elseif eng_tens_cont[eng] then&lt;br /&gt;
		return eng_tens_cont[eng] -- e.g. ninety -&amp;gt; 90&lt;br /&gt;
	else&lt;br /&gt;
		local tens, ones = string.match(eng, &#039;^([a-z]+)[%s%-]+([a-z]+)$&#039;)&lt;br /&gt;
		if tens and ones then&lt;br /&gt;
			local tens_cont = eng_tens_cont[tens]&lt;br /&gt;
			local ones_end  = eng_lt20[ones]&lt;br /&gt;
			if tens_cont and ones_end then&lt;br /&gt;
				return tens_cont + ones_end -- e.g. ninety-nine -&amp;gt; 99&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return -1 -- Failed&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Converts a number expressed as a string in scientific notation to a string in standard decimal notation&lt;br /&gt;
-- e.g. 1.23E5 -&amp;gt; 123000, 1.23E-5 = .0000123. Conversion is exact, no rounding is performed.&lt;br /&gt;
local function scientific_notation_to_decimal(num)&lt;br /&gt;
	local exponent, subs = num:gsub(&amp;quot;^%-?%d*%.?%d*%-?[Ee]([+%-]?%d+)$&amp;quot;, &amp;quot;%1&amp;quot;)&lt;br /&gt;
	if subs == 0 then return num end  -- Input not in scientific notation, just return unmodified&lt;br /&gt;
	exponent = tonumber(exponent)&lt;br /&gt;
&lt;br /&gt;
	local negative = num:find(&amp;quot;^%-&amp;quot;)&lt;br /&gt;
	local _, decimal_pos = num:find(&amp;quot;%.&amp;quot;)&lt;br /&gt;
	-- Mantissa will consist of all decimal digits with no decimal point&lt;br /&gt;
	local mantissa = num:gsub(&amp;quot;^%-?(%d*)%.?(%d*)%-?[Ee][+%-]?%d+$&amp;quot;, &amp;quot;%1%2&amp;quot;)&lt;br /&gt;
	if negative and decimal_pos then decimal_pos = decimal_pos - 1 end&lt;br /&gt;
	if not decimal_pos then decimal_pos = #mantissa + 1 end&lt;br /&gt;
&lt;br /&gt;
	-- Remove leading zeros unless decimal point is in first position&lt;br /&gt;
	while decimal_pos &amp;gt; 1 and mantissa:sub(1,1) == &#039;0&#039; do&lt;br /&gt;
		mantissa = mantissa:sub(2)&lt;br /&gt;
		decimal_pos = decimal_pos - 1&lt;br /&gt;
	end&lt;br /&gt;
	-- Shift decimal point right for exponent &amp;gt; 0&lt;br /&gt;
	while exponent &amp;gt; 0 do&lt;br /&gt;
		decimal_pos = decimal_pos + 1&lt;br /&gt;
		exponent = exponent - 1&lt;br /&gt;
		if decimal_pos &amp;gt; #mantissa + 1 then mantissa = mantissa .. &#039;0&#039; end&lt;br /&gt;
		-- Remove leading zeros unless decimal point is in first position&lt;br /&gt;
		while decimal_pos &amp;gt; 1 and mantissa:sub(1,1) == &#039;0&#039; do&lt;br /&gt;
			mantissa = mantissa:sub(2)&lt;br /&gt;
			decimal_pos = decimal_pos - 1&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	-- Shift decimal point left for exponent &amp;lt; 0&lt;br /&gt;
	while exponent &amp;lt; 0 do&lt;br /&gt;
		if decimal_pos == 1 then&lt;br /&gt;
			mantissa = &#039;0&#039; .. mantissa&lt;br /&gt;
		else&lt;br /&gt;
			decimal_pos = decimal_pos - 1&lt;br /&gt;
		end&lt;br /&gt;
		exponent = exponent + 1&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Insert decimal point in correct position and return&lt;br /&gt;
	return (negative and &#039;-&#039; or &#039;&#039;) .. mantissa:sub(1, decimal_pos - 1) .. &#039;.&#039; .. mantissa:sub(decimal_pos)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Rounds a number to the nearest integer (NOT USED)&lt;br /&gt;
local function round_num(x)&lt;br /&gt;
	if x%1 &amp;gt;= 0.5 then&lt;br /&gt;
		return math.ceil(x)&lt;br /&gt;
	else&lt;br /&gt;
		return math.floor(x)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Rounds a number to the nearest two-word number (round = up, down, or &amp;quot;on&amp;quot; for round to nearest).&lt;br /&gt;
-- Numbers with two digits before the decimal will be rounded to an integer as specified by round.&lt;br /&gt;
-- Larger numbers will be rounded to a number with only one nonzero digit in front and all other digits zero.&lt;br /&gt;
-- Negative sign is preserved and does not count towards word limit.&lt;br /&gt;
local function round_for_english(num, round)&lt;br /&gt;
	-- If an integer with at most two digits, just return&lt;br /&gt;
	if num:find(&amp;quot;^%-?%d?%d%.?$&amp;quot;) then return num end&lt;br /&gt;
&lt;br /&gt;
	local negative = num:find(&amp;quot;^%-&amp;quot;)&lt;br /&gt;
	if negative then&lt;br /&gt;
		-- We&#039;re rounding magnitude so flip it&lt;br /&gt;
		if round == &#039;up&#039; then round = &#039;down&#039; elseif round == &#039;down&#039; then round = &#039;up&#039; end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- If at most two digits before decimal, round to integer and return&lt;br /&gt;
	local _, _, small_int, trailing_digits, round_digit = num:find(&amp;quot;^%-?(%d?%d?)%.((%d)%d*)$&amp;quot;)&lt;br /&gt;
	if small_int then&lt;br /&gt;
		if small_int == &#039;&#039; then small_int = &#039;0&#039; end&lt;br /&gt;
		if (round == &#039;up&#039; and trailing_digits:find(&#039;[1-9]&#039;)) or (round == &#039;on&#039; and tonumber(round_digit) &amp;gt;= 5) then&lt;br /&gt;
			small_int = tostring(tonumber(small_int) + 1)&lt;br /&gt;
		end&lt;br /&gt;
		return (negative and &#039;-&#039; or &#039;&#039;) .. small_int&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- When rounding up, any number with &amp;gt; 1 nonzero digit will round up (e.g. 1000000.001 rounds up to 2000000)&lt;br /&gt;
	local nonzero_digits = 0&lt;br /&gt;
	for digit in num:gfind(&amp;quot;[1-9]&amp;quot;) do&lt;br /&gt;
		nonzero_digits = nonzero_digits + 1&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	num = num:gsub(&amp;quot;%.%d*$&amp;quot;, &amp;quot;&amp;quot;) -- Remove decimal part&lt;br /&gt;
	-- Second digit used to determine which way to round lead digit&lt;br /&gt;
	local _, _, lead_digit, round_digit, round_digit_2, rest = num:find(&amp;quot;^%-?(%d)(%d)(%d)(%d*)$&amp;quot;)&lt;br /&gt;
	if tonumber(lead_digit .. round_digit) &amp;lt; 20 and (1 + #rest) % 3 == 0 then&lt;br /&gt;
		-- In English numbers &amp;lt; 20 are one word so put 2 digits in lead and round based on 3rd&lt;br /&gt;
		lead_digit = lead_digit .. round_digit&lt;br /&gt;
		round_digit = round_digit_2&lt;br /&gt;
	else&lt;br /&gt;
		rest = round_digit_2 .. rest&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if (round == &#039;up&#039; and nonzero_digits &amp;gt; 1) or (round == &#039;on&#039; and tonumber(round_digit) &amp;gt;= 5) then&lt;br /&gt;
		lead_digit = tostring(tonumber(lead_digit) + 1)&lt;br /&gt;
	end&lt;br /&gt;
	-- All digits but lead digit will turn to zero&lt;br /&gt;
	rest = rest:gsub(&amp;quot;%d&amp;quot;, &amp;quot;0&amp;quot;)&lt;br /&gt;
	return (negative and &#039;-&#039; or &#039;&#039;) .. lead_digit .. &#039;0&#039; .. rest&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local denominators = {&lt;br /&gt;
	[2] = { &#039;half&#039;, plural = &#039;halves&#039; },&lt;br /&gt;
	[3] = { &#039;third&#039; },&lt;br /&gt;
	[4] = { &#039;quarter&#039;, us = &#039;fourth&#039; },&lt;br /&gt;
	[5] = { &#039;fifth&#039; },&lt;br /&gt;
	[6] = { &#039;sixth&#039; },&lt;br /&gt;
	[8] = { &#039;eighth&#039; },&lt;br /&gt;
	[9] = { &#039;ninth&#039; },&lt;br /&gt;
	[10] = { &#039;tenth&#039; },&lt;br /&gt;
	[16] = { &#039;sixteenth&#039; },&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
-- Return status, fraction where:&lt;br /&gt;
-- status is a string:&lt;br /&gt;
--     &amp;quot;finished&amp;quot; if there is a fraction with no whole number;&lt;br /&gt;
--     &amp;quot;ok&amp;quot; if fraction is empty or valid;&lt;br /&gt;
--     &amp;quot;unsupported&amp;quot; if bad fraction;&lt;br /&gt;
-- fraction is a string giving (numerator / denominator) as English text, or is &amp;quot;&amp;quot;.&lt;br /&gt;
-- Only unsigned fractions with a very limited range of values are supported,&lt;br /&gt;
-- except that if whole is empty, the numerator can use &amp;quot;-&amp;quot; to indicate negative.&lt;br /&gt;
-- whole (string or nil): nil or &amp;quot;&amp;quot; if no number before the fraction&lt;br /&gt;
-- numerator (string or nil): numerator, if any (default = 1 if a denominator is given)&lt;br /&gt;
-- denominator (string or nil): denominator, if any&lt;br /&gt;
-- sp_us (boolean): true if sp=us&lt;br /&gt;
-- negative_word (string): word to use for negative sign, if whole is empty&lt;br /&gt;
-- use_one (boolean): false: 2+1/2 → &amp;quot;two and a half&amp;quot;; true: &amp;quot;two and one-half&amp;quot;&lt;br /&gt;
local function fraction_to_english(whole, numerator, denominator, sp_us, negative_word, use_one)&lt;br /&gt;
	if numerator or denominator then&lt;br /&gt;
		local finished = (whole == nil or whole == &#039;&#039;)&lt;br /&gt;
		local sign = &#039;&#039;&lt;br /&gt;
		if numerator then&lt;br /&gt;
			if finished and numerator:sub(1, 1) == &#039;-&#039; then&lt;br /&gt;
				numerator = numerator:sub(2)&lt;br /&gt;
				sign = negative_word .. &#039; &#039;&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			numerator = &#039;1&#039;&lt;br /&gt;
		end&lt;br /&gt;
		if not numerator:match(&#039;^%d+$&#039;) or not denominator or not denominator:match(&#039;^%d+$&#039;) then&lt;br /&gt;
			return &#039;unsupported&#039;, &#039;&#039;&lt;br /&gt;
		end&lt;br /&gt;
		numerator = tonumber(numerator)&lt;br /&gt;
		denominator = tonumber(denominator)&lt;br /&gt;
		local dendata = denominators[denominator]&lt;br /&gt;
		if not (dendata and 1 &amp;lt;= numerator and numerator &amp;lt;= 99) then&lt;br /&gt;
			return &#039;unsupported&#039;, &#039;&#039;&lt;br /&gt;
		end&lt;br /&gt;
		local numstr, denstr&lt;br /&gt;
		local sep = &#039;-&#039;&lt;br /&gt;
		if numerator == 1 then&lt;br /&gt;
			denstr = sp_us and dendata.us or dendata[1]&lt;br /&gt;
			if finished or use_one then&lt;br /&gt;
				numstr = &#039;one&#039;&lt;br /&gt;
			elseif denstr:match(&#039;^[aeiou]&#039;) then&lt;br /&gt;
				numstr = &#039;an&#039;&lt;br /&gt;
				sep = &#039; &#039;&lt;br /&gt;
			else&lt;br /&gt;
				numstr = &#039;a&#039;&lt;br /&gt;
				sep = &#039; &#039;&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			numstr = numeral_to_english_less_100(numerator)&lt;br /&gt;
			denstr = dendata.plural&lt;br /&gt;
			if not denstr then&lt;br /&gt;
				denstr = (sp_us and dendata.us or dendata[1]) .. &#039;s&#039;&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if finished then&lt;br /&gt;
			return &#039;finished&#039;, sign .. numstr .. sep .. denstr&lt;br /&gt;
		end&lt;br /&gt;
		return &#039;ok&#039;, &#039; and &#039; .. numstr .. sep .. denstr&lt;br /&gt;
	end&lt;br /&gt;
	return &#039;ok&#039;, &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Takes a decimal number and converts it to English text.&lt;br /&gt;
-- Return nil if a fraction cannot be converted (only some numbers are supported for fractions).&lt;br /&gt;
-- num (string or nil): the number to convert.&lt;br /&gt;
--      Can be an arbitrarily large decimal, such as &amp;quot;-123456789123456789.345&amp;quot;, and&lt;br /&gt;
--      can use scientific notation (e.g. &amp;quot;1.23E5&amp;quot;).&lt;br /&gt;
--      May fail for very large numbers not listed in &amp;quot;groups&amp;quot; such as &amp;quot;1E4000&amp;quot;.&lt;br /&gt;
--      num is nil if there is no whole number before a fraction.&lt;br /&gt;
-- numerator (string or nil): numerator of fraction (nil if no fraction)&lt;br /&gt;
-- denominator (string or nil): denominator of fraction (nil if no fraction)&lt;br /&gt;
-- capitalize (boolean): whether to capitalize the result (e.g. &#039;One&#039; instead of &#039;one&#039;)&lt;br /&gt;
-- use_and (boolean): whether to use the word &#039;and&#039; between tens/ones place and higher places&lt;br /&gt;
-- hyphenate (boolean): whether to hyphenate all words in the result, useful as an adjective&lt;br /&gt;
-- ordinal (boolean): whether to produce an ordinal (e.g. &#039;first&#039; instead of &#039;one&#039;)&lt;br /&gt;
-- plural (boolean): whether to pluralize the resulting number&lt;br /&gt;
-- links: nil: do not add any links; &#039;on&#039;: link &amp;quot;billion&amp;quot; and larger to Orders of magnitude article;&lt;br /&gt;
--        any other text: list of numbers to link (e.g. &amp;quot;billion,quadrillion&amp;quot;)&lt;br /&gt;
-- negative_word: word to use for negative sign (typically &#039;negative&#039; or &#039;minus&#039;; nil to use default)&lt;br /&gt;
-- round: nil or &#039;&#039;: no rounding; &#039;on&#039;: round to nearest two-word number; &#039;up&#039;/&#039;down&#039;: round up/down to two-word number&lt;br /&gt;
-- zero: word to use for value &#039;0&#039; (nil to use default)&lt;br /&gt;
-- use_one (boolean): false: 2+1/2 → &amp;quot;two and a half&amp;quot;; true: &amp;quot;two and one-half&amp;quot;&lt;br /&gt;
local function _numeral_to_english(num, numerator, denominator, capitalize, use_and, hyphenate, ordinal, plural, links, negative_word, round, zero, use_one)&lt;br /&gt;
	if not negative_word then&lt;br /&gt;
		if use_and then&lt;br /&gt;
			-- TODO Should &#039;minus&#039; be used when do not have sp=us?&lt;br /&gt;
			--      If so, need to update testcases, and need to fix &amp;quot;minus zero&amp;quot;.&lt;br /&gt;
			-- negative_word = &#039;minus&#039;&lt;br /&gt;
			negative_word = &#039;negative&#039;&lt;br /&gt;
		else&lt;br /&gt;
			negative_word = &#039;negative&#039;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local status, fraction_text = fraction_to_english(num, numerator, denominator, not use_and, negative_word, use_one)&lt;br /&gt;
	if status == &#039;unsupported&#039; then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	if status == &#039;finished&#039; then&lt;br /&gt;
		-- Input is a fraction with no whole number.&lt;br /&gt;
		-- Hack to avoid executing stuff that depends on num being a number.&lt;br /&gt;
		local s = fraction_text&lt;br /&gt;
		if hyphenate then s = s:gsub(&amp;quot;%s&amp;quot;, &amp;quot;-&amp;quot;) end&lt;br /&gt;
		if capitalize then s = s:gsub(&amp;quot;^%l&amp;quot;, string.upper) end&lt;br /&gt;
		return s&lt;br /&gt;
	end&lt;br /&gt;
	num = scientific_notation_to_decimal(num)&lt;br /&gt;
	if round and round ~= &#039;&#039; then&lt;br /&gt;
		if round ~= &#039;on&#039; and round ~= &#039;up&#039; and round ~= &#039;down&#039; then&lt;br /&gt;
			error(&amp;quot;Invalid rounding mode&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
		num = round_for_english(num, round)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Separate into negative sign, num (digits before decimal), decimal_places (digits after decimal)&lt;br /&gt;
	local MINUS = &#039;−&#039;  -- Unicode U+2212 MINUS SIGN (may be in values from [[Module:Convert]])&lt;br /&gt;
	if num:sub(1, #MINUS) == MINUS then&lt;br /&gt;
		num = &#039;-&#039; .. num:sub(#MINUS + 1)  -- replace MINUS with &#039;-&#039;&lt;br /&gt;
	elseif num:sub(1, 1) == &#039;+&#039; then&lt;br /&gt;
		num = num:sub(2)  -- ignore any &#039;+&#039;&lt;br /&gt;
	end&lt;br /&gt;
	local negative = num:find(&amp;quot;^%-&amp;quot;)&lt;br /&gt;
	local decimal_places, subs = num:gsub(&amp;quot;^%-?%d*%.(%d+)$&amp;quot;, &amp;quot;%1&amp;quot;)&lt;br /&gt;
	if subs == 0 then decimal_places = nil end&lt;br /&gt;
	num, subs = num:gsub(&amp;quot;^%-?(%d*)%.?%d*$&amp;quot;, &amp;quot;%1&amp;quot;)&lt;br /&gt;
	if num == &#039;&#039; and decimal_places then num = &#039;0&#039; end&lt;br /&gt;
	if subs == 0 or num == &#039;&#039; then error(&amp;quot;Invalid decimal numeral&amp;quot;) end&lt;br /&gt;
&lt;br /&gt;
	-- For each group of 3 digits except the last one, print with appropriate group name (e.g. million)&lt;br /&gt;
	local s = &#039;&#039;&lt;br /&gt;
	while #num &amp;gt; 3 do&lt;br /&gt;
		if s ~= &#039;&#039; then s = s .. &#039; &#039; end&lt;br /&gt;
		local group_num = math.floor((#num - 1) / 3)&lt;br /&gt;
		local group = groups[group_num]&lt;br /&gt;
		local group_digits = #num - group_num*3&lt;br /&gt;
		s = s .. numeral_to_english_less_1000(num:sub(1, group_digits), false, false, false, zero) .. &#039; &#039;&lt;br /&gt;
		if links and (((links == &#039;on&#039; and group_num &amp;gt;= 3) or links:find(group)) and group_num &amp;lt;= 13) then&lt;br /&gt;
			s = s .. &#039;[[Orders_of_magnitude_(numbers)#10&#039; .. group_num*3 .. &#039;|&#039; .. group .. &#039;]]&#039;&lt;br /&gt;
		else&lt;br /&gt;
			s = s .. group&lt;br /&gt;
		end&lt;br /&gt;
		num = num:sub(1 + group_digits)&lt;br /&gt;
		num = num:gsub(&amp;quot;^0*&amp;quot;, &amp;quot;&amp;quot;)  -- Trim leading zeros&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Handle final three digits of integer part&lt;br /&gt;
	if s ~= &#039;&#039; and num ~= &#039;&#039; then&lt;br /&gt;
		if #num &amp;lt;= 2 and use_and then&lt;br /&gt;
			s = s .. &#039; and &#039;&lt;br /&gt;
		else&lt;br /&gt;
			s = s .. &#039; &#039;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if s == &#039;&#039; or num ~= &#039;&#039; then&lt;br /&gt;
		s = s .. numeral_to_english_less_1000(num, use_and, ordinal, plural, zero)&lt;br /&gt;
	elseif ordinal or plural then&lt;br /&gt;
		-- Round numbers like &amp;quot;one million&amp;quot; take standard suffixes for ordinal/plural&lt;br /&gt;
		s = s .. standard_suffix(ordinal, plural)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- For decimal places (if any) output &amp;quot;point&amp;quot; followed by spelling out digit by digit&lt;br /&gt;
	if decimal_places then&lt;br /&gt;
		s = s .. &#039; point&#039;&lt;br /&gt;
		for i = 1, #decimal_places do&lt;br /&gt;
			s = s .. &#039; &#039; .. ones_position[tonumber(decimal_places:sub(i,i))]&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	s = s:gsub(&amp;quot;^%s*(.-)%s*$&amp;quot;, &amp;quot;%1&amp;quot;)   -- Trim whitespace&lt;br /&gt;
	if ordinal and plural then s = s .. &#039;s&#039; end  -- s suffix works for all ordinals&lt;br /&gt;
	if negative and s ~= zero then s = negative_word .. &#039; &#039; .. s end&lt;br /&gt;
	s = s:gsub(&amp;quot;negative zero&amp;quot;, &amp;quot;zero&amp;quot;)&lt;br /&gt;
	s = s .. fraction_text&lt;br /&gt;
	if hyphenate then s = s:gsub(&amp;quot;%s&amp;quot;, &amp;quot;-&amp;quot;) end&lt;br /&gt;
	if capitalize then s = s:gsub(&amp;quot;^%l&amp;quot;, string.upper) end&lt;br /&gt;
	return s&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function _numeral_to_english2(args)&lt;br /&gt;
	local num = tostring(args.num)&lt;br /&gt;
&lt;br /&gt;
	num = num:gsub(&amp;quot;^%s*(.-)%s*$&amp;quot;, &amp;quot;%1&amp;quot;)   -- Trim whitespace&lt;br /&gt;
	num = num:gsub(&amp;quot;,&amp;quot;, &amp;quot;&amp;quot;)   -- Remove commas&lt;br /&gt;
	num = num:gsub(&amp;quot;^&amp;lt;span[^&amp;lt;&amp;gt;]*&amp;gt;&amp;lt;/span&amp;gt;&amp;quot;, &amp;quot;&amp;quot;) -- Generated by Template:age&lt;br /&gt;
	if num ~= &#039;&#039; then  -- a fraction may have an empty whole number&lt;br /&gt;
		if not num:find(&amp;quot;^%-?%d*%.?%d*%-?[Ee]?[+%-]?%d*$&amp;quot;) then&lt;br /&gt;
			-- Input not in a valid format, try to eval it as an expr to see&lt;br /&gt;
			-- if that produces a number (e.g. &amp;quot;3 + 5&amp;quot; will become &amp;quot;8&amp;quot;).&lt;br /&gt;
			local noerr, result = pcall(mw.ext.ParserFunctions.expr, num)&lt;br /&gt;
			if noerr then&lt;br /&gt;
				num = result&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Call helper function passing args&lt;br /&gt;
	return _numeral_to_english(&lt;br /&gt;
		num,&lt;br /&gt;
		args[&#039;numerator&#039;],&lt;br /&gt;
		args[&#039;denominator&#039;],&lt;br /&gt;
		args[&#039;capitalize&#039;],&lt;br /&gt;
		args[&#039;use_and&#039;],&lt;br /&gt;
		args[&#039;hyphenate&#039;],&lt;br /&gt;
		args[&#039;ordinal&#039;],&lt;br /&gt;
		args[&#039;plural&#039;],&lt;br /&gt;
		args[&#039;links&#039;],&lt;br /&gt;
		args[&#039;negative_word&#039;],&lt;br /&gt;
		args[&#039;round&#039;],&lt;br /&gt;
		args[&#039;zero&#039;],&lt;br /&gt;
		args[&#039;use_one&#039;]&lt;br /&gt;
	) or &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local p = {  -- Functions that can be called from another module&lt;br /&gt;
	roman_to_numeral = roman_to_numeral,&lt;br /&gt;
	spell_number = _numeral_to_english,&lt;br /&gt;
	spell_number2 = _numeral_to_english2,&lt;br /&gt;
	english_to_ordinal = english_to_ordinal,&lt;br /&gt;
	english_to_numeral = english_to_numeral,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function p._roman_to_numeral(frame) -- Callable via {{#invoke:ConvertNumeric|_roman_to_numeral|VI}}&lt;br /&gt;
	return roman_to_numeral(frame.args[1])&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._english_to_ordinal(frame) -- callable via {{#invoke:ConvertNumeric|_english_to_ordinal|First}}&lt;br /&gt;
	return english_to_ordinal(frame.args[1])&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._english_to_numeral(frame) -- callable via {{#invoke:ConvertNumeric|_english_to_numeral|One}}&lt;br /&gt;
	return english_to_numeral(frame.args[1])&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.numeral_to_english(frame)&lt;br /&gt;
	local args = frame.args&lt;br /&gt;
	-- Tail call to helper function passing args from frame&lt;br /&gt;
	return _numeral_to_english2{&lt;br /&gt;
		[&#039;num&#039;] = args[1],&lt;br /&gt;
		[&#039;numerator&#039;] = args[&#039;numerator&#039;],&lt;br /&gt;
		[&#039;denominator&#039;] = args[&#039;denominator&#039;],&lt;br /&gt;
		[&#039;capitalize&#039;] = args[&#039;case&#039;] == &#039;U&#039; or args[&#039;case&#039;] == &#039;u&#039;,&lt;br /&gt;
		[&#039;use_and&#039;] = args[&#039;sp&#039;] ~= &#039;us&#039;,&lt;br /&gt;
		[&#039;hyphenate&#039;] = args[&#039;adj&#039;] == &#039;on&#039;,&lt;br /&gt;
		[&#039;ordinal&#039;] = args[&#039;ord&#039;] == &#039;on&#039;,&lt;br /&gt;
		[&#039;plural&#039;] = args[&#039;pl&#039;] == &#039;on&#039;,&lt;br /&gt;
		[&#039;links&#039;] = args[&#039;lk&#039;],&lt;br /&gt;
		[&#039;negative_word&#039;] = args[&#039;negative&#039;],&lt;br /&gt;
		[&#039;round&#039;] = args[&#039;round&#039;],&lt;br /&gt;
		[&#039;zero&#039;] = args[&#039;zero&#039;],&lt;br /&gt;
		[&#039;use_one&#039;] = args[&#039;one&#039;] == &#039;one&#039;  -- experiment: using &#039;|one=one&#039; makes fraction 2+1/2 give &amp;quot;two and one-half&amp;quot; instead of &amp;quot;two and a half&amp;quot;&lt;br /&gt;
	}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
---- recursive function for p.decToHex&lt;br /&gt;
local function decToHexDigit(dec)&lt;br /&gt;
	local dig = {&amp;quot;0&amp;quot;,&amp;quot;1&amp;quot;,&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;,&amp;quot;4&amp;quot;,&amp;quot;5&amp;quot;,&amp;quot;6&amp;quot;,&amp;quot;7&amp;quot;,&amp;quot;8&amp;quot;,&amp;quot;9&amp;quot;,&amp;quot;A&amp;quot;,&amp;quot;B&amp;quot;,&amp;quot;C&amp;quot;,&amp;quot;D&amp;quot;,&amp;quot;E&amp;quot;,&amp;quot;F&amp;quot;}&lt;br /&gt;
	local div = math.floor(dec/16)&lt;br /&gt;
	local mod = dec-(16*div)&lt;br /&gt;
	if div &amp;gt;= 1 then return decToHexDigit(div)..dig[mod+1] else return dig[mod+1] end&lt;br /&gt;
end -- I think this is supposed to be done with a tail call but first I want something that works at all&lt;br /&gt;
&lt;br /&gt;
---- finds all the decimal numbers in the input text and hexes each of them&lt;br /&gt;
function p.decToHex(frame)&lt;br /&gt;
	local args=frame.args&lt;br /&gt;
	local parent=frame.getParent(frame)&lt;br /&gt;
	local pargs={}&lt;br /&gt;
	if parent then pargs=parent.args end&lt;br /&gt;
	local text=args[1] or pargs[1] or &amp;quot;&amp;quot;&lt;br /&gt;
	local minlength=args.minlength or pargs.minlength or 1&lt;br /&gt;
	minlength=tonumber(minlength)&lt;br /&gt;
	local prowl=mw.ustring.gmatch(text,&amp;quot;(.-)(%d+)&amp;quot;)&lt;br /&gt;
	local output=&amp;quot;&amp;quot;&lt;br /&gt;
	repeat&lt;br /&gt;
		local chaff,dec=prowl()&lt;br /&gt;
		if not(dec) then break end&lt;br /&gt;
		local hex=decToHexDigit(dec)&lt;br /&gt;
		while (mw.ustring.len(hex)&amp;lt;minlength) do hex=&amp;quot;0&amp;quot;..hex end&lt;br /&gt;
		output=output..chaff..hex&lt;br /&gt;
	until false&lt;br /&gt;
	local chaff=mw.ustring.match(text,&amp;quot;(%D+)$&amp;quot;) or &amp;quot;&amp;quot;&lt;br /&gt;
	return output..chaff&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EB%AA%A8%EB%93%88:Date3&amp;diff=62831</id>
		<title>모듈:Date3</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EB%AA%A8%EB%93%88:Date3&amp;diff=62831"/>
		<updated>2026-07-05T15:19:46Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: 한국어 위키백과 https://ko.wikipedia.org/wiki/모듈:Date3에서 모듈 가져옴&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;-- Date functions for use by other modules.&lt;br /&gt;
-- I18N and time zones are not supported.&lt;br /&gt;
&lt;br /&gt;
local MINUS = &#039;−&#039;  -- Unicode U+2212 MINUS SIGN&lt;br /&gt;
local floor = math.floor&lt;br /&gt;
&lt;br /&gt;
local Date, DateDiff, diffmt  -- forward declarations&lt;br /&gt;
local uniq = { &#039;unique identifier&#039; }&lt;br /&gt;
&lt;br /&gt;
local function is_date(t)&lt;br /&gt;
	-- The system used to make a date read-only means there is no unique&lt;br /&gt;
	-- metatable that is conveniently accessible to check.&lt;br /&gt;
	return type(t) == &#039;table&#039; and t._id == uniq&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function is_diff(t)&lt;br /&gt;
	return type(t) == &#039;table&#039; and getmetatable(t) == diffmt&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function _list_join(list, sep)&lt;br /&gt;
	return table.concat(list, sep)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function collection()&lt;br /&gt;
	-- Return a table to hold items.&lt;br /&gt;
	return {&lt;br /&gt;
		n = 0,&lt;br /&gt;
		add = function (self, item)&lt;br /&gt;
			self.n = self.n + 1&lt;br /&gt;
			self[self.n] = item&lt;br /&gt;
		end,&lt;br /&gt;
		join = _list_join,&lt;br /&gt;
	}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function strip_to_nil(text)&lt;br /&gt;
	-- If text is a string, return its trimmed content, or nil if empty.&lt;br /&gt;
	-- Otherwise return text (convenient when Date fields are provided from&lt;br /&gt;
	-- another module which may pass a string, a number, or another type).&lt;br /&gt;
	if type(text) == &#039;string&#039; then&lt;br /&gt;
		text = text:match(&#039;(%S.-)%s*$&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	return text&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function is_leap_year(year, calname)&lt;br /&gt;
	-- Return true if year is a leap year.&lt;br /&gt;
	if calname == &#039;Julian&#039; then&lt;br /&gt;
		return year % 4 == 0&lt;br /&gt;
	end&lt;br /&gt;
	return (year % 4 == 0 and year % 100 ~= 0) or year % 400 == 0&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function days_in_month(year, month, calname)&lt;br /&gt;
	-- Return number of days (1..31) in given month (1..12).&lt;br /&gt;
	if month == 2 and is_leap_year(year, calname) then&lt;br /&gt;
		return 29&lt;br /&gt;
	end&lt;br /&gt;
	return ({ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 })[month]&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function h_m_s(time)&lt;br /&gt;
	-- Return hour, minute, second extracted from fraction of a day.&lt;br /&gt;
	time = floor(time * 24 * 3600 + 0.5)  -- number of seconds&lt;br /&gt;
	local second = time % 60&lt;br /&gt;
	time = floor(time / 60)&lt;br /&gt;
	return floor(time / 60), time % 60, second&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function hms(date)&lt;br /&gt;
	-- Return fraction of a day from date&#039;s time, where (0 &amp;lt;= fraction &amp;lt; 1)&lt;br /&gt;
	-- if the values are valid, but could be anything if outside range.&lt;br /&gt;
	return (date.hour + (date.minute + date.second / 60) / 60) / 24&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function julian_date(date)&lt;br /&gt;
	-- Return jd, jdz from a Julian or Gregorian calendar date where&lt;br /&gt;
	--   jd = Julian date and its fractional part is zero at noon&lt;br /&gt;
	--   jdz = same, but assume time is 00:00:00 if no time given&lt;br /&gt;
	-- http://www.tondering.dk/claus/cal/julperiod.php#formula&lt;br /&gt;
	-- Testing shows this works for all dates from year -9999 to 9999!&lt;br /&gt;
	-- JDN 0 is the 24-hour period starting at noon UTC on Monday&lt;br /&gt;
	--    1 January 4713 BC  = (-4712, 1, 1)   Julian calendar&lt;br /&gt;
	--   24 November 4714 BC = (-4713, 11, 24) Gregorian calendar&lt;br /&gt;
	local offset&lt;br /&gt;
	local a = floor((14 - date.month)/12)&lt;br /&gt;
	local y = date.year + 4800 - a&lt;br /&gt;
	if date.calendar == &#039;Julian&#039; then&lt;br /&gt;
		offset = floor(y/4) - 32083&lt;br /&gt;
	else&lt;br /&gt;
		offset = floor(y/4) - floor(y/100) + floor(y/400) - 32045&lt;br /&gt;
	end&lt;br /&gt;
	local m = date.month + 12*a - 3&lt;br /&gt;
	local jd = date.day + floor((153*m + 2)/5) + 365*y + offset&lt;br /&gt;
	if date.hastime then&lt;br /&gt;
		jd = jd + hms(date) - 0.5&lt;br /&gt;
		return jd, jd&lt;br /&gt;
	end&lt;br /&gt;
	return jd, jd - 0.5&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function set_date_from_jd(date)&lt;br /&gt;
	-- Set the fields of table date from its Julian date field.&lt;br /&gt;
	-- Return true if date is valid.&lt;br /&gt;
	-- http://www.tondering.dk/claus/cal/julperiod.php#formula&lt;br /&gt;
	-- This handles the proleptic Julian and Gregorian calendars.&lt;br /&gt;
	-- Negative Julian dates are not defined but they work.&lt;br /&gt;
	local calname = date.calendar&lt;br /&gt;
	local low, high  -- min/max limits for date ranges −9999-01-01 to 9999-12-31&lt;br /&gt;
	if calname == &#039;Gregorian&#039; then&lt;br /&gt;
		low, high = -1930999.5, 5373484.49999&lt;br /&gt;
	elseif calname == &#039;Julian&#039; then&lt;br /&gt;
		low, high = -1931076.5, 5373557.49999&lt;br /&gt;
	else&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
	local jd = date.jd&lt;br /&gt;
	if not (type(jd) == &#039;number&#039; and low &amp;lt;= jd and jd &amp;lt;= high) then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
	local jdn = floor(jd)&lt;br /&gt;
	if date.hastime then&lt;br /&gt;
		local time = jd - jdn  -- 0 &amp;lt;= time &amp;lt; 1&lt;br /&gt;
		if time &amp;gt;= 0.5 then    -- if at or after midnight of next day&lt;br /&gt;
			jdn = jdn + 1&lt;br /&gt;
			time = time - 0.5&lt;br /&gt;
		else&lt;br /&gt;
			time = time + 0.5&lt;br /&gt;
		end&lt;br /&gt;
		date.hour, date.minute, date.second = h_m_s(time)&lt;br /&gt;
	else&lt;br /&gt;
		date.second = 0&lt;br /&gt;
		date.minute = 0&lt;br /&gt;
		date.hour = 0&lt;br /&gt;
	end&lt;br /&gt;
	local b, c&lt;br /&gt;
	if calname == &#039;Julian&#039; then&lt;br /&gt;
		b = 0&lt;br /&gt;
		c = jdn + 32082&lt;br /&gt;
	else  -- Gregorian&lt;br /&gt;
		local a = jdn + 32044&lt;br /&gt;
		b = floor((4*a + 3)/146097)&lt;br /&gt;
		c = a - floor(146097*b/4)&lt;br /&gt;
	end&lt;br /&gt;
	local d = floor((4*c + 3)/1461)&lt;br /&gt;
	local e = c - floor(1461*d/4)&lt;br /&gt;
	local m = floor((5*e + 2)/153)&lt;br /&gt;
	date.day = e - floor((153*m + 2)/5) + 1&lt;br /&gt;
	date.month = m + 3 - 12*floor(m/10)&lt;br /&gt;
	date.year = 100*b + d - 4800 + floor(m/10)&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function fix_numbers(numbers, y, m, d, H, M, S, partial, hastime, calendar)&lt;br /&gt;
	-- Put the result of normalizing the given values in table numbers.&lt;br /&gt;
	-- The result will have valid m, d values if y is valid; caller checks y.&lt;br /&gt;
	-- The logic of PHP mktime is followed where m or d can be zero to mean&lt;br /&gt;
	-- the previous unit, and -1 is the one before that, etc.&lt;br /&gt;
	-- Positive values carry forward.&lt;br /&gt;
	local date&lt;br /&gt;
	if not (1 &amp;lt;= m and m &amp;lt;= 12) then&lt;br /&gt;
		date = Date(y, 1, 1)&lt;br /&gt;
		if not date then return end&lt;br /&gt;
		date = date + ((m - 1) .. &#039;m&#039;)&lt;br /&gt;
		y, m = date.year, date.month&lt;br /&gt;
	end&lt;br /&gt;
	local days_hms&lt;br /&gt;
	if not partial then&lt;br /&gt;
		if hastime and H and M and S then&lt;br /&gt;
			if not (0 &amp;lt;= H and H &amp;lt;= 23 and&lt;br /&gt;
					0 &amp;lt;= M and M &amp;lt;= 59 and&lt;br /&gt;
					0 &amp;lt;= S and S &amp;lt;= 59) then&lt;br /&gt;
				days_hms = hms({ hour = H, minute = M, second = S })&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if days_hms or not (1 &amp;lt;= d and d &amp;lt;= days_in_month(y, m, calendar)) then&lt;br /&gt;
			date = date or Date(y, m, 1)&lt;br /&gt;
			if not date then return end&lt;br /&gt;
			date = date + (d - 1 + (days_hms or 0))&lt;br /&gt;
			y, m, d = date.year, date.month, date.day&lt;br /&gt;
			if days_hms then&lt;br /&gt;
				H, M, S = date.hour, date.minute, date.second&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	numbers.year = y&lt;br /&gt;
	numbers.month = m&lt;br /&gt;
	numbers.day = d&lt;br /&gt;
	if days_hms then&lt;br /&gt;
		-- Don&#039;t set H unless it was valid because a valid H will set hastime.&lt;br /&gt;
		numbers.hour = H&lt;br /&gt;
		numbers.minute = M&lt;br /&gt;
		numbers.second = S&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function set_date_from_numbers(date, numbers, options)&lt;br /&gt;
	-- Set the fields of table date from numeric values.&lt;br /&gt;
	-- Return true if date is valid.&lt;br /&gt;
	if type(numbers) ~= &#039;table&#039; then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
	local y = numbers.year   or date.year&lt;br /&gt;
	local m = numbers.month  or date.month&lt;br /&gt;
	local d = numbers.day    or date.day&lt;br /&gt;
	local H = numbers.hour&lt;br /&gt;
	local M = numbers.minute or date.minute or 0&lt;br /&gt;
	local S = numbers.second or date.second or 0&lt;br /&gt;
	local need_fix&lt;br /&gt;
	if y and m and d then&lt;br /&gt;
		date.partial = nil&lt;br /&gt;
		if not (-9999 &amp;lt;= y and y &amp;lt;= 9999 and&lt;br /&gt;
			1 &amp;lt;= m and m &amp;lt;= 12 and&lt;br /&gt;
			1 &amp;lt;= d and d &amp;lt;= days_in_month(y, m, date.calendar)) then&lt;br /&gt;
				if not date.want_fix then&lt;br /&gt;
					return&lt;br /&gt;
				end&lt;br /&gt;
				need_fix = true&lt;br /&gt;
		end&lt;br /&gt;
	elseif y and date.partial then&lt;br /&gt;
		if d or not (-9999 &amp;lt;= y and y &amp;lt;= 9999) then&lt;br /&gt;
			return&lt;br /&gt;
		end&lt;br /&gt;
		if m and not (1 &amp;lt;= m and m &amp;lt;= 12) then&lt;br /&gt;
			if not date.want_fix then&lt;br /&gt;
				return&lt;br /&gt;
			end&lt;br /&gt;
			need_fix = true&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
	if date.partial then&lt;br /&gt;
		H = nil  -- ignore any time&lt;br /&gt;
		M = nil&lt;br /&gt;
		S = nil&lt;br /&gt;
	else&lt;br /&gt;
		if H then&lt;br /&gt;
			-- It is not possible to set M or S without also setting H.&lt;br /&gt;
			date.hastime = true&lt;br /&gt;
		else&lt;br /&gt;
			H = 0&lt;br /&gt;
		end&lt;br /&gt;
		if not (0 &amp;lt;= H and H &amp;lt;= 23 and&lt;br /&gt;
				0 &amp;lt;= M and M &amp;lt;= 59 and&lt;br /&gt;
				0 &amp;lt;= S and S &amp;lt;= 59) then&lt;br /&gt;
			if date.want_fix then&lt;br /&gt;
				need_fix = true&lt;br /&gt;
			else&lt;br /&gt;
				return&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	date.want_fix = nil&lt;br /&gt;
	if need_fix then&lt;br /&gt;
		fix_numbers(numbers, y, m, d, H, M, S, date.partial, date.hastime, date.calendar)&lt;br /&gt;
		return set_date_from_numbers(date, numbers, options)&lt;br /&gt;
	end&lt;br /&gt;
	date.year = y    -- -9999 to 9999 (&#039;n BC&#039; → year = 1 - n)&lt;br /&gt;
	date.month = m   -- 1 to 12 (may be nil if partial)&lt;br /&gt;
	date.day = d     -- 1 to 31 (* = nil if partial)&lt;br /&gt;
	date.hour = H    -- 0 to 59 (*)&lt;br /&gt;
	date.minute = M  -- 0 to 59 (*)&lt;br /&gt;
	date.second = S  -- 0 to 59 (*)&lt;br /&gt;
	if type(options) == &#039;table&#039; then&lt;br /&gt;
		for _, k in ipairs({ &#039;am&#039;, &#039;era&#039;, &#039;format&#039; }) do&lt;br /&gt;
			if options[k] then&lt;br /&gt;
				date.options[k] = options[k]&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function make_option_table(options1, options2)&lt;br /&gt;
	-- If options1 is a string, return a table with its settings, or&lt;br /&gt;
	-- if it is a table, use its settings.&lt;br /&gt;
	-- Missing options are set from table options2 or defaults.&lt;br /&gt;
	-- If a default is used, a flag is set so caller knows the value was not intentionally set.&lt;br /&gt;
	-- Valid option settings are:&lt;br /&gt;
	-- am: &#039;am&#039;, &#039;a.m.&#039;, &#039;AM&#039;, &#039;A.M.&#039;&lt;br /&gt;
	--     &#039;pm&#039;, &#039;p.m.&#039;, &#039;PM&#039;, &#039;P.M.&#039; (each has same meaning as corresponding item above)&lt;br /&gt;
	-- era: &#039;BCMINUS&#039;, &#039;BCNEGATIVE&#039;, &#039;BC&#039;, &#039;B.C.&#039;, &#039;BCE&#039;, &#039;B.C.E.&#039;, &#039;AD&#039;, &#039;A.D.&#039;, &#039;CE&#039;, &#039;C.E.&#039;&lt;br /&gt;
	-- Option am = &#039;am&#039; does not mean the hour is AM; it means &#039;am&#039; or &#039;pm&#039; is used, depending on the hour,&lt;br /&gt;
	--    and am = &#039;pm&#039; has the same meaning.&lt;br /&gt;
	-- Similarly, era = &#039;BC&#039; means &#039;BC&#039; is used if year &amp;lt;= 0.&lt;br /&gt;
	-- BCMINUS displays a MINUS if year &amp;lt; 0 and the display format does not include %{era}.&lt;br /&gt;
	-- BCNEGATIVE is similar but displays a hyphen.&lt;br /&gt;
	local result = { bydefault = {} }&lt;br /&gt;
	if type(options1) == &#039;table&#039; then&lt;br /&gt;
		result.am = options1.am&lt;br /&gt;
		result.era = options1.era&lt;br /&gt;
	elseif type(options1) == &#039;string&#039; then&lt;br /&gt;
		-- Example: &#039;am:AM era:BC&#039; or &#039;am=AM era=BC&#039;.&lt;br /&gt;
		for item in options1:gmatch(&#039;%S+&#039;) do&lt;br /&gt;
			local lhs, rhs = item:match(&#039;^(%w+)[:=](.+)$&#039;)&lt;br /&gt;
			if lhs then&lt;br /&gt;
				result[lhs] = rhs&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	options2 = type(options2) == &#039;table&#039; and options2 or {}&lt;br /&gt;
	local defaults = { am = &#039;am&#039;, era = &#039;BC&#039; }&lt;br /&gt;
	for k, v in pairs(defaults) do&lt;br /&gt;
		if not result[k] then&lt;br /&gt;
			if options2[k] then&lt;br /&gt;
				result[k] = options2[k]&lt;br /&gt;
			else&lt;br /&gt;
				result[k] = v&lt;br /&gt;
				result.bydefault[k] = true&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return result&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local ampm_options = {&lt;br /&gt;
	-- lhs = input text accepted as an am/pm option&lt;br /&gt;
	-- rhs = code used internally&lt;br /&gt;
	[&#039;am&#039;]   = &#039;am&#039;,&lt;br /&gt;
	[&#039;AM&#039;]   = &#039;AM&#039;,&lt;br /&gt;
	[&#039;a.m.&#039;] = &#039;a.m.&#039;,&lt;br /&gt;
	[&#039;A.M.&#039;] = &#039;A.M.&#039;,&lt;br /&gt;
	[&#039;pm&#039;]   = &#039;am&#039;,  -- same as am&lt;br /&gt;
	[&#039;PM&#039;]   = &#039;AM&#039;,&lt;br /&gt;
	[&#039;p.m.&#039;] = &#039;a.m.&#039;,&lt;br /&gt;
	[&#039;P.M.&#039;] = &#039;A.M.&#039;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local era_text = {&lt;br /&gt;
	-- Text for displaying an era with a positive year (after adjusting&lt;br /&gt;
	-- by replacing year with 1 - year if date.year &amp;lt;= 0).&lt;br /&gt;
	-- options.era = { year&amp;lt;=0 , year&amp;gt;0 }&lt;br /&gt;
	[&#039;BCMINUS&#039;]    = { &#039;BC&#039;    , &#039;&#039;    , isbc = true, sign = MINUS },&lt;br /&gt;
	[&#039;BCNEGATIVE&#039;] = { &#039;BC&#039;    , &#039;&#039;    , isbc = true, sign = &#039;-&#039;   },&lt;br /&gt;
	[&#039;BC&#039;]         = { &#039;BC&#039;    , &#039;&#039;    , isbc = true },&lt;br /&gt;
	[&#039;B.C.&#039;]       = { &#039;B.C.&#039;  , &#039;&#039;    , isbc = true },&lt;br /&gt;
	[&#039;BCE&#039;]        = { &#039;BCE&#039;   , &#039;&#039;    , isbc = true },&lt;br /&gt;
	[&#039;B.C.E.&#039;]     = { &#039;B.C.E.&#039;, &#039;&#039;    , isbc = true },&lt;br /&gt;
	[&#039;AD&#039;]         = { &#039;BC&#039;    , &#039;AD&#039;   },&lt;br /&gt;
	[&#039;A.D.&#039;]       = { &#039;B.C.&#039;  , &#039;A.D.&#039; },&lt;br /&gt;
	[&#039;CE&#039;]         = { &#039;BCE&#039;   , &#039;CE&#039;   },&lt;br /&gt;
	[&#039;C.E.&#039;]       = { &#039;B.C.E.&#039;, &#039;C.E.&#039; },&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local function get_era_for_year(era, year)&lt;br /&gt;
	return (era_text[era] or era_text[&#039;BC&#039;])[year &amp;gt; 0 and 2 or 1] or &#039;&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function strftime(date, format, options)&lt;br /&gt;
	-- Return date formatted as a string using codes similar to those&lt;br /&gt;
	-- in the C strftime library function.&lt;br /&gt;
	local sformat = string.format&lt;br /&gt;
	local shortcuts = {&lt;br /&gt;
		[&#039;%c&#039;] = &#039;%-I:%M %p %-d %B %-Y %{era}&#039;,  -- date and time: 2:30 pm 1 April 2016&lt;br /&gt;
		[&#039;%x&#039;] = &#039;%-d %B %-Y %{era}&#039;,            -- date:          1 April 2016&lt;br /&gt;
		[&#039;%X&#039;] = &#039;%-I:%M %p&#039;,                    -- time:          2:30 pm&lt;br /&gt;
	}&lt;br /&gt;
	if shortcuts[format] then&lt;br /&gt;
		format = shortcuts[format]&lt;br /&gt;
	end&lt;br /&gt;
	local codes = {&lt;br /&gt;
		a = { field = &#039;dayabbr&#039; },&lt;br /&gt;
		A = { field = &#039;dayname&#039; },&lt;br /&gt;
		b = { field = &#039;monthabbr&#039; },&lt;br /&gt;
		B = { field = &#039;monthname&#039; },&lt;br /&gt;
		u = { fmt = &#039;%d&#039;  , field = &#039;dowiso&#039; },&lt;br /&gt;
		w = { fmt = &#039;%d&#039;  , field = &#039;dow&#039; },&lt;br /&gt;
		d = { fmt = &#039;%02d&#039;, fmt2 = &#039;%d&#039;, field = &#039;day&#039; },&lt;br /&gt;
		m = { fmt = &#039;%02d&#039;, fmt2 = &#039;%d&#039;, field = &#039;month&#039; },&lt;br /&gt;
		Y = { fmt = &#039;%04d&#039;, fmt2 = &#039;%d&#039;, field = &#039;year&#039; },&lt;br /&gt;
		H = { fmt = &#039;%02d&#039;, fmt2 = &#039;%d&#039;, field = &#039;hour&#039; },&lt;br /&gt;
		M = { fmt = &#039;%02d&#039;, fmt2 = &#039;%d&#039;, field = &#039;minute&#039; },&lt;br /&gt;
		S = { fmt = &#039;%02d&#039;, fmt2 = &#039;%d&#039;, field = &#039;second&#039; },&lt;br /&gt;
		j = { fmt = &#039;%03d&#039;, fmt2 = &#039;%d&#039;, field = &#039;dayofyear&#039; },&lt;br /&gt;
		I = { fmt = &#039;%02d&#039;, fmt2 = &#039;%d&#039;, field = &#039;hour&#039;, special = &#039;hour12&#039; },&lt;br /&gt;
		p = { field = &#039;hour&#039;, special = &#039;am&#039; },&lt;br /&gt;
	}&lt;br /&gt;
	options = make_option_table(options, date.options)&lt;br /&gt;
	local amopt = options.am&lt;br /&gt;
	local eraopt = options.era&lt;br /&gt;
	local function replace_code(spaces, modifier, id)&lt;br /&gt;
		local code = codes[id]&lt;br /&gt;
		if code then&lt;br /&gt;
			local fmt = code.fmt&lt;br /&gt;
			if modifier == &#039;-&#039; and code.fmt2 then&lt;br /&gt;
				fmt = code.fmt2&lt;br /&gt;
			end&lt;br /&gt;
			local value = date[code.field]&lt;br /&gt;
			if not value then&lt;br /&gt;
				return nil  -- an undefined field in a partial date&lt;br /&gt;
			end&lt;br /&gt;
			local special = code.special&lt;br /&gt;
			if special then&lt;br /&gt;
				if special == &#039;hour12&#039; then&lt;br /&gt;
					value = value % 12&lt;br /&gt;
					value = value == 0 and 12 or value&lt;br /&gt;
				elseif special == &#039;am&#039; then&lt;br /&gt;
					local ap = ({&lt;br /&gt;
						[&#039;a.m.&#039;] = { &#039;a.m.&#039;, &#039;p.m.&#039; },&lt;br /&gt;
						[&#039;AM&#039;] = { &#039;AM&#039;, &#039;PM&#039; },&lt;br /&gt;
						[&#039;A.M.&#039;] = { &#039;A.M.&#039;, &#039;P.M.&#039; },&lt;br /&gt;
					})[ampm_options[amopt]] or { &#039;am&#039;, &#039;pm&#039; }&lt;br /&gt;
					return (spaces == &#039;&#039; and &#039;&#039; or &#039;&amp;amp;nbsp;&#039;) .. (value &amp;lt; 12 and ap[1] or ap[2])&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			if code.field == &#039;year&#039; then&lt;br /&gt;
				local sign = (era_text[eraopt] or {}).sign&lt;br /&gt;
				if not sign or format:find(&#039;%{era}&#039;, 1, true) then&lt;br /&gt;
					sign = &#039;&#039;&lt;br /&gt;
					if value &amp;lt;= 0 then&lt;br /&gt;
						value = 1 - value&lt;br /&gt;
					end&lt;br /&gt;
				else&lt;br /&gt;
					if value &amp;gt;= 0 then&lt;br /&gt;
						sign = &#039;&#039;&lt;br /&gt;
					else&lt;br /&gt;
						value = -value&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
				return spaces .. sign .. sformat(fmt, value)&lt;br /&gt;
			end&lt;br /&gt;
			return spaces .. (fmt and sformat(fmt, value) or value)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local function replace_property(spaces, id)&lt;br /&gt;
		if id == &#039;era&#039; then&lt;br /&gt;
			-- Special case so can use local era option.&lt;br /&gt;
			local result = get_era_for_year(eraopt, date.year)&lt;br /&gt;
			if result == &#039;&#039; then&lt;br /&gt;
				return &#039;&#039;&lt;br /&gt;
			end&lt;br /&gt;
			return (spaces == &#039;&#039; and &#039;&#039; or &#039;&amp;amp;nbsp;&#039;) .. result&lt;br /&gt;
		end&lt;br /&gt;
		local result = date[id]&lt;br /&gt;
		if type(result) == &#039;string&#039; then&lt;br /&gt;
			return spaces .. result&lt;br /&gt;
		end&lt;br /&gt;
		if type(result) == &#039;number&#039; then&lt;br /&gt;
			return  spaces .. tostring(result)&lt;br /&gt;
		end&lt;br /&gt;
		if type(result) == &#039;boolean&#039; then&lt;br /&gt;
			return  spaces .. (result and &#039;1&#039; or &#039;0&#039;)&lt;br /&gt;
		end&lt;br /&gt;
		-- This occurs if id is an undefined field in a partial date, or is the name of a function.&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	local PERCENT = &#039;\127PERCENT\127&#039;&lt;br /&gt;
	return (format&lt;br /&gt;
		:gsub(&#039;%%%%&#039;, PERCENT)&lt;br /&gt;
		:gsub(&#039;(%s*)%%{(%w+)}&#039;, replace_property)&lt;br /&gt;
		:gsub(&#039;(%s*)%%(%-?)(%a)&#039;, replace_code)&lt;br /&gt;
		:gsub(PERCENT, &#039;%%&#039;)&lt;br /&gt;
	)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function _date_text(date, fmt, options)&lt;br /&gt;
	-- Return a formatted string representing the given date.&lt;br /&gt;
	if not is_date(date) then&lt;br /&gt;
		error(&#039;date:text: need a date (use &amp;quot;date:text()&amp;quot; with a colon)&#039;, 2)&lt;br /&gt;
	end&lt;br /&gt;
	if type(fmt) == &#039;string&#039; and fmt:match(&#039;%S&#039;) then&lt;br /&gt;
		if fmt:find(&#039;%&#039;, 1, true) then&lt;br /&gt;
			return strftime(date, fmt, options)&lt;br /&gt;
		end&lt;br /&gt;
	elseif date.partial then&lt;br /&gt;
		fmt = date.month and &#039;my&#039; or &#039;y&#039;&lt;br /&gt;
	else&lt;br /&gt;
		fmt = &#039;dmy&#039;&lt;br /&gt;
		if date.hastime then&lt;br /&gt;
			fmt = (date.second &amp;gt; 0 and &#039;hms &#039; or &#039;hm &#039;) .. fmt&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local function bad_format()&lt;br /&gt;
		-- For consistency with other format processing, return given format&lt;br /&gt;
		-- (or cleaned format if original was not a string) if invalid.&lt;br /&gt;
		return mw.text.nowiki(fmt)&lt;br /&gt;
	end&lt;br /&gt;
	if date.partial then&lt;br /&gt;
		-- Ignore days in standard formats like &#039;ymd&#039;.&lt;br /&gt;
		if fmt == &#039;ym&#039; or fmt == &#039;ymd&#039; then&lt;br /&gt;
			fmt = date.month and &#039;%Y-%m %{era}&#039; or &#039;%Y %{era}&#039;&lt;br /&gt;
		elseif fmt == &#039;my&#039; or fmt == &#039;dmy&#039; or fmt == &#039;mdy&#039; then&lt;br /&gt;
			fmt = date.month and &#039;%B %-Y %{era}&#039; or &#039;%-Y %{era}&#039;&lt;br /&gt;
		elseif fmt == &#039;y&#039; then&lt;br /&gt;
			fmt = date.month and &#039;%-Y %{era}&#039; or &#039;%-Y %{era}&#039;&lt;br /&gt;
		else&lt;br /&gt;
			return bad_format()&lt;br /&gt;
		end&lt;br /&gt;
		return strftime(date, fmt, options)&lt;br /&gt;
	end&lt;br /&gt;
	local function hm_fmt()&lt;br /&gt;
		local plain = make_option_table(options, date.options).bydefault.am&lt;br /&gt;
		return plain and &#039;%H:%M&#039; or &#039;%-I:%M %p&#039;&lt;br /&gt;
	end&lt;br /&gt;
	local need_time = date.hastime&lt;br /&gt;
	local t = collection()&lt;br /&gt;
	for item in fmt:gmatch(&#039;%S+&#039;) do&lt;br /&gt;
		local f&lt;br /&gt;
		if item == &#039;hm&#039; then&lt;br /&gt;
			f = hm_fmt()&lt;br /&gt;
			need_time = false&lt;br /&gt;
		elseif item == &#039;hms&#039; then&lt;br /&gt;
			f = &#039;%H:%M:%S&#039;&lt;br /&gt;
			need_time = false&lt;br /&gt;
		elseif item == &#039;ymd&#039; then&lt;br /&gt;
			f = &#039;%Y-%m-%d %{era}&#039;&lt;br /&gt;
		elseif item == &#039;mdy&#039; then&lt;br /&gt;
			f = &#039;%B %-d, %-Y %{era}&#039;&lt;br /&gt;
		elseif item == &#039;dmy&#039; then&lt;br /&gt;
			f = &#039;%-d %B %-Y %{era}&#039;&lt;br /&gt;
		else&lt;br /&gt;
			return bad_format()&lt;br /&gt;
		end&lt;br /&gt;
		t:add(f)&lt;br /&gt;
	end&lt;br /&gt;
	fmt = t:join(&#039; &#039;)&lt;br /&gt;
	if need_time then&lt;br /&gt;
		fmt = hm_fmt() .. &#039; &#039; .. fmt&lt;br /&gt;
	end&lt;br /&gt;
	return strftime(date, fmt, options)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local day_info = {&lt;br /&gt;
	-- 0=Sun to 6=Sat&lt;br /&gt;
	[0] = { &#039;Sun&#039;, &#039;Sunday&#039; },&lt;br /&gt;
	{ &#039;Mon&#039;, &#039;Monday&#039; },&lt;br /&gt;
	{ &#039;Tue&#039;, &#039;Tuesday&#039; },&lt;br /&gt;
	{ &#039;Wed&#039;, &#039;Wednesday&#039; },&lt;br /&gt;
	{ &#039;Thu&#039;, &#039;Thursday&#039; },&lt;br /&gt;
	{ &#039;Fri&#039;, &#039;Friday&#039; },&lt;br /&gt;
	{ &#039;Sat&#039;, &#039;Saturday&#039; },&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local month_info = {&lt;br /&gt;
	-- 1=Jan to 12=Dec&lt;br /&gt;
	{ &#039;Jan&#039;, &#039;January&#039; },&lt;br /&gt;
	{ &#039;Feb&#039;, &#039;February&#039; },&lt;br /&gt;
	{ &#039;Mar&#039;, &#039;March&#039; },&lt;br /&gt;
	{ &#039;Apr&#039;, &#039;April&#039; },&lt;br /&gt;
	{ &#039;May&#039;, &#039;May&#039; },&lt;br /&gt;
	{ &#039;Jun&#039;, &#039;June&#039; },&lt;br /&gt;
	{ &#039;Jul&#039;, &#039;July&#039; },&lt;br /&gt;
	{ &#039;Aug&#039;, &#039;August&#039; },&lt;br /&gt;
	{ &#039;Sep&#039;, &#039;September&#039; },&lt;br /&gt;
	{ &#039;Oct&#039;, &#039;October&#039; },&lt;br /&gt;
	{ &#039;Nov&#039;, &#039;November&#039; },&lt;br /&gt;
	{ &#039;Dec&#039;, &#039;December&#039; },&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local function name_to_number(text, translate)&lt;br /&gt;
	if type(text) == &#039;string&#039; then&lt;br /&gt;
		return translate[text:lower()]&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function day_number(text)&lt;br /&gt;
	return name_to_number(text, {&lt;br /&gt;
		sun = 0, sunday = 0,&lt;br /&gt;
		mon = 1, monday = 1,&lt;br /&gt;
		tue = 2, tuesday = 2,&lt;br /&gt;
		wed = 3, wednesday = 3,&lt;br /&gt;
		thu = 4, thursday = 4,&lt;br /&gt;
		fri = 5, friday = 5,&lt;br /&gt;
		sat = 6, saturday = 6,&lt;br /&gt;
	})&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function month_number(text)&lt;br /&gt;
	return name_to_number(text:gsub(&#039;%.&#039;, &#039;&#039;), {&lt;br /&gt;
		jan = 1, january = 1,&lt;br /&gt;
		feb = 2, february = 2,&lt;br /&gt;
		mar = 3, march = 3,&lt;br /&gt;
		apr = 4, april = 4,&lt;br /&gt;
		may = 5,&lt;br /&gt;
		jun = 6, june = 6,&lt;br /&gt;
		jul = 7, july = 7,&lt;br /&gt;
		aug = 8, august = 8,&lt;br /&gt;
		sep = 9, september = 9, sept = 9,&lt;br /&gt;
		oct = 10, october = 10,&lt;br /&gt;
		nov = 11, november = 11,&lt;br /&gt;
		dec = 12, december = 12,&lt;br /&gt;
	})&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function _list_text(list, fmt)&lt;br /&gt;
	-- Return a list of formatted strings from a list of dates.&lt;br /&gt;
	if not type(list) == &#039;table&#039; then&lt;br /&gt;
		error(&#039;date:list:text: need &amp;quot;list:text()&amp;quot; with a colon&#039;, 2)&lt;br /&gt;
	end&lt;br /&gt;
	local result = { join = _list_join }&lt;br /&gt;
	for i, date in ipairs(list) do&lt;br /&gt;
		result[i] = date:text(fmt)&lt;br /&gt;
	end&lt;br /&gt;
	return result&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function _date_list(date, spec)&lt;br /&gt;
	-- Return a possibly empty numbered table of dates meeting the specification.&lt;br /&gt;
	-- Dates in the list are in ascending order (oldest date first).&lt;br /&gt;
	-- The spec should be a string of form &amp;quot;&amp;lt;count&amp;gt; &amp;lt;day&amp;gt; &amp;lt;op&amp;gt;&amp;quot;&lt;br /&gt;
	-- where each item is optional and&lt;br /&gt;
	--   count = number of items wanted in list&lt;br /&gt;
	--   day = abbreviation or name such as Mon or Monday&lt;br /&gt;
	--   op = &amp;gt;, &amp;gt;=, &amp;lt;, &amp;lt;= (default is &amp;gt; meaning after date)&lt;br /&gt;
	-- If no count is given, the list is for the specified days in date&#039;s month.&lt;br /&gt;
	-- The default day is date&#039;s day.&lt;br /&gt;
	-- The spec can also be a positive or negative number:&lt;br /&gt;
	--   -5 is equivalent to &#039;5 &amp;lt;&#039;&lt;br /&gt;
	--   5  is equivalent to &#039;5&#039; which is &#039;5 &amp;gt;&#039;&lt;br /&gt;
	if not is_date(date) then&lt;br /&gt;
		error(&#039;date:list: need a date (use &amp;quot;date:list()&amp;quot; with a colon)&#039;, 2)&lt;br /&gt;
	end&lt;br /&gt;
	local list = { text = _list_text }&lt;br /&gt;
	if date.partial then&lt;br /&gt;
		return list&lt;br /&gt;
	end&lt;br /&gt;
	local count, offset, operation&lt;br /&gt;
	local ops = {&lt;br /&gt;
		[&#039;&amp;gt;=&#039;] = { before = false, include = true  },&lt;br /&gt;
		[&#039;&amp;gt;&#039;]  = { before = false, include = false },&lt;br /&gt;
		[&#039;&amp;lt;=&#039;] = { before = true , include = true  },&lt;br /&gt;
		[&#039;&amp;lt;&#039;]  = { before = true , include = false },&lt;br /&gt;
	}&lt;br /&gt;
	if spec then&lt;br /&gt;
		if type(spec) == &#039;number&#039; then&lt;br /&gt;
			count = floor(spec + 0.5)&lt;br /&gt;
			if count &amp;lt; 0 then&lt;br /&gt;
				count = -count&lt;br /&gt;
				operation = ops[&#039;&amp;lt;&#039;]&lt;br /&gt;
			end&lt;br /&gt;
		elseif type(spec) == &#039;string&#039; then&lt;br /&gt;
			local num, day, op = spec:match(&#039;^%s*(%d*)%s*(%a*)%s*([&amp;lt;&amp;gt;=]*)%s*$&#039;)&lt;br /&gt;
			if not num then&lt;br /&gt;
				return list&lt;br /&gt;
			end&lt;br /&gt;
			if num ~= &#039;&#039; then&lt;br /&gt;
				count = tonumber(num)&lt;br /&gt;
			end&lt;br /&gt;
			if day ~= &#039;&#039; then&lt;br /&gt;
				local dow = day_number(day:gsub(&#039;[sS]$&#039;, &#039;&#039;))  -- accept plural days&lt;br /&gt;
				if not dow then&lt;br /&gt;
					return list&lt;br /&gt;
				end&lt;br /&gt;
				offset = dow - date.dow&lt;br /&gt;
			end&lt;br /&gt;
			operation = ops[op]&lt;br /&gt;
		else&lt;br /&gt;
			return list&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	offset = offset or 0&lt;br /&gt;
	operation = operation or ops[&#039;&amp;gt;&#039;]&lt;br /&gt;
	local datefrom, dayfirst, daylast&lt;br /&gt;
	if operation.before then&lt;br /&gt;
		if offset &amp;gt; 0 or (offset == 0 and not operation.include) then&lt;br /&gt;
			offset = offset - 7&lt;br /&gt;
		end&lt;br /&gt;
		if count then&lt;br /&gt;
			if count &amp;gt; 1 then&lt;br /&gt;
				offset = offset - 7*(count - 1)&lt;br /&gt;
			end&lt;br /&gt;
			datefrom = date + offset&lt;br /&gt;
		else&lt;br /&gt;
			daylast = date.day + offset&lt;br /&gt;
			dayfirst = daylast % 7&lt;br /&gt;
			if dayfirst == 0 then&lt;br /&gt;
				dayfirst = 7&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		if offset &amp;lt; 0 or (offset == 0 and not operation.include) then&lt;br /&gt;
			offset = offset + 7&lt;br /&gt;
		end&lt;br /&gt;
		if count then&lt;br /&gt;
			datefrom = date + offset&lt;br /&gt;
		else&lt;br /&gt;
			dayfirst = date.day + offset&lt;br /&gt;
			daylast = date.monthdays&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if not count then&lt;br /&gt;
		if daylast &amp;lt; dayfirst then&lt;br /&gt;
			return list&lt;br /&gt;
		end&lt;br /&gt;
		count = floor((daylast - dayfirst)/7) + 1&lt;br /&gt;
		datefrom = Date(date, {day = dayfirst})&lt;br /&gt;
	end&lt;br /&gt;
	for i = 1, count do&lt;br /&gt;
		if not datefrom then break end  -- exceeds date limits&lt;br /&gt;
		list[i] = datefrom&lt;br /&gt;
		datefrom = datefrom + 7&lt;br /&gt;
	end&lt;br /&gt;
	return list&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Cache the current date/time (UTC).&lt;br /&gt;
--&lt;br /&gt;
-- Note that os.date() returns an empty object with optimized lazy getters for each field.&lt;br /&gt;
-- Avoid current.min or current.sec in articles! https://phabricator.wikimedia.org/T416616&lt;br /&gt;
--&lt;br /&gt;
-- Beware that while os.date() uses &#039;min&#039; and &#039;sec&#039;, our Date() uses &#039;minute&#039; and &#039;second&#039;.&lt;br /&gt;
local current = os.date(&#039;!*t&#039;)&lt;br /&gt;
&lt;br /&gt;
local function extract_date(newdate, text)&lt;br /&gt;
	-- Parse the date/time in text and return n, o where&lt;br /&gt;
	--   n = table of numbers with date/time fields&lt;br /&gt;
	--   o = table of options for AM/PM or AD/BC or format, if any&lt;br /&gt;
	-- or return nothing if date is known to be invalid.&lt;br /&gt;
	-- Caller determines if the values in n are valid.&lt;br /&gt;
	-- A year must be positive (&#039;1&#039; to &#039;9999&#039;); use &#039;BC&#039; for BC.&lt;br /&gt;
	-- In a y-m-d string, the year must be four digits to avoid ambiguity&lt;br /&gt;
	-- (&#039;0001&#039; to &#039;9999&#039;). The only way to enter year &amp;lt;= 0 is by specifying&lt;br /&gt;
	-- the date as three numeric parameters like ymd Date(-1, 1, 1).&lt;br /&gt;
	-- Dates of form d/m/y, m/d/y, y/m/d are rejected as potentially ambiguous.&lt;br /&gt;
	local date, options = {}, {}&lt;br /&gt;
	if text:sub(-1) == &#039;Z&#039; then&lt;br /&gt;
		-- Extract date/time from a Wikidata timestamp.&lt;br /&gt;
		-- The year can be 1 to 16 digits but this module handles 1 to 4 digits only.&lt;br /&gt;
		-- Examples: &#039;+2016-06-21T14:30:00Z&#039;, &#039;-0000000180-00-00T00:00:00Z&#039;.&lt;br /&gt;
		local sign, y, m, d, H, M, S = text:match(&#039;^([+%-])(%d+)%-(%d%d)%-(%d%d)T(%d%d):(%d%d):(%d%d)Z$&#039;)&lt;br /&gt;
		if sign then&lt;br /&gt;
			y = tonumber(y)&lt;br /&gt;
			if sign == &#039;-&#039; and y &amp;gt; 0 then&lt;br /&gt;
				y = -y&lt;br /&gt;
			end&lt;br /&gt;
			if y &amp;lt;= 0 then&lt;br /&gt;
				options.era = &#039;BCE&#039;&lt;br /&gt;
			end&lt;br /&gt;
			date.year = y&lt;br /&gt;
			m = tonumber(m)&lt;br /&gt;
			d = tonumber(d)&lt;br /&gt;
			H = tonumber(H)&lt;br /&gt;
			M = tonumber(M)&lt;br /&gt;
			S = tonumber(S)&lt;br /&gt;
			if m == 0 then&lt;br /&gt;
				newdate.partial = true&lt;br /&gt;
				return date, options&lt;br /&gt;
			end&lt;br /&gt;
			date.month = m&lt;br /&gt;
			if d == 0 then&lt;br /&gt;
				newdate.partial = true&lt;br /&gt;
				return date, options&lt;br /&gt;
			end&lt;br /&gt;
			date.day = d&lt;br /&gt;
			if H &amp;gt; 0 or M &amp;gt; 0 or S &amp;gt; 0 then&lt;br /&gt;
				date.hour = H&lt;br /&gt;
				date.minute = M&lt;br /&gt;
				date.second = S&lt;br /&gt;
			end&lt;br /&gt;
			return date, options&lt;br /&gt;
		end&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
	local function extract_ymd(item)&lt;br /&gt;
		-- Called when no day or month has been set.&lt;br /&gt;
		local y, m, d = item:match(&#039;^(%d%d%d%d)%-(%w+)%-(%d%d?)$&#039;)&lt;br /&gt;
		if y then&lt;br /&gt;
			if date.year then&lt;br /&gt;
				return&lt;br /&gt;
			end&lt;br /&gt;
			if m:match(&#039;^%d%d?$&#039;) then&lt;br /&gt;
				m = tonumber(m)&lt;br /&gt;
			else&lt;br /&gt;
				m = month_number(m)&lt;br /&gt;
			end&lt;br /&gt;
			if m then&lt;br /&gt;
				date.year = tonumber(y)&lt;br /&gt;
				date.month = m&lt;br /&gt;
				date.day = tonumber(d)&lt;br /&gt;
				return true&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local function extract_day_or_year(item)&lt;br /&gt;
		-- Called when a day would be valid, or&lt;br /&gt;
		-- when a year would be valid if no year has been set and partial is set.&lt;br /&gt;
		local number, suffix = item:match(&#039;^(%d%d?%d?%d?)(.*)$&#039;)&lt;br /&gt;
		if number then&lt;br /&gt;
			local n = tonumber(number)&lt;br /&gt;
			if #number &amp;lt;= 2 and n &amp;lt;= 31 then&lt;br /&gt;
				suffix = suffix:lower()&lt;br /&gt;
				if suffix == &#039;&#039; or suffix == &#039;st&#039; or suffix == &#039;nd&#039; or suffix == &#039;rd&#039; or suffix == &#039;th&#039; then&lt;br /&gt;
					date.day = n&lt;br /&gt;
					return true&lt;br /&gt;
				end&lt;br /&gt;
			elseif suffix == &#039;&#039; and newdate.partial and not date.year then&lt;br /&gt;
				date.year = n&lt;br /&gt;
				return true&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local function extract_month(item)&lt;br /&gt;
		-- A month must be given as a name or abbreviation; a number could be ambiguous.&lt;br /&gt;
		local m = month_number(item)&lt;br /&gt;
		if m then&lt;br /&gt;
			date.month = m&lt;br /&gt;
			return true&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local function extract_time(item)&lt;br /&gt;
		local h, m, s = item:match(&#039;^(%d%d?):(%d%d)(:?%d*)$&#039;)&lt;br /&gt;
		if date.hour or not h then&lt;br /&gt;
			return&lt;br /&gt;
		end&lt;br /&gt;
		if s ~= &#039;&#039; then&lt;br /&gt;
			s = s:match(&#039;^:(%d%d)$&#039;)&lt;br /&gt;
			if not s then&lt;br /&gt;
				return&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		date.hour = tonumber(h)&lt;br /&gt;
		date.minute = tonumber(m)&lt;br /&gt;
		date.second = tonumber(s)  -- nil if empty string&lt;br /&gt;
		return true&lt;br /&gt;
	end&lt;br /&gt;
	local item_count = 0&lt;br /&gt;
	local index_time&lt;br /&gt;
	local function set_ampm(item)&lt;br /&gt;
		local H = date.hour&lt;br /&gt;
		if H and not options.am and index_time + 1 == item_count then&lt;br /&gt;
			options.am = ampm_options[item]  -- caller checked this is not nil&lt;br /&gt;
			if item:match(&#039;^[Aa]&#039;) then&lt;br /&gt;
				if not (1 &amp;lt;= H and H &amp;lt;= 12) then&lt;br /&gt;
					return&lt;br /&gt;
				end&lt;br /&gt;
				if H == 12 then&lt;br /&gt;
					date.hour = 0&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				if not (1 &amp;lt;= H and H &amp;lt;= 23) then&lt;br /&gt;
					return&lt;br /&gt;
				end&lt;br /&gt;
				if H &amp;lt;= 11 then&lt;br /&gt;
					date.hour = H + 12&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			return true&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	for item in text:gsub(&#039;,&#039;, &#039; &#039;):gsub(&#039;&amp;amp;nbsp;&#039;, &#039; &#039;):gmatch(&#039;%S+&#039;) do&lt;br /&gt;
		item_count = item_count + 1&lt;br /&gt;
		if era_text[item] then&lt;br /&gt;
			-- Era is accepted in peculiar places.&lt;br /&gt;
			if options.era then&lt;br /&gt;
				return&lt;br /&gt;
			end&lt;br /&gt;
			options.era = item&lt;br /&gt;
		elseif ampm_options[item] then&lt;br /&gt;
			if not set_ampm(item) then&lt;br /&gt;
				return&lt;br /&gt;
			end&lt;br /&gt;
		elseif item:find(&#039;:&#039;, 1, true) then&lt;br /&gt;
			if not extract_time(item) then&lt;br /&gt;
				return&lt;br /&gt;
			end&lt;br /&gt;
			index_time = item_count&lt;br /&gt;
		elseif date.day and date.month then&lt;br /&gt;
			if date.year then&lt;br /&gt;
				return  -- should be nothing more so item is invalid&lt;br /&gt;
			end&lt;br /&gt;
			if not item:match(&#039;^(%d%d?%d?%d?)$&#039;) then&lt;br /&gt;
				return&lt;br /&gt;
			end&lt;br /&gt;
			date.year = tonumber(item)&lt;br /&gt;
		elseif date.day then&lt;br /&gt;
			if not extract_month(item) then&lt;br /&gt;
				return&lt;br /&gt;
			end&lt;br /&gt;
		elseif date.month then&lt;br /&gt;
			if not extract_day_or_year(item) then&lt;br /&gt;
				return&lt;br /&gt;
			end&lt;br /&gt;
		elseif extract_month(item) then&lt;br /&gt;
			options.format = &#039;mdy&#039;&lt;br /&gt;
		elseif extract_ymd(item) then&lt;br /&gt;
			options.format = &#039;ymd&#039;&lt;br /&gt;
		elseif extract_day_or_year(item) then&lt;br /&gt;
			if date.day then&lt;br /&gt;
				options.format = &#039;dmy&#039;&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			return&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if not date.year or date.year == 0 then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
	local era = era_text[options.era]&lt;br /&gt;
	if era and era.isbc then&lt;br /&gt;
		date.year = 1 - date.year&lt;br /&gt;
	end&lt;br /&gt;
	return date, options&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function autofill(date1, date2)&lt;br /&gt;
	-- Fill any missing month or day in each date using the&lt;br /&gt;
	-- corresponding component from the other date, if present,&lt;br /&gt;
	-- or with 1 if both dates are missing the month or day.&lt;br /&gt;
	-- This gives a good result for calculating the difference&lt;br /&gt;
	-- between two partial dates when no range is wanted.&lt;br /&gt;
	-- Return filled date1, date2 (two full dates).&lt;br /&gt;
	local function filled(a, b)&lt;br /&gt;
		-- Return date a filled, if necessary, with month and/or day from date b.&lt;br /&gt;
		-- The filled day is truncated to fit the number of days in the month.&lt;br /&gt;
		local fillmonth, fillday&lt;br /&gt;
		if not a.month then&lt;br /&gt;
			fillmonth = b.month or 1&lt;br /&gt;
		end&lt;br /&gt;
		if not a.day then&lt;br /&gt;
			fillday = b.day or 1&lt;br /&gt;
		end&lt;br /&gt;
		if fillmonth or fillday then  -- need to create a new date&lt;br /&gt;
			a = Date(a, {&lt;br /&gt;
				month = fillmonth,&lt;br /&gt;
				day = math.min(fillday or a.day, days_in_month(a.year, fillmonth or a.month, a.calendar))&lt;br /&gt;
			})&lt;br /&gt;
		end&lt;br /&gt;
		return a&lt;br /&gt;
	end&lt;br /&gt;
	return filled(date1, date2), filled(date2, date1)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function date_add_sub(lhs, rhs, is_sub)&lt;br /&gt;
	-- Return a new date from calculating (lhs + rhs) or (lhs - rhs),&lt;br /&gt;
	-- or return nothing if invalid.&lt;br /&gt;
	-- The result is nil if the calculated date exceeds allowable limits.&lt;br /&gt;
	-- Caller ensures that lhs is a date; its properties are copied for the new date.&lt;br /&gt;
	if lhs.partial then&lt;br /&gt;
		-- Adding to a partial is not supported.&lt;br /&gt;
		-- Can subtract a date or partial from a partial, but this is not called for that.&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
	local function is_prefix(text, word, minlen)&lt;br /&gt;
		local n = #text&lt;br /&gt;
		return (minlen or 1) &amp;lt;= n and n &amp;lt;= #word and text == word:sub(1, n)&lt;br /&gt;
	end&lt;br /&gt;
	local function do_days(n)&lt;br /&gt;
		local forcetime, jd&lt;br /&gt;
		if floor(n) == n then&lt;br /&gt;
			jd = lhs.jd&lt;br /&gt;
		else&lt;br /&gt;
			forcetime = not lhs.hastime&lt;br /&gt;
			jd = lhs.jdz&lt;br /&gt;
		end&lt;br /&gt;
		jd = jd + (is_sub and -n or n)&lt;br /&gt;
		if forcetime then&lt;br /&gt;
			jd = tostring(jd)&lt;br /&gt;
			if not jd:find(&#039;.&#039;, 1, true) then&lt;br /&gt;
				jd = jd .. &#039;.0&#039;&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return Date(lhs, &#039;juliandate&#039;, jd)&lt;br /&gt;
	end&lt;br /&gt;
	if type(rhs) == &#039;number&#039; then&lt;br /&gt;
		-- Add/subtract days, including fractional days.&lt;br /&gt;
		return do_days(rhs)&lt;br /&gt;
	end&lt;br /&gt;
	if type(rhs) == &#039;string&#039; then&lt;br /&gt;
		-- rhs is a single component like &#039;26m&#039; or &#039;26 months&#039; (with optional sign).&lt;br /&gt;
		-- Fractions like &#039;3.25d&#039; are accepted for the units which are handled as days.&lt;br /&gt;
		local sign, numstr, id = rhs:match(&#039;^%s*([+-]?)([%d%.]+)%s*(%a+)$&#039;)&lt;br /&gt;
		if sign then&lt;br /&gt;
			if sign == &#039;-&#039; then&lt;br /&gt;
				is_sub = not (is_sub and true or false)&lt;br /&gt;
			end&lt;br /&gt;
			local y, m, days&lt;br /&gt;
			local num = tonumber(numstr)&lt;br /&gt;
			if not num then&lt;br /&gt;
				return&lt;br /&gt;
			end&lt;br /&gt;
			id = id:lower()&lt;br /&gt;
			if is_prefix(id, &#039;years&#039;) then&lt;br /&gt;
				y = num&lt;br /&gt;
				m = 0&lt;br /&gt;
			elseif is_prefix(id, &#039;months&#039;) then&lt;br /&gt;
				y = floor(num / 12)&lt;br /&gt;
				m = num % 12&lt;br /&gt;
			elseif is_prefix(id, &#039;weeks&#039;) then&lt;br /&gt;
				days = num * 7&lt;br /&gt;
			elseif is_prefix(id, &#039;days&#039;) then&lt;br /&gt;
				days = num&lt;br /&gt;
			elseif is_prefix(id, &#039;hours&#039;) then&lt;br /&gt;
				days = num / 24&lt;br /&gt;
			elseif is_prefix(id, &#039;minutes&#039;, 3) then&lt;br /&gt;
				days = num / (24 * 60)&lt;br /&gt;
			elseif is_prefix(id, &#039;seconds&#039;) then&lt;br /&gt;
				days = num / (24 * 3600)&lt;br /&gt;
			else&lt;br /&gt;
				return&lt;br /&gt;
			end&lt;br /&gt;
			if days then&lt;br /&gt;
				return do_days(days)&lt;br /&gt;
			end&lt;br /&gt;
			if numstr:find(&#039;.&#039;, 1, true) then&lt;br /&gt;
				return&lt;br /&gt;
			end&lt;br /&gt;
			if is_sub then&lt;br /&gt;
				y = -y&lt;br /&gt;
				m = -m&lt;br /&gt;
			end&lt;br /&gt;
			assert(-11 &amp;lt;= m and m &amp;lt;= 11)&lt;br /&gt;
			y = lhs.year + y&lt;br /&gt;
			m = lhs.month + m&lt;br /&gt;
			if m &amp;gt; 12 then&lt;br /&gt;
				y = y + 1&lt;br /&gt;
				m = m - 12&lt;br /&gt;
			elseif m &amp;lt; 1 then&lt;br /&gt;
				y = y - 1&lt;br /&gt;
				m = m + 12&lt;br /&gt;
			end&lt;br /&gt;
			local d = math.min(lhs.day, days_in_month(y, m, lhs.calendar))&lt;br /&gt;
			return Date(lhs, y, m, d)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if is_diff(rhs) then&lt;br /&gt;
		local days = rhs.age_days&lt;br /&gt;
		if (is_sub or false) ~= (rhs.isnegative or false) then&lt;br /&gt;
			days = -days&lt;br /&gt;
		end&lt;br /&gt;
		return lhs + days&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local full_date_only = {&lt;br /&gt;
	dayabbr = true,&lt;br /&gt;
	dayname = true,&lt;br /&gt;
	dow = true,&lt;br /&gt;
	dayofweek = true,&lt;br /&gt;
	dowiso = true,&lt;br /&gt;
	dayofweekiso = true,&lt;br /&gt;
	dayofyear = true,&lt;br /&gt;
	gsd = true,&lt;br /&gt;
	juliandate = true,&lt;br /&gt;
	jd = true,&lt;br /&gt;
	jdz = true,&lt;br /&gt;
	jdnoon = true,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
-- Metatable for a date&#039;s calculated fields.&lt;br /&gt;
local datemt = {&lt;br /&gt;
	__index = function (self, key)&lt;br /&gt;
		if rawget(self, &#039;partial&#039;) then&lt;br /&gt;
			if full_date_only[key] then return end&lt;br /&gt;
			if key == &#039;monthabbr&#039; or key == &#039;monthdays&#039; or key == &#039;monthname&#039; then&lt;br /&gt;
				if not self.month then return end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		local value&lt;br /&gt;
		if key == &#039;dayabbr&#039; then&lt;br /&gt;
			value = day_info[self.dow][1]&lt;br /&gt;
		elseif key == &#039;dayname&#039; then&lt;br /&gt;
			value = day_info[self.dow][2]&lt;br /&gt;
		elseif key == &#039;dow&#039; then&lt;br /&gt;
			value = (self.jdnoon + 1) % 7  -- day-of-week 0=Sun to 6=Sat&lt;br /&gt;
		elseif key == &#039;dayofweek&#039; then&lt;br /&gt;
			value = self.dow&lt;br /&gt;
		elseif key == &#039;dowiso&#039; then&lt;br /&gt;
			value = (self.jdnoon % 7) + 1  -- ISO day-of-week 1=Mon to 7=Sun&lt;br /&gt;
		elseif key == &#039;dayofweekiso&#039; then&lt;br /&gt;
			value = self.dowiso&lt;br /&gt;
		elseif key == &#039;dayofyear&#039; then&lt;br /&gt;
			local first = Date(self.year, 1, 1, self.calendar).jdnoon&lt;br /&gt;
			value = self.jdnoon - first + 1  -- day-of-year 1 to 366&lt;br /&gt;
		elseif key == &#039;era&#039; then&lt;br /&gt;
			-- Era text (never a negative sign) from year and options.&lt;br /&gt;
			value = get_era_for_year(self.options.era, self.year)&lt;br /&gt;
		elseif key == &#039;format&#039; then&lt;br /&gt;
			value = self.options.format or &#039;dmy&#039;&lt;br /&gt;
		elseif key == &#039;gsd&#039; then&lt;br /&gt;
			-- GSD = 1 from 00:00:00 to 23:59:59 on 1 January 1 AD Gregorian calendar,&lt;br /&gt;
			-- which is from jd 1721425.5 to 1721426.49999.&lt;br /&gt;
			value = floor(self.jd - 1721424.5)&lt;br /&gt;
		elseif key == &#039;juliandate&#039; or key == &#039;jd&#039; or key == &#039;jdz&#039; then&lt;br /&gt;
			local jd, jdz = julian_date(self)&lt;br /&gt;
			rawset(self, &#039;juliandate&#039;, jd)&lt;br /&gt;
			rawset(self, &#039;jd&#039;, jd)&lt;br /&gt;
			rawset(self, &#039;jdz&#039;, jdz)&lt;br /&gt;
			return key == &#039;jdz&#039; and jdz or jd&lt;br /&gt;
		elseif key == &#039;jdnoon&#039; then&lt;br /&gt;
			-- Julian date at noon (an integer) on the calendar day when jd occurs.&lt;br /&gt;
			value = floor(self.jd + 0.5)&lt;br /&gt;
		elseif key == &#039;isleapyear&#039; then&lt;br /&gt;
			value = is_leap_year(self.year, self.calendar)&lt;br /&gt;
		elseif key == &#039;monthabbr&#039; then&lt;br /&gt;
			value = month_info[self.month][1]&lt;br /&gt;
		elseif key == &#039;monthdays&#039; then&lt;br /&gt;
			value = days_in_month(self.year, self.month, self.calendar)&lt;br /&gt;
		elseif key == &#039;monthname&#039; then&lt;br /&gt;
			value = month_info[self.month][2]&lt;br /&gt;
		end&lt;br /&gt;
		if value ~= nil then&lt;br /&gt;
			rawset(self, key, value)&lt;br /&gt;
			return value&lt;br /&gt;
		end&lt;br /&gt;
	end,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
-- Date operators.&lt;br /&gt;
local function mt_date_add(lhs, rhs)&lt;br /&gt;
	if not is_date(lhs) then&lt;br /&gt;
		lhs, rhs = rhs, lhs  -- put date on left (it must be a date for this to have been called)&lt;br /&gt;
	end&lt;br /&gt;
	return date_add_sub(lhs, rhs)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function mt_date_sub(lhs, rhs)&lt;br /&gt;
	if is_date(lhs) then&lt;br /&gt;
		if is_date(rhs) then&lt;br /&gt;
			return DateDiff(lhs, rhs)&lt;br /&gt;
		end&lt;br /&gt;
		return date_add_sub(lhs, rhs, true)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function mt_date_concat(lhs, rhs)&lt;br /&gt;
	return tostring(lhs) .. tostring(rhs)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function mt_date_tostring(self)&lt;br /&gt;
	return self:text()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function mt_date_eq(lhs, rhs)&lt;br /&gt;
	-- Return true if dates identify same date/time where, for example,&lt;br /&gt;
	-- Date(-4712, 1, 1, &#039;Julian&#039;) == Date(-4713, 11, 24, &#039;Gregorian&#039;) is true.&lt;br /&gt;
	-- This is called only if lhs and rhs have the same type and the same metamethod.&lt;br /&gt;
	if lhs.partial or rhs.partial then&lt;br /&gt;
		-- One date is partial; the other is a partial or a full date.&lt;br /&gt;
		-- The months may both be nil, but must be the same.&lt;br /&gt;
		return lhs.year == rhs.year and lhs.month == rhs.month and lhs.calendar == rhs.calendar&lt;br /&gt;
	end&lt;br /&gt;
	return lhs.jdz == rhs.jdz&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function mt_date_lt(lhs, rhs)&lt;br /&gt;
	-- Return true if lhs &amp;lt; rhs, for example,&lt;br /&gt;
	-- Date(&#039;1 Jan 2016&#039;) &amp;lt; Date(&#039;06:00 1 Jan 2016&#039;) is true.&lt;br /&gt;
	-- This is called only if lhs and rhs have the same type and the same metamethod.&lt;br /&gt;
	if lhs.partial or rhs.partial then&lt;br /&gt;
		-- One date is partial; the other is a partial or a full date.&lt;br /&gt;
		if lhs.calendar ~= rhs.calendar then&lt;br /&gt;
			return lhs.calendar == &#039;Julian&#039;&lt;br /&gt;
		end&lt;br /&gt;
		if lhs.partial then&lt;br /&gt;
			lhs = lhs.partial.first&lt;br /&gt;
		end&lt;br /&gt;
		if rhs.partial then&lt;br /&gt;
			rhs = rhs.partial.first&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return lhs.jdz &amp;lt; rhs.jdz&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[ Examples of syntax to construct a date:&lt;br /&gt;
Date(y, m, d, &#039;julian&#039;)             default calendar is &#039;gregorian&#039;&lt;br /&gt;
Date(y, m, d, H, M, S, &#039;julian&#039;)&lt;br /&gt;
Date(&#039;juliandate&#039;, jd, &#039;julian&#039;)    if jd contains &amp;quot;.&amp;quot; text output includes H:M:S&lt;br /&gt;
Date(&#039;currentdate&#039;)&lt;br /&gt;
Date(&#039;currentdatetime&#039;)&lt;br /&gt;
Date(&#039;1 April 1995&#039;, &#039;julian&#039;)      parse date from text&lt;br /&gt;
Date(&#039;1 April 1995 AD&#039;, &#039;julian&#039;)   using an era sets a flag to do the same for output&lt;br /&gt;
Date(&#039;04:30:59 1 April 1995&#039;, &#039;julian&#039;)&lt;br /&gt;
Date(date)                          copy of an existing date&lt;br /&gt;
Date(date, t)                       same, updated with y,m,d,H,M,S fields from table t&lt;br /&gt;
Date(t)                       		date with y,m,d,H,M,S fields from table t&lt;br /&gt;
]]&lt;br /&gt;
function Date(...)  -- for forward declaration above&lt;br /&gt;
	-- Return a table holding a date assuming a uniform calendar always applies&lt;br /&gt;
	-- (proleptic Gregorian calendar or proleptic Julian calendar), or&lt;br /&gt;
	-- return nothing if date is invalid.&lt;br /&gt;
	-- A partial date has a valid year, however its month may be nil, and&lt;br /&gt;
	-- its day and time fields are nil.&lt;br /&gt;
	-- Field partial is set to false (if a full date) or a table (if a partial date).&lt;br /&gt;
	local calendars = { julian = &#039;Julian&#039;, gregorian = &#039;Gregorian&#039; }&lt;br /&gt;
	local newdate = {&lt;br /&gt;
		_id = uniq,&lt;br /&gt;
		calendar = &#039;Gregorian&#039;,  -- default is Gregorian calendar&lt;br /&gt;
		hastime = false,  -- true if input sets a time&lt;br /&gt;
		hour = 0,  -- always set hour/minute/second so don&#039;t have to handle nil&lt;br /&gt;
		minute = 0,&lt;br /&gt;
		second = 0,&lt;br /&gt;
		options = {},&lt;br /&gt;
		list = _date_list,&lt;br /&gt;
		subtract = function (self, rhs, options)&lt;br /&gt;
			return DateDiff(self, rhs, options)&lt;br /&gt;
		end,&lt;br /&gt;
		text = _date_text,&lt;br /&gt;
	}&lt;br /&gt;
	local argtype, datetext, is_copy, jd_number, tnums&lt;br /&gt;
	local numindex = 0&lt;br /&gt;
	local numfields = { &#039;year&#039;, &#039;month&#039;, &#039;day&#039;, &#039;hour&#039;, &#039;minute&#039;, &#039;second&#039; }&lt;br /&gt;
	local numbers = {}&lt;br /&gt;
	for _, v in ipairs({...}) do&lt;br /&gt;
		v = strip_to_nil(v)&lt;br /&gt;
		local vlower = type(v) == &#039;string&#039; and v:lower() or nil&lt;br /&gt;
		if v == nil then&lt;br /&gt;
			-- Ignore empty arguments after stripping so modules can directly pass template parameters.&lt;br /&gt;
		elseif calendars[vlower] then&lt;br /&gt;
			newdate.calendar = calendars[vlower]&lt;br /&gt;
		elseif vlower == &#039;partial&#039; then&lt;br /&gt;
			newdate.partial = true&lt;br /&gt;
		elseif vlower == &#039;fix&#039; then&lt;br /&gt;
			newdate.want_fix = true&lt;br /&gt;
		elseif is_date(v) then&lt;br /&gt;
			-- Copy existing date (items can be overridden by other arguments).&lt;br /&gt;
			if is_copy or tnums then&lt;br /&gt;
				return&lt;br /&gt;
			end&lt;br /&gt;
			is_copy = true&lt;br /&gt;
			newdate.calendar = v.calendar&lt;br /&gt;
			newdate.partial = v.partial&lt;br /&gt;
			newdate.hastime = v.hastime&lt;br /&gt;
			newdate.options = v.options&lt;br /&gt;
			newdate.year = v.year&lt;br /&gt;
			newdate.month = v.month&lt;br /&gt;
			newdate.day = v.day&lt;br /&gt;
			newdate.hour = v.hour&lt;br /&gt;
			newdate.minute = v.minute&lt;br /&gt;
			newdate.second = v.second&lt;br /&gt;
		elseif type(v) == &#039;table&#039; then&lt;br /&gt;
			if tnums then&lt;br /&gt;
				return&lt;br /&gt;
			end&lt;br /&gt;
			tnums = {}&lt;br /&gt;
			local tfields = { year=1, month=1, day=1, hour=2, minute=2, second=2 }&lt;br /&gt;
			for tk, tv in pairs(v) do&lt;br /&gt;
				if tfields[tk] then&lt;br /&gt;
					tnums[tk] = tonumber(tv)&lt;br /&gt;
				end&lt;br /&gt;
				if tfields[tk] == 2 then&lt;br /&gt;
					newdate.hastime = true&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			local num = tonumber(v)&lt;br /&gt;
			if not num and argtype == &#039;setdate&#039; and numindex == 1 then&lt;br /&gt;
				num = month_number(v)&lt;br /&gt;
			end&lt;br /&gt;
			if num then&lt;br /&gt;
				if not argtype then&lt;br /&gt;
					argtype = &#039;setdate&#039;&lt;br /&gt;
				end&lt;br /&gt;
				if argtype == &#039;setdate&#039; and numindex &amp;lt; 6 then&lt;br /&gt;
					numindex = numindex + 1&lt;br /&gt;
					numbers[numfields[numindex]] = num&lt;br /&gt;
				elseif argtype == &#039;juliandate&#039; and not jd_number then&lt;br /&gt;
					jd_number = num&lt;br /&gt;
					if type(v) == &#039;string&#039; then&lt;br /&gt;
						if v:find(&#039;.&#039;, 1, true) then&lt;br /&gt;
							newdate.hastime = true&lt;br /&gt;
						end&lt;br /&gt;
					elseif num ~= floor(num) then&lt;br /&gt;
						-- The given value was a number. The time will be used&lt;br /&gt;
						-- if the fractional part is nonzero.&lt;br /&gt;
						newdate.hastime = true&lt;br /&gt;
					end&lt;br /&gt;
				else&lt;br /&gt;
					return&lt;br /&gt;
				end&lt;br /&gt;
			elseif argtype then&lt;br /&gt;
				return&lt;br /&gt;
			elseif type(v) == &#039;string&#039; then&lt;br /&gt;
				if v == &#039;currentdate&#039; or v == &#039;currentdatetime&#039; or v == &#039;juliandate&#039; then&lt;br /&gt;
					argtype = v&lt;br /&gt;
				else&lt;br /&gt;
					argtype = &#039;datetext&#039;&lt;br /&gt;
					datetext = v&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				return&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if argtype == &#039;datetext&#039; then&lt;br /&gt;
		if tnums or not set_date_from_numbers(newdate, extract_date(newdate, datetext)) then&lt;br /&gt;
			return&lt;br /&gt;
		end&lt;br /&gt;
	elseif argtype == &#039;juliandate&#039; then&lt;br /&gt;
		newdate.partial = nil&lt;br /&gt;
		newdate.jd = jd_number&lt;br /&gt;
		if not set_date_from_jd(newdate) then&lt;br /&gt;
			return&lt;br /&gt;
		end&lt;br /&gt;
	elseif argtype == &#039;currentdate&#039; or argtype == &#039;currentdatetime&#039; then&lt;br /&gt;
		newdate.partial = nil&lt;br /&gt;
		newdate.year = current.year&lt;br /&gt;
		newdate.month = current.month&lt;br /&gt;
		newdate.day = current.day&lt;br /&gt;
		if argtype == &#039;currentdatetime&#039; then&lt;br /&gt;
			newdate.hour = current.hour&lt;br /&gt;
			newdate.minute = current.min&lt;br /&gt;
			newdate.second = current.sec&lt;br /&gt;
			newdate.hastime = true&lt;br /&gt;
		end&lt;br /&gt;
		newdate.calendar = &#039;Gregorian&#039;  -- ignore any given calendar name&lt;br /&gt;
	elseif argtype == &#039;setdate&#039; then&lt;br /&gt;
		if tnums or not set_date_from_numbers(newdate, numbers) then&lt;br /&gt;
			return&lt;br /&gt;
		end&lt;br /&gt;
	elseif not (is_copy or tnums) then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
	if tnums then&lt;br /&gt;
		newdate.jd = nil  -- force recalculation in case jd was set before changes from tnums&lt;br /&gt;
		if not set_date_from_numbers(newdate, tnums) then&lt;br /&gt;
			return&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if newdate.partial then&lt;br /&gt;
		local year = newdate.year&lt;br /&gt;
		local month = newdate.month&lt;br /&gt;
		local first = Date(year, month or 1, 1, newdate.calendar)&lt;br /&gt;
		month = month or 12&lt;br /&gt;
		local last = Date(year, month, days_in_month(year, month), newdate.calendar)&lt;br /&gt;
		newdate.partial = { first = first, last = last }&lt;br /&gt;
	else&lt;br /&gt;
		newdate.partial = false  -- avoid index lookup&lt;br /&gt;
	end&lt;br /&gt;
	setmetatable(newdate, datemt)&lt;br /&gt;
	local readonly = {}&lt;br /&gt;
	local mt = {&lt;br /&gt;
		__index = newdate,&lt;br /&gt;
		__newindex = function(t, k, v) error(&#039;date.&#039; .. tostring(k) .. &#039; is read-only&#039;, 2) end,&lt;br /&gt;
		__add = mt_date_add,&lt;br /&gt;
		__sub = mt_date_sub,&lt;br /&gt;
		__concat = mt_date_concat,&lt;br /&gt;
		__tostring = mt_date_tostring,&lt;br /&gt;
		__eq = mt_date_eq,&lt;br /&gt;
		__lt = mt_date_lt,&lt;br /&gt;
	}&lt;br /&gt;
	return setmetatable(readonly, mt)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function _diff_age(diff, code, options)&lt;br /&gt;
	-- Return a tuple of integer values from diff as specified by code, except that&lt;br /&gt;
	-- each integer may be a list of two integers for a diff with a partial date, or&lt;br /&gt;
	-- return nil if the code is not supported.&lt;br /&gt;
	-- If want round, the least significant unit is rounded to nearest whole unit.&lt;br /&gt;
	-- For a duration, an extra day is added.&lt;br /&gt;
	local wantround, wantduration, wantrange&lt;br /&gt;
	if type(options) == &#039;table&#039; then&lt;br /&gt;
		wantround = options.round&lt;br /&gt;
		wantduration = options.duration&lt;br /&gt;
		wantrange = options.range&lt;br /&gt;
	else&lt;br /&gt;
		wantround = options&lt;br /&gt;
	end&lt;br /&gt;
	if not is_diff(diff) then&lt;br /&gt;
		local f = wantduration and &#039;duration&#039; or &#039;age&#039;&lt;br /&gt;
		error(f .. &#039;: need a date difference (use &amp;quot;diff:&#039; .. f .. &#039;()&amp;quot; with a colon)&#039;, 2)&lt;br /&gt;
	end&lt;br /&gt;
	if diff.partial then&lt;br /&gt;
		-- Ignore wantround, wantduration.&lt;br /&gt;
		local function choose(v)&lt;br /&gt;
			if type(v) == &#039;table&#039; then&lt;br /&gt;
				if not wantrange or v[1] == v[2] then&lt;br /&gt;
					-- Example: Date(&#039;partial&#039;, 2005) - Date(&#039;partial&#039;, 2001) gives&lt;br /&gt;
					-- diff.years = { 3, 4 } to show the range of possible results.&lt;br /&gt;
					-- If do not want a range, choose the second value as more expected.&lt;br /&gt;
					return v[2]&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			return v&lt;br /&gt;
		end&lt;br /&gt;
		if code == &#039;ym&#039; or code == &#039;ymd&#039; then&lt;br /&gt;
			if not wantrange and diff.iszero then&lt;br /&gt;
				-- This avoids an unexpected result such as&lt;br /&gt;
				-- Date(&#039;partial&#039;, 2001) - Date(&#039;partial&#039;, 2001)&lt;br /&gt;
				-- giving diff = { years = 0, months = { 0, 11 } }&lt;br /&gt;
				-- which would be reported as 0 years and 11 months.&lt;br /&gt;
				return 0, 0&lt;br /&gt;
			end&lt;br /&gt;
			return choose(diff.partial.years), choose(diff.partial.months)&lt;br /&gt;
		end&lt;br /&gt;
		if code == &#039;y&#039; then&lt;br /&gt;
			return choose(diff.partial.years)&lt;br /&gt;
		end&lt;br /&gt;
		if code == &#039;m&#039; or code == &#039;w&#039; or code == &#039;d&#039; then&lt;br /&gt;
			return choose({ diff.partial.mindiff:age(code), diff.partial.maxdiff:age(code) })&lt;br /&gt;
		end&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	local extra_days = wantduration and 1 or 0&lt;br /&gt;
	if code == &#039;wd&#039; or code == &#039;w&#039; or code == &#039;d&#039; then&lt;br /&gt;
		local offset = wantround and 0.5 or 0&lt;br /&gt;
		local days = diff.age_days + extra_days&lt;br /&gt;
		if code == &#039;wd&#039; or code == &#039;d&#039; then&lt;br /&gt;
			days = floor(days + offset)&lt;br /&gt;
			if code == &#039;d&#039; then&lt;br /&gt;
				return days&lt;br /&gt;
			end&lt;br /&gt;
			return floor(days/7), days % 7&lt;br /&gt;
		end&lt;br /&gt;
		return floor(days/7 + offset)&lt;br /&gt;
	end&lt;br /&gt;
	local H, M, S = diff.hours, diff.minutes, diff.seconds&lt;br /&gt;
	if code == &#039;dh&#039; or code == &#039;dhm&#039; or code == &#039;dhms&#039; or code == &#039;h&#039; or code == &#039;hm&#039; or code == &#039;hms&#039; or code == &#039;M&#039; or code == &#039;s&#039; then&lt;br /&gt;
		local days = floor(diff.age_days + extra_days)&lt;br /&gt;
		local inc_hour&lt;br /&gt;
		if wantround then&lt;br /&gt;
			if code == &#039;dh&#039; or code == &#039;h&#039; then&lt;br /&gt;
				if M &amp;gt;= 30 then&lt;br /&gt;
					inc_hour = true&lt;br /&gt;
				end&lt;br /&gt;
			elseif code == &#039;dhm&#039; or code == &#039;hm&#039; then&lt;br /&gt;
				if S &amp;gt;= 30 then&lt;br /&gt;
					M = M + 1&lt;br /&gt;
					if M &amp;gt;= 60 then&lt;br /&gt;
						M = 0&lt;br /&gt;
						inc_hour = true&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			elseif code == &#039;M&#039; then&lt;br /&gt;
				if S &amp;gt;= 30 then&lt;br /&gt;
					M = M + 1&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				-- Nothing needed because S is an integer.&lt;br /&gt;
			end&lt;br /&gt;
			if inc_hour then&lt;br /&gt;
				H = H + 1&lt;br /&gt;
				if H &amp;gt;= 24 then&lt;br /&gt;
					H = 0&lt;br /&gt;
					days = days + 1&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if code == &#039;dh&#039; or code == &#039;dhm&#039; or code == &#039;dhms&#039; then&lt;br /&gt;
			if code == &#039;dh&#039; then&lt;br /&gt;
				return days, H&lt;br /&gt;
			elseif code == &#039;dhm&#039; then&lt;br /&gt;
				return days, H, M&lt;br /&gt;
			else&lt;br /&gt;
				return days, H, M, S&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		local hours = days * 24 + H&lt;br /&gt;
		if code == &#039;h&#039; then&lt;br /&gt;
			return hours&lt;br /&gt;
		elseif code == &#039;hm&#039; then&lt;br /&gt;
			return hours, M&lt;br /&gt;
		elseif code == &#039;M&#039; or code == &#039;s&#039; then&lt;br /&gt;
			M = hours * 60 + M&lt;br /&gt;
			if code == &#039;M&#039; then&lt;br /&gt;
				return M&lt;br /&gt;
			end&lt;br /&gt;
			return M * 60 + S&lt;br /&gt;
		end&lt;br /&gt;
		return hours, M, S&lt;br /&gt;
	end&lt;br /&gt;
	if wantround then&lt;br /&gt;
		local inc_hour&lt;br /&gt;
		if code == &#039;ymdh&#039; or code == &#039;ymwdh&#039; then&lt;br /&gt;
			if M &amp;gt;= 30 then&lt;br /&gt;
				inc_hour = true&lt;br /&gt;
			end&lt;br /&gt;
		elseif code == &#039;ymdhm&#039; or code == &#039;ymwdhm&#039; then&lt;br /&gt;
			if S &amp;gt;= 30 then&lt;br /&gt;
				M = M + 1&lt;br /&gt;
				if M &amp;gt;= 60 then&lt;br /&gt;
					M = 0&lt;br /&gt;
					inc_hour = true&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		elseif code == &#039;ymd&#039; or code == &#039;ymwd&#039; or code == &#039;yd&#039; or code == &#039;md&#039; then&lt;br /&gt;
			if H &amp;gt;= 12 then&lt;br /&gt;
				extra_days = extra_days + 1&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if inc_hour then&lt;br /&gt;
			H = H + 1&lt;br /&gt;
			if H &amp;gt;= 24 then&lt;br /&gt;
				H = 0&lt;br /&gt;
				extra_days = extra_days + 1&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local y, m, d = diff.years, diff.months, diff.days&lt;br /&gt;
	if extra_days &amp;gt; 0 then&lt;br /&gt;
		d = d + extra_days&lt;br /&gt;
		if d &amp;gt; 28 or code == &#039;yd&#039; then&lt;br /&gt;
			-- Recalculate in case have passed a month.&lt;br /&gt;
			diff = diff.date1 + extra_days - diff.date2&lt;br /&gt;
			y, m, d = diff.years, diff.months, diff.days&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if code == &#039;ymd&#039; then&lt;br /&gt;
		return y, m, d&lt;br /&gt;
	elseif code == &#039;yd&#039; then&lt;br /&gt;
		if y &amp;gt; 0 then&lt;br /&gt;
			-- It is known that diff.date1 &amp;gt; diff.date2.&lt;br /&gt;
			diff = diff.date1 - (diff.date2 + (y .. &#039;y&#039;))&lt;br /&gt;
		end&lt;br /&gt;
		return y, floor(diff.age_days)&lt;br /&gt;
	elseif code == &#039;md&#039; then&lt;br /&gt;
		return y * 12 + m, d&lt;br /&gt;
	elseif code == &#039;ym&#039; or code == &#039;m&#039; then&lt;br /&gt;
		if wantround then&lt;br /&gt;
			if d &amp;gt;= 16 then&lt;br /&gt;
				m = m + 1&lt;br /&gt;
				if m &amp;gt;= 12 then&lt;br /&gt;
					m = 0&lt;br /&gt;
					y = y + 1&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if code == &#039;ym&#039; then&lt;br /&gt;
			return y, m&lt;br /&gt;
		end&lt;br /&gt;
		return y * 12 + m&lt;br /&gt;
	elseif code == &#039;ymw&#039; then&lt;br /&gt;
		local weeks = floor(d/7)&lt;br /&gt;
		if wantround then&lt;br /&gt;
			local days = d % 7&lt;br /&gt;
			if days &amp;gt; 3 or (days == 3 and H &amp;gt;= 12) then&lt;br /&gt;
				weeks = weeks + 1&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return y, m, weeks&lt;br /&gt;
	elseif code == &#039;ymwd&#039; then&lt;br /&gt;
		return y, m, floor(d/7), d % 7&lt;br /&gt;
	elseif code == &#039;ymdh&#039; then&lt;br /&gt;
		return y, m, d, H&lt;br /&gt;
	elseif code == &#039;ymwdh&#039; then&lt;br /&gt;
		return y, m, floor(d/7), d % 7, H&lt;br /&gt;
	elseif code == &#039;ymdhm&#039; then&lt;br /&gt;
		return y, m, d, H, M&lt;br /&gt;
	elseif code == &#039;ymwdhm&#039; then&lt;br /&gt;
		return y, m, floor(d/7), d % 7, H, M&lt;br /&gt;
	end&lt;br /&gt;
	if code == &#039;y&#039; then&lt;br /&gt;
		if wantround and m &amp;gt;= 6 then&lt;br /&gt;
			y = y + 1&lt;br /&gt;
		end&lt;br /&gt;
		return y&lt;br /&gt;
	end&lt;br /&gt;
	return nil&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function _diff_duration(diff, code, options)&lt;br /&gt;
	if type(options) ~= &#039;table&#039; then&lt;br /&gt;
		options = { round = options }&lt;br /&gt;
	end&lt;br /&gt;
	options.duration = true&lt;br /&gt;
	return _diff_age(diff, code, options)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Metatable for some operations on date differences.&lt;br /&gt;
diffmt = {  -- for forward declaration above&lt;br /&gt;
	__concat = function (lhs, rhs)&lt;br /&gt;
		return tostring(lhs) .. tostring(rhs)&lt;br /&gt;
	end,&lt;br /&gt;
	__tostring = function (self)&lt;br /&gt;
		return tostring(self.age_days)&lt;br /&gt;
	end,&lt;br /&gt;
	__index = function (self, key)&lt;br /&gt;
		local value&lt;br /&gt;
		if key == &#039;age_days&#039; then&lt;br /&gt;
			if rawget(self, &#039;partial&#039;) then&lt;br /&gt;
				local function jdz(date)&lt;br /&gt;
					return (date.partial and date.partial.first or date).jdz&lt;br /&gt;
				end&lt;br /&gt;
				value = jdz(self.date1) - jdz(self.date2)&lt;br /&gt;
			else&lt;br /&gt;
				value = self.date1.jdz - self.date2.jdz&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if value ~= nil then&lt;br /&gt;
			rawset(self, key, value)&lt;br /&gt;
			return value&lt;br /&gt;
		end&lt;br /&gt;
	end,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function DateDiff(date1, date2, options)  -- for forward declaration above&lt;br /&gt;
	-- Return a table with the difference between two dates (date1 - date2).&lt;br /&gt;
	-- The difference is negative if date1 is older than date2.&lt;br /&gt;
	-- Return nothing if invalid.&lt;br /&gt;
	-- If d = date1 - date2 then&lt;br /&gt;
	--     date1 = date2 + d&lt;br /&gt;
	-- If date1 &amp;gt;= date2 and the dates have no H:M:S time specified then&lt;br /&gt;
	--     date1 = date2 + (d.years..&#039;y&#039;) + (d.months..&#039;m&#039;) + d.days&lt;br /&gt;
	-- where the larger time units are added first.&lt;br /&gt;
	-- The result of Date(2015,1,x) + &#039;1m&#039; is Date(2015,2,28) for&lt;br /&gt;
	-- x = 28, 29, 30, 31. That means, for example,&lt;br /&gt;
	--     d = Date(2015,3,3) - Date(2015,1,31)&lt;br /&gt;
	-- gives d.years, d.months, d.days = 0, 1, 3 (excluding date1).&lt;br /&gt;
	if not (is_date(date1) and is_date(date2) and date1.calendar == date2.calendar) then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
	local wantfill&lt;br /&gt;
	if type(options) == &#039;table&#039; then&lt;br /&gt;
		wantfill = options.fill&lt;br /&gt;
	end&lt;br /&gt;
	local isnegative = false&lt;br /&gt;
	local iszero = false&lt;br /&gt;
	if date1 &amp;lt; date2 then&lt;br /&gt;
		isnegative = true&lt;br /&gt;
		date1, date2 = date2, date1&lt;br /&gt;
	elseif date1 == date2 then&lt;br /&gt;
		iszero = true&lt;br /&gt;
	end&lt;br /&gt;
	-- It is known that date1 &amp;gt;= date2 (period is from date2 to date1).&lt;br /&gt;
	if date1.partial or date2.partial then&lt;br /&gt;
		-- Two partial dates might have timelines:&lt;br /&gt;
		---------------------A=================B--- date1 is from A to B inclusive&lt;br /&gt;
		--------C=======D-------------------------- date2 is from C to D inclusive&lt;br /&gt;
		-- date1 &amp;gt; date2 iff A &amp;gt; C (date1.partial.first &amp;gt; date2.partial.first)&lt;br /&gt;
		-- The periods can overlap (&#039;April 2001&#039; - &#039;2001&#039;):&lt;br /&gt;
		-------------A===B------------------------- A=2001-04-01  B=2001-04-30&lt;br /&gt;
		--------C=====================D------------ C=2001-01-01  D=2001-12-31&lt;br /&gt;
		if wantfill then&lt;br /&gt;
			date1, date2 = autofill(date1, date2)&lt;br /&gt;
		else&lt;br /&gt;
			local function zdiff(date1, date2)&lt;br /&gt;
				local diff = date1 - date2&lt;br /&gt;
				if diff.isnegative then&lt;br /&gt;
					return date1 - date1  -- a valid diff in case we call its methods&lt;br /&gt;
				end&lt;br /&gt;
				return diff&lt;br /&gt;
			end&lt;br /&gt;
			local function getdate(date, which)&lt;br /&gt;
				return date.partial and date.partial[which] or date&lt;br /&gt;
			end&lt;br /&gt;
			local maxdiff = zdiff(getdate(date1, &#039;last&#039;), getdate(date2, &#039;first&#039;))&lt;br /&gt;
			local mindiff = zdiff(getdate(date1, &#039;first&#039;), getdate(date2, &#039;last&#039;))&lt;br /&gt;
			local years, months&lt;br /&gt;
			if maxdiff.years == mindiff.years then&lt;br /&gt;
				years = maxdiff.years&lt;br /&gt;
				if maxdiff.months == mindiff.months then&lt;br /&gt;
					months = maxdiff.months&lt;br /&gt;
				else&lt;br /&gt;
					months = { mindiff.months, maxdiff.months }&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				years = { mindiff.years, maxdiff.years }&lt;br /&gt;
			end&lt;br /&gt;
			return setmetatable({&lt;br /&gt;
				date1 = date1,&lt;br /&gt;
				date2 = date2,&lt;br /&gt;
				partial = {&lt;br /&gt;
					years = years,&lt;br /&gt;
					months = months,&lt;br /&gt;
					maxdiff = maxdiff,&lt;br /&gt;
					mindiff = mindiff,&lt;br /&gt;
				},&lt;br /&gt;
				isnegative = isnegative,&lt;br /&gt;
				iszero = iszero,&lt;br /&gt;
				age = _diff_age,&lt;br /&gt;
				duration = _diff_duration,&lt;br /&gt;
			}, diffmt)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local y1, m1 = date1.year, date1.month&lt;br /&gt;
	local y2, m2 = date2.year, date2.month&lt;br /&gt;
	local years = y1 - y2&lt;br /&gt;
	local months = m1 - m2&lt;br /&gt;
	local d1 = date1.day + hms(date1)&lt;br /&gt;
	local d2 = date2.day + hms(date2)&lt;br /&gt;
	local days, time&lt;br /&gt;
	if d1 &amp;gt;= d2 then&lt;br /&gt;
		days = d1 - d2&lt;br /&gt;
	else&lt;br /&gt;
		months = months - 1&lt;br /&gt;
		-- Get days in previous month (before the &amp;quot;to&amp;quot; date) given December has 31 days.&lt;br /&gt;
		local dpm = m1 &amp;gt; 1 and days_in_month(y1, m1 - 1, date1.calendar) or 31&lt;br /&gt;
		if d2 &amp;gt;= dpm then&lt;br /&gt;
			days = d1 - hms(date2)&lt;br /&gt;
		else&lt;br /&gt;
			days = dpm - d2 + d1&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if months &amp;lt; 0 then&lt;br /&gt;
		years = years - 1&lt;br /&gt;
		months = months + 12&lt;br /&gt;
	end&lt;br /&gt;
	days, time = math.modf(days)&lt;br /&gt;
	local H, M, S = h_m_s(time)&lt;br /&gt;
	return setmetatable({&lt;br /&gt;
		date1 = date1,&lt;br /&gt;
		date2 = date2,&lt;br /&gt;
		partial = false,  -- avoid index lookup&lt;br /&gt;
		years = years,&lt;br /&gt;
		months = months,&lt;br /&gt;
		days = days,&lt;br /&gt;
		hours = H,&lt;br /&gt;
		minutes = M,&lt;br /&gt;
		seconds = S,&lt;br /&gt;
		isnegative = isnegative,&lt;br /&gt;
		iszero = iszero,&lt;br /&gt;
		age = _diff_age,&lt;br /&gt;
		duration = _diff_duration,&lt;br /&gt;
	}, diffmt)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return {&lt;br /&gt;
	_current = current,&lt;br /&gt;
	_Date = Date,&lt;br /&gt;
	_days_in_month = days_in_month,&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EB%AA%A8%EB%93%88:Age&amp;diff=62830</id>
		<title>모듈:Age</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EB%AA%A8%EB%93%88:Age&amp;diff=62830"/>
		<updated>2026-07-05T15:19:44Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: 한국어 위키백과 https://ko.wikipedia.org/wiki/모듈:Age에서 모듈 가져옴&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;-- Implement various &amp;quot;age of&amp;quot; and other date-related templates.&lt;br /&gt;
&lt;br /&gt;
local mtext = {&lt;br /&gt;
	-- Message and other text that should be localized.&lt;br /&gt;
	-- Also need to localize text in table names in function dateDifference.&lt;br /&gt;
    [&#039;mt-bad-param2&#039;] =             &#039;변수 $1=$2이(가) 잘못되었습니다&#039;,&lt;br /&gt;
    [&#039;mt-bad-show&#039;] =               &#039;여기서는 show=$1 변수를 지원하지 않습니다&#039;,&lt;br /&gt;
    [&#039;mt-cannot-add&#039;] =             &#039;&amp;quot;$1&amp;quot;을(를) 더할 수 없습니다&#039;,&lt;br /&gt;
    [&#039;mt-conflicting-show&#039;] =       &#039;show=$1 변수가 round=$2와 충돌합니다&#039;,&lt;br /&gt;
    [&#039;mt-date-wrong-order&#039;] =       &#039;두 번째 날짜는 첫 번째 날짜보다 나중이어야 합니다&#039;,&lt;br /&gt;
    [&#039;mt-dd-future&#039;] =              &#039;사망일(첫 번째 날짜)은 미래일 수 없습니다&#039;,&lt;br /&gt;
    [&#039;mt-dd-wrong-order&#039;] =         &#039;사망일(첫 번째 날짜)은 생년월일(두 번째 날짜)보다 나중이어야 합니다&#039;,&lt;br /&gt;
    [&#039;mt-invalid-bd-age&#039;] =         &#039;나이 계산을 위한 생년월일이 잘못되었습니다&#039;,&lt;br /&gt;
    [&#039;mt-invalid-dates-age&#039;] =      &#039;나이 계산을 위한 날짜가 잘못되었습니다&#039;,&lt;br /&gt;
    [&#039;mt-invalid-end&#039;] =            &#039;두 번째 변수의 종료 날짜가 잘못되었습니다&#039;,&lt;br /&gt;
    [&#039;mt-invalid-start&#039;] =          &#039;첫 번째 변수의 시작 날짜가 잘못되었습니다&#039;,&lt;br /&gt;
    [&#039;mt-need-jdn&#039;] =               &#039;유효한 율리우스 적일(Julian date number)이 필요합니다&#039;,&lt;br /&gt;
    [&#039;mt-need-valid-bd&#039;] =          &#039;유효한 생년월일(연, 월, 일)이 필요합니다&#039;,&lt;br /&gt;
    [&#039;mt-need-valid-bd2&#039;] =         &#039;유효한 생년월일(두 번째 날짜): 연, 월, 일)이 필요합니다&#039;,&lt;br /&gt;
    [&#039;mt-need-valid-date&#039;] =        &#039;유효한 날짜가 필요합니다&#039;,&lt;br /&gt;
    [&#039;mt-need-valid-dd&#039;] =          &#039;유효한 사망일(첫 번째 날짜): 연, 월, 일)이 필요합니다&#039;,&lt;br /&gt;
    [&#039;mt-need-valid-ymd&#039;] =         &#039;유효한 연, 월, 일이 필요합니다&#039;,&lt;br /&gt;
	[&#039;mt-need-valid-ymd-current&#039;] = &#039;유효한 연|월|일 또는 &amp;quot;currentdate&amp;quot;가 필요합니다&#039;,&lt;br /&gt;
    [&#039;mt-need-valid-ymd2&#039;] =        &#039;두 번째 날짜는 연, 월, 일 형식이어야 합니다&#039;,&lt;br /&gt;
    [&#039;mt-template-bad-name&#039;] =      &#039;지정된 틀 이름이 유효하지 않습니다&#039;,&lt;br /&gt;
    [&#039;mt-template-x&#039;] =             &#039;이 모듈을 호출하는 틀에는 실행할 작업을 지정하는 &amp;quot;|template=x&amp;quot;가 있어야 합니다&#039;,&lt;br /&gt;
    [&#039;mt-warn-param1&#039;] =            &#039;잘못된 변수 $1&#039;,&lt;br /&gt;
    [&#039;mt-warn-param2&#039;] =            &#039;변수 $1=$2이(가) 잘못되었습니다&#039;,&lt;br /&gt;
	[&#039;txt-affirmative&#039;] =           { y = true, yes = true, Y = true, Yes = true, YES = true },  -- valid values for df + mf parameters&lt;br /&gt;
	[&#039;txt-yes&#039;] =                   { y = true, yes = true, on = true },  -- valid values for parameters introduced with this module&lt;br /&gt;
    [&#039;txt-and&#039;] =                   &#039; 그리고 &#039;,&lt;br /&gt;
    [&#039;txt-or&#039;] =                    &#039;&amp;amp;nbsp;또는 &#039;,&lt;br /&gt;
    [&#039;txt-category&#039;] =              &#039;분류:잘못된 날짜 변수를 사용 중인 나이 틀이 포함된 문서&#039;,&lt;br /&gt;
    [&#039;txt-comma-and&#039;] =             &#039;, 그리고 &#039;,&lt;br /&gt;
    [&#039;txt-error&#039;] =                 &#039;오류: &#039;,&lt;br /&gt;
	[&#039;txt-format-default&#039;] =        &#039;mf&#039;,  -- &#039;df&#039; (day first = dmy) or &#039;mf&#039; (month first = mdy)&lt;br /&gt;
    [&#039;txt-module-convertnumeric&#039;] = &#039;모듈:ConvertNumeric&#039;,&lt;br /&gt;
	[&#039;txt-module-date&#039;] =           &#039;모듈:Date3&#039;,&lt;br /&gt;
	[&#039;txt-sandbox&#039;] =               &#039;연습장&#039;,&lt;br /&gt;
	[&#039;txt-bda&#039;] = &#039;&amp;lt;span style=&amp;quot;display:none&amp;quot;&amp;gt; (&amp;lt;span class=&amp;quot;bday&amp;quot;&amp;gt;$1&amp;lt;/span&amp;gt;) &amp;lt;/span&amp;gt;$2&amp;lt;span class=&amp;quot;noprint ForceAgeToShow&amp;quot;&amp;gt; ($3세)&amp;lt;/span&amp;gt;&#039;,&lt;br /&gt;
	[&#039;txt-dda&#039;] = &#039;$2&amp;lt;span style=&amp;quot;display:none&amp;quot;&amp;gt;($1)&amp;lt;/span&amp;gt; ($3세)&#039;,&lt;br /&gt;
	[&#039;txt-bda-disp&#039;] = &#039;disp_raw&#039;,  -- disp_raw → age is a number only; disp_age → age is a number and unit (normally years but months or days if very young)&lt;br /&gt;
	[&#039;txt-dda-disp&#039;] = &#039;disp_raw&#039;,&lt;br /&gt;
	[&#039;txt-dmy&#039;] = &#039;%-d일 %B월 %-Y년&#039;,&lt;br /&gt;
	[&#039;txt-mdy&#039;] = &#039;%B월 %-d일, %-Y년&#039;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local isWarning = {&lt;br /&gt;
	[&#039;mt-warn-param1&#039;] = true,&lt;br /&gt;
	[&#039;mt-warn-param2&#039;] = true,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
-- yes[parameter] is true if parameter should be interpreted as &amp;quot;yes&amp;quot;.&lt;br /&gt;
-- Do not want to accept mixed upper/lowercase unless done by previously used templates.&lt;br /&gt;
-- Need to accept &amp;quot;on&amp;quot; because &amp;quot;round=on&amp;quot; is wanted.&lt;br /&gt;
local yes = mtext[&#039;txt-yes&#039;]&lt;br /&gt;
&lt;br /&gt;
-- Max valid age.&lt;br /&gt;
local MAX_AGE = 130&lt;br /&gt;
&lt;br /&gt;
local translate, from_en, to_en, isZero&lt;br /&gt;
if translate then&lt;br /&gt;
	-- Functions to translate from en to local language and reverse go here.&lt;br /&gt;
	-- See example at [[:bn:Module:বয়স]].&lt;br /&gt;
else&lt;br /&gt;
	from_en = function (text)&lt;br /&gt;
		return text&lt;br /&gt;
	end&lt;br /&gt;
	isZero = function (text)&lt;br /&gt;
		return tonumber(text) == 0&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local _Date, _currentDate&lt;br /&gt;
local function getExports(frame)&lt;br /&gt;
	-- Return objects exported from the date module or its sandbox.&lt;br /&gt;
	if not _Date then&lt;br /&gt;
		local sandbox = frame:getTitle():find(mtext[&#039;txt-sandbox&#039;], 1, true) and (&#039;/&#039; .. mtext[&#039;txt-sandbox&#039;]) or &#039;&#039;&lt;br /&gt;
		local datemod = require(mtext[&#039;txt-module-date&#039;] .. sandbox)&lt;br /&gt;
		local realDate = datemod._Date&lt;br /&gt;
		_currentDate = datemod._current&lt;br /&gt;
		if to_en then&lt;br /&gt;
			_Date = function (...)&lt;br /&gt;
				local args = {}&lt;br /&gt;
				for i, v in ipairs({...}) do&lt;br /&gt;
					args[i] = to_en(v)&lt;br /&gt;
				end&lt;br /&gt;
				return realDate(unpack(args))&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			_Date = realDate&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return _Date, _currentDate&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local Collection  -- a table to hold items&lt;br /&gt;
Collection = {&lt;br /&gt;
	add = function (self, item)&lt;br /&gt;
		if item ~= nil then&lt;br /&gt;
			self.n = self.n + 1&lt;br /&gt;
			self[self.n] = item&lt;br /&gt;
		end&lt;br /&gt;
	end,&lt;br /&gt;
	join = function (self, sep)&lt;br /&gt;
		return table.concat(self, sep)&lt;br /&gt;
	end,&lt;br /&gt;
	remove = function (self, pos)&lt;br /&gt;
		if self.n &amp;gt; 0 and (pos == nil or (0 &amp;lt; pos and pos &amp;lt;= self.n)) then&lt;br /&gt;
			self.n = self.n - 1&lt;br /&gt;
			return table.remove(self, pos)&lt;br /&gt;
		end&lt;br /&gt;
	end,&lt;br /&gt;
	sort = function (self, comp)&lt;br /&gt;
		table.sort(self, comp)&lt;br /&gt;
	end,&lt;br /&gt;
	new = function ()&lt;br /&gt;
		return setmetatable({n = 0}, Collection)&lt;br /&gt;
	end&lt;br /&gt;
}&lt;br /&gt;
Collection.__index = Collection&lt;br /&gt;
&lt;br /&gt;
local function stripToNil(text)&lt;br /&gt;
	-- If text is a string, return its trimmed content, or nil if empty.&lt;br /&gt;
	-- Otherwise return text (which may, for example, be nil).&lt;br /&gt;
	if type(text) == &#039;string&#039; then&lt;br /&gt;
		text = text:match(&#039;(%S.-)%s*$&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	return text&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function substituteParameters(text, ...)&lt;br /&gt;
	-- Return text after substituting any given parameters for $1, $2, etc.&lt;br /&gt;
	return mw.message.newRawMessage(text, ...):plain()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function message(msg, ...)&lt;br /&gt;
	-- Return formatted message text for an error or warning.&lt;br /&gt;
	local function getText(msg)&lt;br /&gt;
		return mtext[msg] or error(&#039;Bug: message &amp;quot;&#039; .. tostring(msg) .. &#039;&amp;quot; not defined&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	local categories = {&lt;br /&gt;
		error = mtext[&#039;txt-category&#039;],&lt;br /&gt;
		warning = mtext[&#039;txt-category&#039;],&lt;br /&gt;
	}&lt;br /&gt;
	local a, b, k, category&lt;br /&gt;
	local text = substituteParameters(getText(msg), ...)&lt;br /&gt;
	if isWarning[msg] then&lt;br /&gt;
		a = &#039;&amp;lt;sup&amp;gt;[&amp;lt;i&amp;gt;&#039;&lt;br /&gt;
		b = &#039;&amp;lt;/i&amp;gt;]&amp;lt;/sup&amp;gt;&#039;&lt;br /&gt;
		k = &#039;warning&#039;&lt;br /&gt;
	else&lt;br /&gt;
		a = &#039;&amp;lt;strong class=&amp;quot;error&amp;quot;&amp;gt;&#039; .. getText(&#039;txt-error&#039;)&lt;br /&gt;
		b = &#039;&amp;lt;/strong&amp;gt;&#039;&lt;br /&gt;
		k = &#039;error&#039;&lt;br /&gt;
	end&lt;br /&gt;
	if mw.title.getCurrentTitle():inNamespaces(0) then&lt;br /&gt;
		-- Category only in namespaces: 0=article.&lt;br /&gt;
		category = &#039;[[&#039; .. categories[k] .. &#039;]]&#039;&lt;br /&gt;
	end&lt;br /&gt;
	return&lt;br /&gt;
		a ..&lt;br /&gt;
		mw.text.nowiki(text) ..&lt;br /&gt;
		b ..&lt;br /&gt;
		(category or &#039;&#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function dateFormat(args, options)&lt;br /&gt;
	-- Return&lt;br /&gt;
	--    nil, f	if parameter is valid&lt;br /&gt;
	--      m, f    otherwise&lt;br /&gt;
	-- where&lt;br /&gt;
	--      m = string for warning message with category&lt;br /&gt;
	--      f = string for wanted date format&lt;br /&gt;
	local wanted&lt;br /&gt;
	if options.suppliedformat == &#039;dmy&#039; then&lt;br /&gt;
		wanted = &#039;df&#039;&lt;br /&gt;
	elseif options.suppliedformat == &#039;mdy&#039; then&lt;br /&gt;
		wanted = &#039;mf&#039;&lt;br /&gt;
	else&lt;br /&gt;
		wanted = mtext[&#039;txt-format-default&#039;]&lt;br /&gt;
	end&lt;br /&gt;
	local problem&lt;br /&gt;
	local other = wanted == &#039;df&#039; and &#039;mf&#039; or &#039;df&#039;&lt;br /&gt;
	local parm = args[other] or &#039;&#039;&lt;br /&gt;
	if mtext[&#039;txt-affirmative&#039;][parm] then&lt;br /&gt;
		wanted = other&lt;br /&gt;
	elseif parm ~= &#039;&#039; then&lt;br /&gt;
		problem = message(&#039;mt-warn-param2&#039;, other, parm)&lt;br /&gt;
	end&lt;br /&gt;
	return problem, wanted == &#039;df&#039; and mtext[&#039;txt-dmy&#039;] or mtext[&#039;txt-mdy&#039;]&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatNumber(number)&lt;br /&gt;
	-- Return the given number formatted with commas as group separators,&lt;br /&gt;
	-- given that the number is an integer.&lt;br /&gt;
	local numstr = tostring(number)&lt;br /&gt;
	local length = #numstr&lt;br /&gt;
	local places = Collection.new()&lt;br /&gt;
	local pos = 0&lt;br /&gt;
	repeat&lt;br /&gt;
		places:add(pos)&lt;br /&gt;
		pos = pos + 3&lt;br /&gt;
	until pos &amp;gt;= length&lt;br /&gt;
	places:add(length)&lt;br /&gt;
	local groups = Collection.new()&lt;br /&gt;
	for i = places.n, 2, -1 do&lt;br /&gt;
		local p1 = length - places[i] + 1&lt;br /&gt;
		local p2 = length - places[i - 1]&lt;br /&gt;
		groups:add(numstr:sub(p1, p2))&lt;br /&gt;
	end&lt;br /&gt;
	return groups:join(&#039;,&#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function spellNumber(number, options, i)&lt;br /&gt;
	-- Return result of spelling number, or&lt;br /&gt;
	-- return number (as a string) if cannot spell it.&lt;br /&gt;
	-- i == 1 for the first number which can optionally start with an uppercase letter.&lt;br /&gt;
	number = tostring(number)&lt;br /&gt;
	return require(mtext[&#039;txt-module-convertnumeric&#039;]).spell_number(&lt;br /&gt;
		number,&lt;br /&gt;
		nil,                       -- fraction numerator&lt;br /&gt;
		nil,                       -- fraction denominator&lt;br /&gt;
		i == 1 and options.upper,  -- true: &#039;One&#039; instead of &#039;one&#039;&lt;br /&gt;
		not options.us,            -- true: use &#039;and&#039; between tens/ones etc&lt;br /&gt;
		options.adj,               -- true: hyphenated&lt;br /&gt;
		options.ordinal            -- true: &#039;first&#039; instead of &#039;one&#039;&lt;br /&gt;
	) or number&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function makeExtra(args, flagCurrent)&lt;br /&gt;
	-- Return extra text that will be inserted before the visible result&lt;br /&gt;
	-- but after any sort key.&lt;br /&gt;
	local extra = args.prefix or &#039;&#039;&lt;br /&gt;
	if mw.ustring.len(extra) &amp;gt; 1 then&lt;br /&gt;
		-- Parameter &amp;quot;~&amp;quot; gives &amp;quot;~3&amp;quot; whereas &amp;quot;over&amp;quot; gives &amp;quot;over 3&amp;quot;.&lt;br /&gt;
		if extra:sub(-6, -1) ~= &#039;&amp;amp;nbsp;&#039; then&lt;br /&gt;
			extra = extra .. &#039; &#039;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if flagCurrent then&lt;br /&gt;
		extra = &#039;&amp;lt;span class=&amp;quot;currentage&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&#039; .. extra&lt;br /&gt;
	end&lt;br /&gt;
	return extra&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function makeSort(value, sortable)&lt;br /&gt;
	-- Return a sort key if requested.&lt;br /&gt;
	-- Assume value is a valid number which has not overflowed.&lt;br /&gt;
	if sortable == &#039;sortable_table&#039; or sortable == &#039;sortable_on&#039; or sortable == &#039;sortable_debug&#039; then&lt;br /&gt;
		local sortKey&lt;br /&gt;
		if value == 0 then&lt;br /&gt;
			sortKey = &#039;5000000000000000000&#039;&lt;br /&gt;
		else&lt;br /&gt;
			local mag = math.floor(math.log10(math.abs(value)) + 1e-14)&lt;br /&gt;
			if value &amp;gt; 0 then&lt;br /&gt;
				sortKey = 7000 + mag&lt;br /&gt;
			else&lt;br /&gt;
				sortKey = 2999 - mag&lt;br /&gt;
				value = value + 10^(mag+1)&lt;br /&gt;
			end&lt;br /&gt;
			sortKey = string.format(&#039;%d&#039;, sortKey) .. string.format(&#039;%015.0f&#039;, math.floor(value * 10^(14-mag)))&lt;br /&gt;
		end&lt;br /&gt;
		local result&lt;br /&gt;
		if sortable == &#039;sortable_table&#039; then&lt;br /&gt;
			result = &#039;data-sort-value=&amp;quot;_SORTKEY_&amp;quot;|&#039;&lt;br /&gt;
		elseif sortable == &#039;sortable_debug&#039; then&lt;br /&gt;
			result = &#039;&amp;lt;span data-sort-value=&amp;quot;_SORTKEY_♠&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;border:1px solid&amp;quot;&amp;gt;_SORTKEY_♠&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&#039;&lt;br /&gt;
		else&lt;br /&gt;
			result = &#039;&amp;lt;span data-sort-value=&amp;quot;_SORTKEY_♠&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&#039;&lt;br /&gt;
		end&lt;br /&gt;
		return (result:gsub(&#039;_SORTKEY_&#039;, sortKey))&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local translateParameters = {&lt;br /&gt;
	abbr = {&lt;br /&gt;
		off = &#039;abbr_off&#039;,&lt;br /&gt;
		on = &#039;abbr_on&#039;,&lt;br /&gt;
	},&lt;br /&gt;
	disp = {&lt;br /&gt;
		age = &#039;disp_age&#039;,&lt;br /&gt;
		raw = &#039;disp_raw&#039;,&lt;br /&gt;
	},&lt;br /&gt;
	format = {&lt;br /&gt;
		raw = &#039;format_raw&#039;,&lt;br /&gt;
		commas = &#039;format_commas&#039;,&lt;br /&gt;
	},&lt;br /&gt;
	round = {&lt;br /&gt;
		on = &#039;on&#039;,&lt;br /&gt;
		yes = &#039;on&#039;,&lt;br /&gt;
		months = &#039;ym&#039;,&lt;br /&gt;
		weeks = &#039;ymw&#039;,&lt;br /&gt;
		days = &#039;ymd&#039;,&lt;br /&gt;
		hours = &#039;ymdh&#039;,&lt;br /&gt;
	},&lt;br /&gt;
	sep = {&lt;br /&gt;
		comma = &#039;sep_comma&#039;,&lt;br /&gt;
		[&#039;,&#039;] = &#039;sep_comma&#039;,&lt;br /&gt;
		serialcomma = &#039;sep_serialcomma&#039;,&lt;br /&gt;
		space = &#039;sep_space&#039;,&lt;br /&gt;
	},&lt;br /&gt;
	show = {&lt;br /&gt;
		hide = { id = &#039;hide&#039; },&lt;br /&gt;
		y = { &#039;y&#039;, id = &#039;y&#039; },&lt;br /&gt;
		ym = { &#039;y&#039;, &#039;m&#039;, id = &#039;ym&#039; },&lt;br /&gt;
		ymd = { &#039;y&#039;, &#039;m&#039;, &#039;d&#039;, id = &#039;ymd&#039; },&lt;br /&gt;
		ymw = { &#039;y&#039;, &#039;m&#039;, &#039;w&#039;, id = &#039;ymw&#039; },&lt;br /&gt;
		ymwd = { &#039;y&#039;, &#039;m&#039;, &#039;w&#039;, &#039;d&#039;, id = &#039;ymwd&#039; },&lt;br /&gt;
		yd = { &#039;y&#039;, &#039;d&#039;, id = &#039;yd&#039;, keepZero = true },&lt;br /&gt;
		m = { &#039;m&#039;, id = &#039;m&#039; },&lt;br /&gt;
		md = { &#039;m&#039;, &#039;d&#039;, id = &#039;md&#039; },&lt;br /&gt;
		w = { &#039;w&#039;, id = &#039;w&#039; },&lt;br /&gt;
		wd = { &#039;w&#039;, &#039;d&#039;, id = &#039;wd&#039; },&lt;br /&gt;
		h = { &#039;H&#039;, id = &#039;h&#039; },&lt;br /&gt;
		hm = { &#039;H&#039;, &#039;M&#039;, id = &#039;hm&#039; },&lt;br /&gt;
		hms = { &#039;H&#039;, &#039;M&#039;, &#039;S&#039;, id = &#039;hms&#039; },&lt;br /&gt;
		M = { &#039;M&#039;, id = &#039;M&#039; },&lt;br /&gt;
		s = { &#039;S&#039;, id = &#039;s&#039; },&lt;br /&gt;
		d = { &#039;d&#039;, id = &#039;d&#039; },&lt;br /&gt;
		dh = { &#039;d&#039;, &#039;H&#039;, id = &#039;dh&#039; },&lt;br /&gt;
		dhm = { &#039;d&#039;, &#039;H&#039;, &#039;M&#039;, id = &#039;dhm&#039; },&lt;br /&gt;
		dhms = { &#039;d&#039;, &#039;H&#039;, &#039;M&#039;, &#039;S&#039;, id = &#039;dhms&#039; },&lt;br /&gt;
		ymdh = { &#039;y&#039;, &#039;m&#039;, &#039;d&#039;, &#039;H&#039;, id = &#039;ymdh&#039; },&lt;br /&gt;
		ymdhm = { &#039;y&#039;, &#039;m&#039;, &#039;d&#039;, &#039;H&#039;, &#039;M&#039;, id = &#039;ymdhm&#039; },&lt;br /&gt;
		ymwdh = { &#039;y&#039;, &#039;m&#039;, &#039;w&#039;, &#039;d&#039;, &#039;H&#039;, id = &#039;ymwdh&#039; },&lt;br /&gt;
		ymwdhm = { &#039;y&#039;, &#039;m&#039;, &#039;w&#039;, &#039;d&#039;, &#039;H&#039;, &#039;M&#039;, id = &#039;ymwdhm&#039; },&lt;br /&gt;
	},&lt;br /&gt;
	sortable = {&lt;br /&gt;
		off = false,&lt;br /&gt;
		on = &#039;sortable_on&#039;,&lt;br /&gt;
		table = &#039;sortable_table&#039;,&lt;br /&gt;
		debug = &#039;sortable_debug&#039;,&lt;br /&gt;
	},&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local spellOptions = {&lt;br /&gt;
	cardinal = {},&lt;br /&gt;
	Cardinal = { upper = true },&lt;br /&gt;
	cardinal_us = { us = true },&lt;br /&gt;
	Cardinal_us = { us = true, upper = true },&lt;br /&gt;
	ordinal = { ordinal = true },&lt;br /&gt;
	Ordinal = { ordinal = true, upper = true },&lt;br /&gt;
	ordinal_us = { ordinal = true, us = true },&lt;br /&gt;
	Ordinal_us = { ordinal = true, us = true, upper = true },&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local function dateExtract(frame)&lt;br /&gt;
	-- Return part of a date after performing an optional operation.&lt;br /&gt;
	local Date = getExports(frame)&lt;br /&gt;
	local args = frame:getParent().args&lt;br /&gt;
	local parms = {}&lt;br /&gt;
	for i, v in ipairs(args) do&lt;br /&gt;
		parms[i] = v&lt;br /&gt;
	end&lt;br /&gt;
	if yes[args.fix] then&lt;br /&gt;
		table.insert(parms, &#039;fix&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	if yes[args.partial] then&lt;br /&gt;
		table.insert(parms, &#039;partial&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	local show = stripToNil(args.show) or &#039;dmy&#039;&lt;br /&gt;
	local date = Date(unpack(parms))&lt;br /&gt;
	if not date then&lt;br /&gt;
		if show == &#039;format&#039; then&lt;br /&gt;
			return &#039;error&#039;&lt;br /&gt;
		end&lt;br /&gt;
		return message(&#039;mt-need-valid-date&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	local add = stripToNil(args.add)&lt;br /&gt;
	if add then&lt;br /&gt;
		for item in add:gmatch(&#039;%S+&#039;) do&lt;br /&gt;
			date = date + item&lt;br /&gt;
			if not date then&lt;br /&gt;
				return message(&#039;mt-cannot-add&#039;, item)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local sortKey, result&lt;br /&gt;
	local sortable = translateParameters.sortable[args.sortable]&lt;br /&gt;
	if sortable then&lt;br /&gt;
		local value = (date.partial and date.partial.first or date).jdz&lt;br /&gt;
		sortKey = makeSort(value, sortable)&lt;br /&gt;
	end&lt;br /&gt;
	if show ~= &#039;hide&#039; then&lt;br /&gt;
		result = date[show]&lt;br /&gt;
		if result == nil then&lt;br /&gt;
			result = from_en(date:text(show))&lt;br /&gt;
		elseif type(result) == &#039;boolean&#039; then&lt;br /&gt;
			result = result and &#039;1&#039; or &#039;0&#039;&lt;br /&gt;
		else&lt;br /&gt;
			result = from_en(tostring(result))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return (sortKey or &#039;&#039;) .. makeExtra(args) .. (result or &#039;&#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function rangeJoin(range)&lt;br /&gt;
	-- Return text to be used between a range of ages.&lt;br /&gt;
	return range == &#039;dash&#039; and &#039;–&#039; or mtext[&#039;txt-or&#039;]&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function makeText(values, components, names, options, noUpper)&lt;br /&gt;
	-- Return wikitext representing an age or duration.&lt;br /&gt;
	local text = Collection.new()&lt;br /&gt;
	local count = #values&lt;br /&gt;
	local sep = names.sep or &#039;&#039;&lt;br /&gt;
	for i, v in ipairs(values) do&lt;br /&gt;
		-- v is a number (say 4 for 4 years), or a table ({4,5} for 4 or 5 years).&lt;br /&gt;
		local islist = type(v) == &#039;table&#039;&lt;br /&gt;
		if (islist or v &amp;gt; 0) or (text.n == 0 and i == count) or (text.n &amp;gt; 0 and components.keepZero) then&lt;br /&gt;
			local fmt, vstr&lt;br /&gt;
			if options.spell then&lt;br /&gt;
				fmt = function(number)&lt;br /&gt;
					return spellNumber(number, options.spell, noUpper or i)&lt;br /&gt;
				end&lt;br /&gt;
			elseif i == 1 and options.format == &#039;format_commas&#039; then&lt;br /&gt;
				-- Numbers after the first should be small and not need formatting.&lt;br /&gt;
				fmt = formatNumber&lt;br /&gt;
			else&lt;br /&gt;
				fmt = tostring&lt;br /&gt;
			end&lt;br /&gt;
			if islist then&lt;br /&gt;
				vstr = fmt(v[1]) .. rangeJoin(options.range)&lt;br /&gt;
				noUpper = true&lt;br /&gt;
				vstr = vstr .. fmt(v[2])&lt;br /&gt;
			else&lt;br /&gt;
				vstr = fmt(v)&lt;br /&gt;
			end&lt;br /&gt;
			local name = names[components[i]]&lt;br /&gt;
			if name then&lt;br /&gt;
				if type(name) == &#039;table&#039; then&lt;br /&gt;
					name = mw.getContentLanguage():plural(islist and v[2] or v, name)&lt;br /&gt;
				end&lt;br /&gt;
				text:add(vstr .. sep .. name)&lt;br /&gt;
			else&lt;br /&gt;
				text:add(vstr)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local first, last&lt;br /&gt;
	if options.join == &#039;sep_space&#039; then&lt;br /&gt;
		first = &#039; &#039;&lt;br /&gt;
		last = &#039; &#039;&lt;br /&gt;
	elseif options.join == &#039;sep_comma&#039; then&lt;br /&gt;
		first = &#039;, &#039;&lt;br /&gt;
		last = &#039;, &#039;&lt;br /&gt;
	elseif options.join == &#039;sep_serialcomma&#039; and text.n &amp;gt; 2 then&lt;br /&gt;
		first = &#039;, &#039;&lt;br /&gt;
		last = mtext[&#039;txt-comma-and&#039;]&lt;br /&gt;
	else&lt;br /&gt;
		first = &#039;, &#039;&lt;br /&gt;
		last = mtext[&#039;txt-and&#039;]&lt;br /&gt;
	end&lt;br /&gt;
	for i, v in ipairs(text) do&lt;br /&gt;
		if i &amp;lt; text.n then&lt;br /&gt;
			text[i] = v .. (i + 1 &amp;lt; text.n and first or last)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local sign = &#039;&#039;&lt;br /&gt;
	if options.isnegative then&lt;br /&gt;
		-- Do not display negative zero.&lt;br /&gt;
		if text.n &amp;gt; 1 or (text.n == 1 and text[1]:sub(1, 1) ~= &#039;0&#039; ) then&lt;br /&gt;
			if options.format == &#039;format_raw&#039; then&lt;br /&gt;
				sign = &#039;-&#039;  -- plain hyphen so result can be used in a calculation&lt;br /&gt;
			else&lt;br /&gt;
				sign = &#039;−&#039;  -- Unicode U+2212 MINUS SIGN&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return&lt;br /&gt;
		(options.sortKey or &#039;&#039;) ..&lt;br /&gt;
		(options.extra or &#039;&#039;) ..&lt;br /&gt;
		sign ..&lt;br /&gt;
		text:join() ..&lt;br /&gt;
		(options.suffix or &#039;&#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function dateDifference(parms)&lt;br /&gt;
	-- Return a formatted date difference using the given parameters&lt;br /&gt;
	-- which have been validated.&lt;br /&gt;
	local names = {&lt;br /&gt;
		-- Each name is:&lt;br /&gt;
		-- * a string if no plural form of the name is used; or&lt;br /&gt;
		-- * a table of strings, one of which is selected using the rules at&lt;br /&gt;
		--   https://translatewiki.net/wiki/Plural/Mediawiki_plural_rules&lt;br /&gt;
		abbr_off = {&lt;br /&gt;
			sep = &#039;&#039;,&lt;br /&gt;
			y = {&#039;년&#039;, &#039;년&#039;},&lt;br /&gt;
			m = {&#039;개월&#039;, &#039;개월&#039;},&lt;br /&gt;
			w = {&#039;주&#039;, &#039;주&#039;},&lt;br /&gt;
			d = {&#039;일&#039;, &#039;일&#039;},&lt;br /&gt;
			H = {&#039;시간&#039;, &#039;시간&#039;},&lt;br /&gt;
			M = {&#039;분&#039;, &#039;분&#039;},&lt;br /&gt;
			S = {&#039;초&#039;, &#039;초&#039;},&lt;br /&gt;
		},&lt;br /&gt;
		abbr_on = {&lt;br /&gt;
			y = &#039;년&#039;,&lt;br /&gt;
			m = &#039;개월&#039;,&lt;br /&gt;
			w = &#039;주&#039;,&lt;br /&gt;
			d = &#039;일&#039;,&lt;br /&gt;
			H = &#039;시간&#039;,&lt;br /&gt;
			M = &#039;분&#039;,&lt;br /&gt;
			S = &#039;초&#039;,&lt;br /&gt;
		},&lt;br /&gt;
		abbr_infant = {      -- for {{age for infant}}&lt;br /&gt;
			sep = &#039;&#039;,&lt;br /&gt;
			y = {&#039;년&#039;, &#039;년&#039;},&lt;br /&gt;
			m = {&#039;개월&#039;, &#039;개월&#039;},&lt;br /&gt;
			w = {&#039;주&#039;, &#039;주&#039;},&lt;br /&gt;
			d = {&#039;일&#039;, &#039;일&#039;},&lt;br /&gt;
			H = {&#039;시간&#039;, &#039;시간&#039;},&lt;br /&gt;
			M = {&#039;분&#039;, &#039;분&#039;},&lt;br /&gt;
			S = {&#039;초&#039;, &#039;초&#039;},&lt;br /&gt;
		},&lt;br /&gt;
		abbr_raw = {},&lt;br /&gt;
	}&lt;br /&gt;
	local diff = parms.diff  -- must be a valid date difference&lt;br /&gt;
	local show = parms.show  -- may be nil; default is set below&lt;br /&gt;
	local abbr = parms.abbr or &#039;abbr_off&#039;&lt;br /&gt;
	local defaultJoin&lt;br /&gt;
	if abbr ~= &#039;abbr_off&#039; then&lt;br /&gt;
		defaultJoin = &#039;sep_space&#039;&lt;br /&gt;
	end&lt;br /&gt;
	if not show then&lt;br /&gt;
		show = &#039;ymd&#039;&lt;br /&gt;
		if parms.disp == &#039;disp_age&#039; then&lt;br /&gt;
			if diff.years &amp;lt; 3 then&lt;br /&gt;
				defaultJoin = &#039;sep_space&#039;&lt;br /&gt;
				if diff.years &amp;gt;= 1 then&lt;br /&gt;
					show = &#039;ym&#039;&lt;br /&gt;
				else&lt;br /&gt;
					show = &#039;md&#039;&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				show = &#039;y&#039;&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if type(show) ~= &#039;table&#039; then&lt;br /&gt;
		show = translateParameters.show[show]&lt;br /&gt;
	end&lt;br /&gt;
	if parms.disp == &#039;disp_raw&#039; then&lt;br /&gt;
		defaultJoin = &#039;sep_space&#039;&lt;br /&gt;
		abbr = &#039;abbr_raw&#039;&lt;br /&gt;
	elseif parms.wantSc then&lt;br /&gt;
		defaultJoin = &#039;sep_serialcomma&#039;&lt;br /&gt;
	end&lt;br /&gt;
	local diffOptions = {&lt;br /&gt;
		round = parms.round,&lt;br /&gt;
		duration = parms.wantDuration,&lt;br /&gt;
		range = parms.range and true or nil,&lt;br /&gt;
	}&lt;br /&gt;
	local sortKey&lt;br /&gt;
	if parms.sortable then&lt;br /&gt;
		local value = diff.age_days + (parms.wantDuration and 1 or 0)  -- days and fraction of a day&lt;br /&gt;
		if diff.isnegative then&lt;br /&gt;
			value = -value&lt;br /&gt;
		end&lt;br /&gt;
		sortKey = makeSort(value, parms.sortable)&lt;br /&gt;
	end&lt;br /&gt;
	local textOptions = {&lt;br /&gt;
		extra = parms.extra,&lt;br /&gt;
		format = parms.format,&lt;br /&gt;
		join = parms.sep or defaultJoin,&lt;br /&gt;
		isnegative = diff.isnegative,&lt;br /&gt;
		range = parms.range,&lt;br /&gt;
		sortKey = sortKey,&lt;br /&gt;
		spell = parms.spell,&lt;br /&gt;
		suffix = parms.suffix,  -- not currently used&lt;br /&gt;
	}&lt;br /&gt;
	if show.id == &#039;hide&#039; then&lt;br /&gt;
		return sortKey or &#039;&#039;&lt;br /&gt;
	end&lt;br /&gt;
	local values = { diff:age(show.id, diffOptions) }&lt;br /&gt;
	if values[1] then&lt;br /&gt;
		return makeText(values, show, names[abbr], textOptions)&lt;br /&gt;
	end&lt;br /&gt;
	if diff.partial then&lt;br /&gt;
		-- Handle a more complex range such as&lt;br /&gt;
		-- {{age_yd|20 Dec 2001|2003|range=yes}} → 1 year, 12 days or 2 years, 11 days&lt;br /&gt;
		local opt = {&lt;br /&gt;
			format = textOptions.format,&lt;br /&gt;
			join = textOptions.join,&lt;br /&gt;
			isnegative = textOptions.isnegative,&lt;br /&gt;
			spell = textOptions.spell,&lt;br /&gt;
		}&lt;br /&gt;
		return&lt;br /&gt;
			(textOptions.sortKey or &#039;&#039;) ..&lt;br /&gt;
			makeText({ diff.partial.mindiff:age(show.id, diffOptions) }, show, names[abbr], opt) ..&lt;br /&gt;
			rangeJoin(textOptions.range) ..&lt;br /&gt;
			makeText({ diff.partial.maxdiff:age(show.id, diffOptions) }, show, names[abbr], opt, true) ..&lt;br /&gt;
			(textOptions.suffix or &#039;&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	return message(&#039;mt-bad-show&#039;, show.id)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getDates(frame, getopt)&lt;br /&gt;
	-- Parse template parameters and return one of:&lt;br /&gt;
	-- * date         (a date table, if single)&lt;br /&gt;
	-- * date1, date2 (two date tables, if not single)&lt;br /&gt;
	-- * text         (a string error message)&lt;br /&gt;
	-- A missing date is optionally replaced with the current date.&lt;br /&gt;
	-- If wantMixture is true, a missing date component is replaced&lt;br /&gt;
	-- from the current date, so can get a bizarre mixture of&lt;br /&gt;
	-- specified/current y/m/d as has been done by some &amp;quot;age&amp;quot; templates.&lt;br /&gt;
	-- Some results may be placed in table getopt.&lt;br /&gt;
	local Date, currentDate = getExports(frame)&lt;br /&gt;
	getopt = getopt or {}&lt;br /&gt;
	local function flagCurrent(text)&lt;br /&gt;
		-- This allows the calling template to detect if the current date has been used,&lt;br /&gt;
		-- that is, whether both dates have been entered in a template expecting two.&lt;br /&gt;
		-- For example, an infobox may want the age when an event occurred, not the current age.&lt;br /&gt;
		-- Don&#039;t bother detecting if wantMixture is used because not needed and it is a poor option.&lt;br /&gt;
		if not text then&lt;br /&gt;
			if getopt.noMissing then&lt;br /&gt;
				return nil  -- this gives a nil date which gives an error&lt;br /&gt;
			end&lt;br /&gt;
			text = &#039;currentdate&#039;&lt;br /&gt;
			if getopt.flag == &#039;usesCurrent&#039; then&lt;br /&gt;
				getopt.usesCurrent = true&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return text&lt;br /&gt;
	end&lt;br /&gt;
	local args = frame:getParent().args&lt;br /&gt;
	local fields = {}&lt;br /&gt;
	local isNamed = args.year or args.year1 or args.year2 or&lt;br /&gt;
		args.month or args.month1 or args.month2 or&lt;br /&gt;
		args.day or args.day1 or args.day2&lt;br /&gt;
	if isNamed then&lt;br /&gt;
		fields[1] = args.year1 or args.year&lt;br /&gt;
		fields[2] = args.month1 or args.month&lt;br /&gt;
		fields[3] = args.day1 or args.day&lt;br /&gt;
		fields[4] = args.year2&lt;br /&gt;
		fields[5] = args.month2&lt;br /&gt;
		fields[6] = args.day2&lt;br /&gt;
	else&lt;br /&gt;
		for i = 1, 6 do&lt;br /&gt;
			fields[i] = args[i]&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local imax = 0&lt;br /&gt;
	for i = 1, 6 do&lt;br /&gt;
		fields[i] = stripToNil(fields[i])&lt;br /&gt;
		if fields[i] then&lt;br /&gt;
			imax = i&lt;br /&gt;
		end&lt;br /&gt;
		if getopt.omitZero and i % 3 ~= 1 then  -- omit zero months and days as unknown values but keep year 0 which is 1 BCE&lt;br /&gt;
			if isZero(fields[i]) then&lt;br /&gt;
				fields[i] = nil&lt;br /&gt;
				getopt.partial = true&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local fix = getopt.fix and &#039;fix&#039; or &#039;&#039;&lt;br /&gt;
	local partialText = getopt.partial and &#039;partial&#039; or &#039;&#039;&lt;br /&gt;
	local dates = {}&lt;br /&gt;
	if isNamed or imax &amp;gt;= 3 then&lt;br /&gt;
		local nrDates = getopt.single and 1 or 2&lt;br /&gt;
		if getopt.wantMixture then&lt;br /&gt;
			-- Cannot be partial since empty fields are set from current.&lt;br /&gt;
			local components = { &#039;year&#039;, &#039;month&#039;, &#039;day&#039; }&lt;br /&gt;
			for i = 1, nrDates * 3 do&lt;br /&gt;
				fields[i] = fields[i] or currentDate[components[i &amp;gt; 3 and i - 3 or i]]&lt;br /&gt;
			end&lt;br /&gt;
			for i = 1, nrDates do&lt;br /&gt;
				local index = i == 1 and 1 or 4&lt;br /&gt;
				local y, m, d = fields[index], fields[index+1], fields[index+2]&lt;br /&gt;
				if (m == 2 or m == &#039;2&#039;) and (d == 29 or d == &#039;29&#039;) then&lt;br /&gt;
					-- Workaround error with following which attempt to use invalid date 2001-02-29.&lt;br /&gt;
					-- {{age_ymwd|year1=2001|year2=2004|month2=2|day2=29}}&lt;br /&gt;
					-- {{age_ymwd|year1=2001|month1=2|year2=2004|month2=1|day2=29}}&lt;br /&gt;
					-- TODO Get rid of wantMixture because even this ugly code does not handle&lt;br /&gt;
					-- &#039;Feb&#039; or &#039;February&#039; or &#039;feb&#039; or &#039;february&#039;.&lt;br /&gt;
					if not ((y % 4 == 0 and y % 100 ~= 0) or y % 400 == 0) then&lt;br /&gt;
						d = 28&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
				dates[i] = Date(y, m, d)&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			-- If partial dates are allowed, accept&lt;br /&gt;
			--     year only, or&lt;br /&gt;
			--     year and month only&lt;br /&gt;
			-- Do not accept year and day without a month because that makes no sense&lt;br /&gt;
			-- (and because, for example, Date(&#039;partial&#039;, 2001, nil, 12) sets day = nil, not 12).&lt;br /&gt;
			for i = 1, nrDates do&lt;br /&gt;
				local index = i == 1 and 1 or 4&lt;br /&gt;
				local y, m, d = fields[index], fields[index+1], fields[index+2]&lt;br /&gt;
				if (getopt.partial and y and (m or not d)) or (y and m and d) then&lt;br /&gt;
					dates[i] = Date(fix, partialText, y, m, d)&lt;br /&gt;
				elseif not y and not m and not d then&lt;br /&gt;
					dates[i] = Date(flagCurrent())&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		getopt.textdates = true  -- have parsed each date from a single text field&lt;br /&gt;
		dates[1] = Date(fix, partialText, flagCurrent(fields[1]))&lt;br /&gt;
		if not getopt.single then&lt;br /&gt;
			dates[2] = Date(fix, partialText, flagCurrent(fields[2]))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if not dates[1] then&lt;br /&gt;
		return message(getopt.missing1 or &#039;mt-need-valid-ymd&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	if getopt.textdates then&lt;br /&gt;
		getopt.suppliedformat = dates[1].format&lt;br /&gt;
	end&lt;br /&gt;
	if getopt.single then&lt;br /&gt;
		return dates[1]&lt;br /&gt;
	end&lt;br /&gt;
	if not dates[2] then&lt;br /&gt;
		return message(getopt.missing2 or &#039;mt-need-valid-ymd2&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	return dates[1], dates[2]&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function ageGeneric(frame)&lt;br /&gt;
	-- Return the result required by the specified template.&lt;br /&gt;
	-- Can use sortable=x where x = on/table/off/debug in any supported template.&lt;br /&gt;
	-- Some templates default to sortable=on but can be overridden.&lt;br /&gt;
	local name = frame.args.template&lt;br /&gt;
	if not name then&lt;br /&gt;
		return message(&#039;mt-template-x&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	local args = frame:getParent().args&lt;br /&gt;
	local specs = {&lt;br /&gt;
		age_days = {                -- {{age in days}}&lt;br /&gt;
			show = &#039;d&#039;,&lt;br /&gt;
			disp = &#039;disp_raw&#039;,&lt;br /&gt;
		},&lt;br /&gt;
		age_days_nts = {            -- {{age in days nts}}&lt;br /&gt;
			show = &#039;d&#039;,&lt;br /&gt;
			disp = &#039;disp_raw&#039;,&lt;br /&gt;
			format = &#039;format_commas&#039;,&lt;br /&gt;
			sortable = &#039;on&#039;,&lt;br /&gt;
		},&lt;br /&gt;
		duration_days = {           -- {{duration in days}}&lt;br /&gt;
			show = &#039;d&#039;,&lt;br /&gt;
			disp = &#039;disp_raw&#039;,&lt;br /&gt;
			duration = true,&lt;br /&gt;
		},&lt;br /&gt;
		duration_days_nts = {       -- {{duration in days nts}}&lt;br /&gt;
			show = &#039;d&#039;,&lt;br /&gt;
			disp = &#039;disp_raw&#039;,&lt;br /&gt;
			format = &#039;format_commas&#039;,&lt;br /&gt;
			sortable = &#039;on&#039;,&lt;br /&gt;
			duration = true,&lt;br /&gt;
		},&lt;br /&gt;
		age_full_years = {          -- {{age}}&lt;br /&gt;
			show = &#039;y&#039;,&lt;br /&gt;
			abbr = &#039;abbr_raw&#039;,&lt;br /&gt;
			flag = &#039;usesCurrent&#039;,&lt;br /&gt;
			omitZero = true,&lt;br /&gt;
			range = &#039;dash&#039;,&lt;br /&gt;
		},&lt;br /&gt;
		age_full_years_nts = {      -- {{age nts}}&lt;br /&gt;
			show = &#039;y&#039;,&lt;br /&gt;
			abbr = &#039;abbr_raw&#039;,&lt;br /&gt;
			format = &#039;format_commas&#039;,&lt;br /&gt;
			sortable = &#039;on&#039;,&lt;br /&gt;
		},&lt;br /&gt;
		age_in_years = {            -- {{age in years}}&lt;br /&gt;
			show = &#039;y&#039;,&lt;br /&gt;
			abbr = &#039;abbr_raw&#039;,&lt;br /&gt;
			negative = &#039;error&#039;,&lt;br /&gt;
			range = &#039;dash&#039;,&lt;br /&gt;
		},&lt;br /&gt;
		age_in_years_nts = {        -- {{age in years nts}}&lt;br /&gt;
			show = &#039;y&#039;,&lt;br /&gt;
			abbr = &#039;abbr_raw&#039;,&lt;br /&gt;
			negative = &#039;error&#039;,&lt;br /&gt;
			range = &#039;dash&#039;,&lt;br /&gt;
			format = &#039;format_commas&#039;,&lt;br /&gt;
			sortable = &#039;on&#039;,&lt;br /&gt;
		},&lt;br /&gt;
		age_infant = {              -- {{age for infant}}&lt;br /&gt;
			-- Do not set show because special processing is done later.&lt;br /&gt;
			abbr = yes[args.abbr] and &#039;abbr_infant&#039; or &#039;abbr_off&#039;,&lt;br /&gt;
			disp = &#039;disp_age&#039;,&lt;br /&gt;
			sep = &#039;sep_space&#039;,&lt;br /&gt;
			sortable = &#039;on&#039;,&lt;br /&gt;
		},&lt;br /&gt;
		age_m = {                   -- {{age in months}}&lt;br /&gt;
			show = &#039;m&#039;,&lt;br /&gt;
			disp = &#039;disp_raw&#039;,&lt;br /&gt;
		},&lt;br /&gt;
		age_w = {                   -- {{age in weeks}}&lt;br /&gt;
			show = &#039;w&#039;,&lt;br /&gt;
			disp = &#039;disp_raw&#039;,&lt;br /&gt;
		},&lt;br /&gt;
		age_wd = {                  -- {{age in weeks and days}}&lt;br /&gt;
			show = &#039;wd&#039;,&lt;br /&gt;
		},&lt;br /&gt;
		age_yd = {                  -- {{age in years and days}}&lt;br /&gt;
			show = &#039;yd&#039;,&lt;br /&gt;
			format = &#039;format_commas&#039;,&lt;br /&gt;
			sep = args.sep ~= &#039;and&#039; and &#039;sep_comma&#039; or nil,&lt;br /&gt;
		},&lt;br /&gt;
		age_yd_nts = {              -- {{age in years and days nts}}&lt;br /&gt;
			show = &#039;yd&#039;,&lt;br /&gt;
			format = &#039;format_commas&#039;,&lt;br /&gt;
			sep = args.sep ~= &#039;and&#039; and &#039;sep_comma&#039; or nil,&lt;br /&gt;
			sortable = &#039;on&#039;,&lt;br /&gt;
		},&lt;br /&gt;
		age_ym = {                  -- {{age in years and months}}&lt;br /&gt;
			show = &#039;ym&#039;,&lt;br /&gt;
			sep = &#039;sep_comma&#039;,&lt;br /&gt;
		},&lt;br /&gt;
		age_ymd = {                 -- {{age in years, months and days}}&lt;br /&gt;
			show = &#039;ymd&#039;,&lt;br /&gt;
			range = true,&lt;br /&gt;
		},&lt;br /&gt;
		age_ymwd = {                -- {{age in years, months, weeks and days}}&lt;br /&gt;
			show = &#039;ymwd&#039;,&lt;br /&gt;
			wantMixture = true,&lt;br /&gt;
		},&lt;br /&gt;
	}&lt;br /&gt;
	local spec = specs[name]&lt;br /&gt;
	if not spec then&lt;br /&gt;
		return message(&#039;mt-template-bad-name&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	if name == &#039;age_days&#039; then&lt;br /&gt;
		local su = stripToNil(args[&#039;show unit&#039;])&lt;br /&gt;
		if su then&lt;br /&gt;
			if su == &#039;abbr&#039; or su == &#039;full&#039; then&lt;br /&gt;
				spec.disp = nil&lt;br /&gt;
				spec.abbr = su == &#039;abbr&#039; and &#039;abbr_on&#039; or nil&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local partial, autofill&lt;br /&gt;
	local range = stripToNil(args.range) or spec.range&lt;br /&gt;
	if range then&lt;br /&gt;
		-- Suppose partial dates are used and age could be 11 or 12 years.&lt;br /&gt;
		-- &amp;quot;|range=&amp;quot; (empty value) has no effect (spec is used).&lt;br /&gt;
		-- &amp;quot;|range=yes&amp;quot; or spec.range == true sets range = true (gives &amp;quot;11 or 12&amp;quot;)&lt;br /&gt;
		-- &amp;quot;|range=dash&amp;quot; or spec.range == &#039;dash&#039; sets range = &#039;dash&#039; (gives &amp;quot;11–12&amp;quot;).&lt;br /&gt;
		-- &amp;quot;|range=no&amp;quot; or spec.range == &#039;no&#039; sets range = nil and fills each date in the diff (gives &amp;quot;12&amp;quot;).&lt;br /&gt;
		--     (&amp;quot;on&amp;quot; is equivalent to &amp;quot;yes&amp;quot;, and &amp;quot;off&amp;quot; is equivalent to &amp;quot;no&amp;quot;).&lt;br /&gt;
		-- &amp;quot;|range=OTHER&amp;quot; sets range = nil and rejects partial dates.&lt;br /&gt;
		range = ({ dash = &#039;dash&#039;, off = &#039;no&#039;, no = &#039;no&#039;, [true] = true })[range] or yes[range]&lt;br /&gt;
		if range then&lt;br /&gt;
			partial = true  -- accept partial dates with a possible age range for the result&lt;br /&gt;
			if range == &#039;no&#039; then&lt;br /&gt;
				autofill = true  -- missing month/day in first or second date are filled from other date or 1&lt;br /&gt;
				range = nil&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local getopt = {&lt;br /&gt;
		fix = yes[args.fix],&lt;br /&gt;
		flag = stripToNil(args.flag) or spec.flag,&lt;br /&gt;
		omitZero = spec.omitZero,&lt;br /&gt;
		partial = partial,&lt;br /&gt;
		wantMixture = spec.wantMixture,&lt;br /&gt;
	}&lt;br /&gt;
	local date1, date2 = getDates(frame, getopt)&lt;br /&gt;
	if type(date1) == &#039;string&#039; then&lt;br /&gt;
		return date1&lt;br /&gt;
	end&lt;br /&gt;
	local format = stripToNil(args.format)&lt;br /&gt;
	local spell = spellOptions[format]&lt;br /&gt;
	if format then&lt;br /&gt;
		format = &#039;format_&#039; .. format&lt;br /&gt;
	elseif name == &#039;age_days&#039; and getopt.textdates then&lt;br /&gt;
		format = &#039;format_commas&#039;&lt;br /&gt;
	end&lt;br /&gt;
	local parms = {&lt;br /&gt;
		diff = date2:subtract(date1, { fill = autofill }),&lt;br /&gt;
		wantDuration = spec.duration or yes[args.duration],&lt;br /&gt;
		range = range,&lt;br /&gt;
		wantSc = yes[args.sc],&lt;br /&gt;
		show = args.show == &#039;hide&#039; and &#039;hide&#039; or spec.show,&lt;br /&gt;
		abbr = spec.abbr,&lt;br /&gt;
		disp = spec.disp,&lt;br /&gt;
		extra = makeExtra(args, getopt.usesCurrent and format ~= &#039;format_raw&#039;),&lt;br /&gt;
		format = format or spec.format,&lt;br /&gt;
		round = yes[args.round],&lt;br /&gt;
		sep = spec.sep,&lt;br /&gt;
		sortable = translateParameters.sortable[args.sortable or spec.sortable],&lt;br /&gt;
		spell = spell,&lt;br /&gt;
	}&lt;br /&gt;
	if (spec.negative or frame.args.negative) == &#039;error&#039; and parms.diff.isnegative then&lt;br /&gt;
		return message(&#039;mt-date-wrong-order&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	return from_en(dateDifference(parms))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function isFake(args)&lt;br /&gt;
	-- Some templates have TemplateData with an auto value like &amp;quot;{{Birth date and age|YYYY|MM|DD}}&amp;quot;.&lt;br /&gt;
	-- Return true if that appears to be the case so the caller can output nothing rather than an error.&lt;br /&gt;
	return args[1] == &#039;YYYY&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function bda(frame)&lt;br /&gt;
	-- Implement [[Template:Birth date and age]].&lt;br /&gt;
	local args = frame:getParent().args&lt;br /&gt;
	if isFake(args) then&lt;br /&gt;
		return &#039;&#039;&lt;br /&gt;
	end&lt;br /&gt;
	local options = {&lt;br /&gt;
		missing1 = &#039;mt-need-valid-bd&#039;,&lt;br /&gt;
		noMissing = true,&lt;br /&gt;
		single = true,&lt;br /&gt;
	}&lt;br /&gt;
	local date = getDates(frame, options)&lt;br /&gt;
	if type(date) == &#039;string&#039; then&lt;br /&gt;
		return date  -- error text&lt;br /&gt;
	end&lt;br /&gt;
	local Date = getExports(frame)&lt;br /&gt;
	local diff = Date(&#039;currentdate&#039;) - date&lt;br /&gt;
	if diff.isnegative or diff.years &amp;gt; MAX_AGE then&lt;br /&gt;
		return message(&#039;mt-invalid-bd-age&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	local disp = mtext[&#039;txt-bda-disp&#039;]&lt;br /&gt;
	local show = &#039;y&#039;&lt;br /&gt;
	if diff.years &amp;lt; 2 then&lt;br /&gt;
		disp = &#039;disp_age&#039;&lt;br /&gt;
		if diff.years == 0 and diff.months == 0 then&lt;br /&gt;
			show = &#039;d&#039;&lt;br /&gt;
		else&lt;br /&gt;
			show = &#039;m&#039;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local problem, format = dateFormat(args, options)&lt;br /&gt;
	local result = substituteParameters(&lt;br /&gt;
		mtext[&#039;txt-bda&#039;],&lt;br /&gt;
		date:text(&#039;%-Y-%m-%d&#039;),&lt;br /&gt;
		from_en(date:text(format)),&lt;br /&gt;
		from_en(dateDifference({&lt;br /&gt;
			diff = diff,&lt;br /&gt;
			show = show,&lt;br /&gt;
			abbr = &#039;abbr_off&#039;,&lt;br /&gt;
			disp = disp,&lt;br /&gt;
			sep = &#039;sep_space&#039;,&lt;br /&gt;
		}))&lt;br /&gt;
	) .. (problem or &#039;&#039;)&lt;br /&gt;
	local warnings = tonumber(frame.args.warnings)&lt;br /&gt;
	if warnings and warnings &amp;gt; 0 then&lt;br /&gt;
		local good = {&lt;br /&gt;
			df = true,&lt;br /&gt;
			mf = true,&lt;br /&gt;
			day = true,&lt;br /&gt;
			day1 = true,&lt;br /&gt;
			month = true,&lt;br /&gt;
			month1 = true,&lt;br /&gt;
			year = true,&lt;br /&gt;
			year1 = true,&lt;br /&gt;
		}&lt;br /&gt;
		local invalid&lt;br /&gt;
		local imax = options.textdates and 1 or 3&lt;br /&gt;
		for k, _ in pairs(args) do&lt;br /&gt;
			if type(k) == &#039;number&#039; then&lt;br /&gt;
				if k &amp;gt; imax then&lt;br /&gt;
					invalid = tostring(k)&lt;br /&gt;
					break&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				if not good[k] then&lt;br /&gt;
					invalid = k&lt;br /&gt;
					break&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if invalid then&lt;br /&gt;
			result = result .. message(&#039;mt-warn-param1&#039;, invalid)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return result&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function dda(frame)&lt;br /&gt;
	-- Implement [[Template:Death date and age]].&lt;br /&gt;
	local args = frame:getParent().args&lt;br /&gt;
	if isFake(args) then&lt;br /&gt;
		return &#039;&#039;&lt;br /&gt;
	end&lt;br /&gt;
	local options = {&lt;br /&gt;
		missing1 = &#039;mt-need-valid-dd&#039;,&lt;br /&gt;
		missing2 = &#039;mt-need-valid-bd2&#039;,&lt;br /&gt;
		noMissing = true,&lt;br /&gt;
		partial = true,&lt;br /&gt;
	}&lt;br /&gt;
	local date1, date2 = getDates(frame, options)&lt;br /&gt;
	if type(date1) == &#039;string&#039; then&lt;br /&gt;
		return date1&lt;br /&gt;
	end&lt;br /&gt;
	local diff = date1 - date2&lt;br /&gt;
	if diff.isnegative then&lt;br /&gt;
		return message(&#039;mt-dd-wrong-order&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	local Date = getExports(frame)&lt;br /&gt;
	local today = Date(&#039;currentdate&#039;) + 1  -- one day in future allows for timezones&lt;br /&gt;
	if date1 &amp;gt; today then&lt;br /&gt;
		return message(&#039;mt-dd-future&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	local years&lt;br /&gt;
	if diff.partial then&lt;br /&gt;
		years = diff.partial.years&lt;br /&gt;
		years = type(years) == &#039;table&#039; and years[2] or years&lt;br /&gt;
	else&lt;br /&gt;
		years = diff.years&lt;br /&gt;
	end&lt;br /&gt;
	if years &amp;gt; MAX_AGE then&lt;br /&gt;
		return message(&#039;mt-invalid-dates-age&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	local fmt_date, fmt_ymd, problem&lt;br /&gt;
	if date1.day then  -- y, m, d known&lt;br /&gt;
		problem, fmt_date = dateFormat(args, options)&lt;br /&gt;
		fmt_ymd = &#039;%-Y-%m-%d&#039;&lt;br /&gt;
	elseif date1.month then  -- y, m known; d unknown&lt;br /&gt;
		fmt_date = &#039;%B %-Y&#039;&lt;br /&gt;
		fmt_ymd = &#039;%-Y-%m-00&#039;&lt;br /&gt;
	else  -- y known; m, d unknown&lt;br /&gt;
		fmt_date = &#039;%-Y&#039;&lt;br /&gt;
		fmt_ymd = &#039;%-Y-00-00&#039;&lt;br /&gt;
	end&lt;br /&gt;
	local sortKey&lt;br /&gt;
	local sortable = translateParameters.sortable[args.sortable]&lt;br /&gt;
	if sortable then&lt;br /&gt;
		local value = (date1.partial and date1.partial.first or date1).jdz&lt;br /&gt;
		sortKey = makeSort(value, sortable)&lt;br /&gt;
	end&lt;br /&gt;
	local result = (sortKey or &#039;&#039;) .. substituteParameters(&lt;br /&gt;
		mtext[&#039;txt-dda&#039;],&lt;br /&gt;
		date1:text(fmt_ymd),&lt;br /&gt;
		from_en(date1:text(fmt_date)),&lt;br /&gt;
		from_en(dateDifference({&lt;br /&gt;
			diff = diff,&lt;br /&gt;
			show = &#039;y&#039;,&lt;br /&gt;
			abbr = &#039;abbr_off&#039;,&lt;br /&gt;
			disp = mtext[&#039;txt-dda-disp&#039;],&lt;br /&gt;
			range = &#039;dash&#039;,&lt;br /&gt;
			sep = &#039;sep_space&#039;,&lt;br /&gt;
		}))&lt;br /&gt;
	) .. (problem or &#039;&#039;)&lt;br /&gt;
	local warnings = tonumber(frame.args.warnings)&lt;br /&gt;
	if warnings and warnings &amp;gt; 0 then&lt;br /&gt;
		local good = {&lt;br /&gt;
			df = true,&lt;br /&gt;
			mf = true,&lt;br /&gt;
		}&lt;br /&gt;
		local invalid&lt;br /&gt;
		local imax = options.textdates and 2 or 6&lt;br /&gt;
		for k, _ in pairs(args) do&lt;br /&gt;
			if type(k) == &#039;number&#039; then&lt;br /&gt;
				if k &amp;gt; imax then&lt;br /&gt;
					invalid = tostring(k)&lt;br /&gt;
					break&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				if not good[k] then&lt;br /&gt;
					invalid = k&lt;br /&gt;
					break&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if invalid then&lt;br /&gt;
			result = result .. message(&#039;mt-warn-param1&#039;, invalid)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return result&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function dateToGsd(frame)&lt;br /&gt;
	-- Implement [[Template:Gregorian serial date]].&lt;br /&gt;
	-- Return Gregorian serial date of the given date, or the current date.&lt;br /&gt;
	-- The returned value is negative for dates before 1 January 1 AD&lt;br /&gt;
	-- despite the fact that GSD is not defined for such dates.&lt;br /&gt;
	local date = getDates(frame, { wantMixture=true, single=true })&lt;br /&gt;
	if type(date) == &#039;string&#039; then&lt;br /&gt;
		return date&lt;br /&gt;
	end&lt;br /&gt;
	return tostring(date.gsd)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function jdToDate(frame)&lt;br /&gt;
	-- Return formatted date from a Julian date.&lt;br /&gt;
	-- The result includes a time if the input includes a fraction.&lt;br /&gt;
	-- The word &#039;Julian&#039; is accepted for the Julian calendar.&lt;br /&gt;
	local Date = getExports(frame)&lt;br /&gt;
	local args = frame:getParent().args&lt;br /&gt;
	local date = Date(&#039;juliandate&#039;, args[1], args[2])&lt;br /&gt;
	if date then&lt;br /&gt;
		return from_en(date:text())&lt;br /&gt;
	end&lt;br /&gt;
	return message(&#039;mt-need-jdn&#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function dateToJd(frame)&lt;br /&gt;
	-- Return Julian date (a number) from a date which may include a time,&lt;br /&gt;
	-- or the current date (&#039;currentdate&#039;) or current date and time (&#039;currentdatetime&#039;).&lt;br /&gt;
	-- The word &#039;Julian&#039; is accepted for the Julian calendar.&lt;br /&gt;
	local Date = getExports(frame)&lt;br /&gt;
	local args = frame:getParent().args&lt;br /&gt;
	local date = Date(args[1], args[2], args[3], args[4], args[5], args[6], args[7])&lt;br /&gt;
	if date then&lt;br /&gt;
		return tostring(date.jd)&lt;br /&gt;
	end&lt;br /&gt;
	return message(&#039;mt-need-valid-ymd-current&#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function timeInterval(frame)&lt;br /&gt;
	-- Implement [[Template:Time interval]].&lt;br /&gt;
	-- There are two positional arguments: date1, date2.&lt;br /&gt;
	-- The default for each is the current date and time.&lt;br /&gt;
	-- Result is date2 - date1 formatted.&lt;br /&gt;
	local Date = getExports(frame)&lt;br /&gt;
	local args = frame:getParent().args&lt;br /&gt;
	local parms = {&lt;br /&gt;
		extra = makeExtra(args),&lt;br /&gt;
		wantDuration = yes[args.duration],&lt;br /&gt;
		range = yes[args.range] or (args.range == &#039;dash&#039; and &#039;dash&#039; or nil),&lt;br /&gt;
		wantSc = yes[args.sc],&lt;br /&gt;
	}&lt;br /&gt;
	local fix = yes[args.fix] and &#039;fix&#039; or &#039;&#039;&lt;br /&gt;
	local date1 = Date(fix, &#039;partial&#039;, stripToNil(args[1]) or &#039;currentdatetime&#039;)&lt;br /&gt;
	if not date1 then&lt;br /&gt;
		return message(&#039;mt-invalid-start&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	local date2 = Date(fix, &#039;partial&#039;, stripToNil(args[2]) or &#039;currentdatetime&#039;)&lt;br /&gt;
	if not date2 then&lt;br /&gt;
		return message(&#039;mt-invalid-end&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	parms.diff = date2 - date1&lt;br /&gt;
	for argname, translate in pairs(translateParameters) do&lt;br /&gt;
		local parm = stripToNil(args[argname])&lt;br /&gt;
		if parm then&lt;br /&gt;
			parm = translate[parm]&lt;br /&gt;
			if parm == nil then  -- test for nil because false is a valid setting&lt;br /&gt;
				return message(&#039;mt-bad-param2&#039;, argname, args[argname])&lt;br /&gt;
			end&lt;br /&gt;
			parms[argname] = parm&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if parms.round then&lt;br /&gt;
		local round = parms.round&lt;br /&gt;
		local show = parms.show&lt;br /&gt;
		if round ~= &#039;on&#039; then&lt;br /&gt;
			if show then&lt;br /&gt;
				if show.id ~= round then&lt;br /&gt;
					return message(&#039;mt-conflicting-show&#039;, args.show, args.round)&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				parms.show = translateParameters.show[round]&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		parms.round = true&lt;br /&gt;
	end&lt;br /&gt;
	return from_en(dateDifference(parms))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function templateGeneric(frame)&lt;br /&gt;
	-- Example: {{#invoke:age||template=age_days|1 Apr 1980|1 Apr 2080|format=raw}} → 36525&lt;br /&gt;
	local name = frame.args.template&lt;br /&gt;
	if not name then&lt;br /&gt;
		return message(&#039;mt-template-x&#039;)&lt;br /&gt;
	end&lt;br /&gt;
	return ageGeneric(frame:newChild({title = mw.title.new(name, 10), args = frame.args}))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return {&lt;br /&gt;
	age_generic = ageGeneric,           -- can emulate several age templates&lt;br /&gt;
	birth_date_and_age = bda,           -- 틀:Birth_date_and_age&lt;br /&gt;
	death_date_and_age = dda,           -- 틀:Death_date_and_age&lt;br /&gt;
	gsd = dateToGsd,                    -- 틀:Gregorian_serial_date&lt;br /&gt;
	extract = dateExtract,              -- 틀:Extract&lt;br /&gt;
	jd_to_date = jdToDate,              -- 틀:?&lt;br /&gt;
	JULIANDAY = dateToJd,               -- 틀:JULIANDAY&lt;br /&gt;
	time_interval = timeInterval,       -- 틀:Time_interval&lt;br /&gt;
	[&#039;&#039;] = templateGeneric,             -- same as age_generic, but can be invoked directly&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EB%AA%A8%EB%93%88:String&amp;diff=62829</id>
		<title>모듈:String</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EB%AA%A8%EB%93%88:String&amp;diff=62829"/>
		<updated>2026-07-05T15:19:41Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: 한국어 위키백과 https://ko.wikipedia.org/wiki/모듈:String에서 모듈 가져옴&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;--[[&lt;br /&gt;
&lt;br /&gt;
This module is intended to provide access to basic string functions.&lt;br /&gt;
&lt;br /&gt;
Most of the functions provided here can be invoked with named parameters,&lt;br /&gt;
unnamed parameters, or a mixture.  If named parameters are used, Mediawiki will&lt;br /&gt;
automatically remove any leading or trailing whitespace from the parameter.&lt;br /&gt;
Depending on the intended use, it may be advantageous to either preserve or&lt;br /&gt;
remove such whitespace.&lt;br /&gt;
&lt;br /&gt;
Global options&lt;br /&gt;
    ignore_errors: If set to &#039;true&#039; or 1, any error condition will result in&lt;br /&gt;
        an empty string being returned rather than an error message.&lt;br /&gt;
&lt;br /&gt;
    error_category: If an error occurs, specifies the name of a category to&lt;br /&gt;
        include with the error message.  The default category is&lt;br /&gt;
        [Category:Errors reported by Module String].&lt;br /&gt;
&lt;br /&gt;
    no_category: If set to &#039;true&#039; or 1, no category will be added if an error&lt;br /&gt;
        is generated.&lt;br /&gt;
&lt;br /&gt;
Unit tests for this module are available at Module:String/tests.&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local str = {}&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
len&lt;br /&gt;
&lt;br /&gt;
This function returns the length of the target string.&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
{{#invoke:String|len|target_string|}}&lt;br /&gt;
OR&lt;br /&gt;
{{#invoke:String|len|s=target_string}}&lt;br /&gt;
&lt;br /&gt;
Parameters&lt;br /&gt;
    s: The string whose length to report&lt;br /&gt;
&lt;br /&gt;
If invoked using named parameters, Mediawiki will automatically remove any leading or&lt;br /&gt;
trailing whitespace from the target string.&lt;br /&gt;
]]&lt;br /&gt;
function str.len( frame )&lt;br /&gt;
	local new_args = str._getParameters( frame.args, {&#039;s&#039;} )&lt;br /&gt;
	local s = new_args[&#039;s&#039;] or &#039;&#039;&lt;br /&gt;
	return mw.ustring.len( s )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
sub&lt;br /&gt;
&lt;br /&gt;
This function returns a substring of the target string at specified indices.&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
{{#invoke:String|sub|target_string|start_index|end_index}}&lt;br /&gt;
OR&lt;br /&gt;
{{#invoke:String|sub|s=target_string|i=start_index|j=end_index}}&lt;br /&gt;
&lt;br /&gt;
Parameters&lt;br /&gt;
    s: The string to return a subset of&lt;br /&gt;
    i: The fist index of the substring to return, defaults to 1.&lt;br /&gt;
    j: The last index of the string to return, defaults to the last character.&lt;br /&gt;
&lt;br /&gt;
The first character of the string is assigned an index of 1.  If either i or j&lt;br /&gt;
is a negative value, it is interpreted the same as selecting a character by&lt;br /&gt;
counting from the end of the string.  Hence, a value of -1 is the same as&lt;br /&gt;
selecting the last character of the string.&lt;br /&gt;
&lt;br /&gt;
If the requested indices are out of range for the given string, an error is&lt;br /&gt;
reported.&lt;br /&gt;
]]&lt;br /&gt;
function str.sub( frame )&lt;br /&gt;
	local new_args = str._getParameters( frame.args, { &#039;s&#039;, &#039;i&#039;, &#039;j&#039; } )&lt;br /&gt;
	local s = new_args[&#039;s&#039;] or &#039;&#039;&lt;br /&gt;
	local i = tonumber( new_args[&#039;i&#039;] ) or 1&lt;br /&gt;
	local j = tonumber( new_args[&#039;j&#039;] ) or -1&lt;br /&gt;
&lt;br /&gt;
	local len = mw.ustring.len( s )&lt;br /&gt;
&lt;br /&gt;
	-- Convert negatives for range checking&lt;br /&gt;
	if i &amp;lt; 0 then&lt;br /&gt;
		i = len + i + 1&lt;br /&gt;
	end&lt;br /&gt;
	if j &amp;lt; 0 then&lt;br /&gt;
		j = len + j + 1&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if i &amp;gt; len or j &amp;gt; len or i &amp;lt; 1 or j &amp;lt; 1 then&lt;br /&gt;
		return str._error( &#039;String subset index out of range&#039; )&lt;br /&gt;
	end&lt;br /&gt;
	if j &amp;lt; i then&lt;br /&gt;
		return str._error( &#039;String subset indices out of order&#039; )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return mw.ustring.sub( s, i, j )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
This function implements that features of {{str sub old}} and is kept in order&lt;br /&gt;
to maintain these older templates.&lt;br /&gt;
]]&lt;br /&gt;
function str.sublength( frame )&lt;br /&gt;
	local i = tonumber( frame.args.i ) or 0&lt;br /&gt;
	local len = tonumber( frame.args.len )&lt;br /&gt;
	return mw.ustring.sub( frame.args.s, i + 1, len and ( i + len ) )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
_match&lt;br /&gt;
&lt;br /&gt;
This function returns a substring from the source string that matches a&lt;br /&gt;
specified pattern. It is exported for use in other modules&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
strmatch = require(&amp;quot;Module:String&amp;quot;)._match&lt;br /&gt;
sresult = strmatch( s, pattern, start, match, plain, nomatch )&lt;br /&gt;
&lt;br /&gt;
Parameters&lt;br /&gt;
    s: The string to search&lt;br /&gt;
    pattern: The pattern or string to find within the string&lt;br /&gt;
    start: The index within the source string to start the search.  The first&lt;br /&gt;
        character of the string has index 1.  Defaults to 1.&lt;br /&gt;
    match: In some cases it may be possible to make multiple matches on a single&lt;br /&gt;
        string.  This specifies which match to return, where the first match is&lt;br /&gt;
        match= 1.  If a negative number is specified then a match is returned&lt;br /&gt;
        counting from the last match.  Hence match = -1 is the same as requesting&lt;br /&gt;
        the last match.  Defaults to 1.&lt;br /&gt;
    plain: A flag indicating that the pattern should be understood as plain&lt;br /&gt;
        text.  Defaults to false.&lt;br /&gt;
    nomatch: If no match is found, output the &amp;quot;nomatch&amp;quot; value rather than an error.&lt;br /&gt;
&lt;br /&gt;
For information on constructing Lua patterns, a form of [regular expression], see:&lt;br /&gt;
&lt;br /&gt;
* http://www.lua.org/manual/5.1/manual.html#5.4.1&lt;br /&gt;
* http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns&lt;br /&gt;
* http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Ustring_patterns&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
-- This sub-routine is exported for use in other modules&lt;br /&gt;
function str._match( s, pattern, start, match_index, plain_flag, nomatch )&lt;br /&gt;
	if s == &#039;&#039; then&lt;br /&gt;
		return str._error( &#039;Target string is empty&#039; )&lt;br /&gt;
	end&lt;br /&gt;
	if pattern == &#039;&#039; then&lt;br /&gt;
		return str._error( &#039;Pattern string is empty&#039; )&lt;br /&gt;
	end&lt;br /&gt;
	start = tonumber(start) or 1&lt;br /&gt;
	if math.abs(start) &amp;lt; 1 or math.abs(start) &amp;gt; mw.ustring.len( s ) then&lt;br /&gt;
		return str._error( &#039;Requested start is out of range&#039; )&lt;br /&gt;
	end&lt;br /&gt;
	if match_index == 0 then&lt;br /&gt;
		return str._error( &#039;Match index is out of range&#039; )&lt;br /&gt;
	end&lt;br /&gt;
	if plain_flag then&lt;br /&gt;
		pattern = str._escapePattern( pattern )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local result&lt;br /&gt;
	if match_index == 1 then&lt;br /&gt;
		-- Find first match is simple case&lt;br /&gt;
		result = mw.ustring.match( s, pattern, start )&lt;br /&gt;
	else&lt;br /&gt;
		if start &amp;gt; 1 then&lt;br /&gt;
			s = mw.ustring.sub( s, start )&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local iterator = mw.ustring.gmatch(s, pattern)&lt;br /&gt;
		if match_index &amp;gt; 0 then&lt;br /&gt;
			-- Forward search&lt;br /&gt;
			for w in iterator do&lt;br /&gt;
				match_index = match_index - 1&lt;br /&gt;
				if match_index == 0 then&lt;br /&gt;
					result = w&lt;br /&gt;
					break&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			-- Reverse search&lt;br /&gt;
			local result_table = {}&lt;br /&gt;
			local count = 1&lt;br /&gt;
			for w in iterator do&lt;br /&gt;
				result_table[count] = w&lt;br /&gt;
				count = count + 1&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			result = result_table[ count + match_index ]&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if result == nil then&lt;br /&gt;
		if nomatch == nil then&lt;br /&gt;
			return str._error( &#039;Match not found&#039; )&lt;br /&gt;
		else&lt;br /&gt;
			return nomatch&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		return result&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
match&lt;br /&gt;
&lt;br /&gt;
This function returns a substring from the source string that matches a&lt;br /&gt;
specified pattern.&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
{{#invoke:String|match|source_string|pattern_string|start_index|match_number|plain_flag|nomatch_output}}&lt;br /&gt;
OR&lt;br /&gt;
{{#invoke:String|match|s=source_string|pattern=pattern_string|start=start_index&lt;br /&gt;
    |match=match_number|plain=plain_flag|nomatch=nomatch_output}}&lt;br /&gt;
&lt;br /&gt;
Parameters&lt;br /&gt;
    s: The string to search&lt;br /&gt;
    pattern: The pattern or string to find within the string&lt;br /&gt;
    start: The index within the source string to start the search.  The first&lt;br /&gt;
        character of the string has index 1.  Defaults to 1.&lt;br /&gt;
    match: In some cases it may be possible to make multiple matches on a single&lt;br /&gt;
        string.  This specifies which match to return, where the first match is&lt;br /&gt;
        match= 1.  If a negative number is specified then a match is returned&lt;br /&gt;
        counting from the last match.  Hence match = -1 is the same as requesting&lt;br /&gt;
        the last match.  Defaults to 1.&lt;br /&gt;
    plain: A flag indicating that the pattern should be understood as plain&lt;br /&gt;
        text.  Defaults to false.&lt;br /&gt;
    nomatch: If no match is found, output the &amp;quot;nomatch&amp;quot; value rather than an error.&lt;br /&gt;
&lt;br /&gt;
If invoked using named parameters, Mediawiki will automatically remove any leading or&lt;br /&gt;
trailing whitespace from each string.  In some circumstances this is desirable, in&lt;br /&gt;
other cases one may want to preserve the whitespace.&lt;br /&gt;
&lt;br /&gt;
If the match_number or start_index are out of range for the string being queried, then&lt;br /&gt;
this function generates an error.  An error is also generated if no match is found.&lt;br /&gt;
If one adds the parameter ignore_errors=true, then the error will be suppressed and&lt;br /&gt;
an empty string will be returned on any failure.&lt;br /&gt;
&lt;br /&gt;
For information on constructing Lua patterns, a form of [regular expression], see:&lt;br /&gt;
&lt;br /&gt;
* http://www.lua.org/manual/5.1/manual.html#5.4.1&lt;br /&gt;
* http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns&lt;br /&gt;
* http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Ustring_patterns&lt;br /&gt;
&lt;br /&gt;
]]&lt;br /&gt;
-- This is the entry point for #invoke:String|match&lt;br /&gt;
function str.match( frame )&lt;br /&gt;
	local new_args = str._getParameters( frame.args, {&#039;s&#039;, &#039;pattern&#039;, &#039;start&#039;, &#039;match&#039;, &#039;plain&#039;, &#039;nomatch&#039;} )&lt;br /&gt;
	local s = new_args[&#039;s&#039;] or &#039;&#039;&lt;br /&gt;
	local start = tonumber( new_args[&#039;start&#039;] ) or 1&lt;br /&gt;
	local plain_flag = str._getBoolean( new_args[&#039;plain&#039;] or false )&lt;br /&gt;
	local pattern = new_args[&#039;pattern&#039;] or &#039;&#039;&lt;br /&gt;
	local match_index = math.floor( tonumber(new_args[&#039;match&#039;]) or 1 )&lt;br /&gt;
	local nomatch = new_args[&#039;nomatch&#039;]&lt;br /&gt;
&lt;br /&gt;
	return str._match( s, pattern, start, match_index, plain_flag, nomatch )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
pos&lt;br /&gt;
&lt;br /&gt;
This function returns a single character from the target string at position pos.&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
{{#invoke:String|pos|target_string|index_value}}&lt;br /&gt;
OR&lt;br /&gt;
{{#invoke:String|pos|target=target_string|pos=index_value}}&lt;br /&gt;
&lt;br /&gt;
Parameters&lt;br /&gt;
    target: The string to search&lt;br /&gt;
    pos: The index for the character to return&lt;br /&gt;
&lt;br /&gt;
If invoked using named parameters, Mediawiki will automatically remove any leading or&lt;br /&gt;
trailing whitespace from the target string.  In some circumstances this is desirable, in&lt;br /&gt;
other cases one may want to preserve the whitespace.&lt;br /&gt;
&lt;br /&gt;
The first character has an index value of 1.&lt;br /&gt;
&lt;br /&gt;
If one requests a negative value, this function will select a character by counting backwards&lt;br /&gt;
from the end of the string.  In other words pos = -1 is the same as asking for the last character.&lt;br /&gt;
&lt;br /&gt;
A requested value of zero, or a value greater than the length of the string returns an error.&lt;br /&gt;
]]&lt;br /&gt;
function str.pos( frame )&lt;br /&gt;
	local new_args = str._getParameters( frame.args, {&#039;target&#039;, &#039;pos&#039;} )&lt;br /&gt;
	local target_str = new_args[&#039;target&#039;] or &#039;&#039;&lt;br /&gt;
	local pos = tonumber( new_args[&#039;pos&#039;] ) or 0&lt;br /&gt;
&lt;br /&gt;
	if pos == 0 or math.abs(pos) &amp;gt; mw.ustring.len( target_str ) then&lt;br /&gt;
		return str._error( &#039;String index out of range&#039; )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return mw.ustring.sub( target_str, pos, pos )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
str_find&lt;br /&gt;
&lt;br /&gt;
This function duplicates the behavior of {{str_find}}, including all of its quirks.&lt;br /&gt;
This is provided in order to support existing templates, but is NOT RECOMMENDED for&lt;br /&gt;
new code and templates.  New code is recommended to use the &amp;quot;find&amp;quot; function instead.&lt;br /&gt;
&lt;br /&gt;
Returns the first index in &amp;quot;source&amp;quot; that is a match to &amp;quot;target&amp;quot;.  Indexing is 1-based,&lt;br /&gt;
and the function returns -1 if the &amp;quot;target&amp;quot; string is not present in &amp;quot;source&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Important Note: If the &amp;quot;target&amp;quot; string is empty / missing, this function returns a&lt;br /&gt;
value of &amp;quot;1&amp;quot;, which is generally unexpected behavior, and must be accounted for&lt;br /&gt;
separatetly.&lt;br /&gt;
]]&lt;br /&gt;
function str.str_find( frame )&lt;br /&gt;
	local new_args = str._getParameters( frame.args, {&#039;source&#039;, &#039;target&#039;} )&lt;br /&gt;
	local source_str = new_args[&#039;source&#039;] or &#039;&#039;&lt;br /&gt;
	local target_str = new_args[&#039;target&#039;] or &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
	if target_str == &#039;&#039; then&lt;br /&gt;
		return 1&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local start = mw.ustring.find( source_str, target_str, 1, true )&lt;br /&gt;
	if start == nil then&lt;br /&gt;
		start = -1&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return start&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
find&lt;br /&gt;
&lt;br /&gt;
This function allows one to search for a target string or pattern within another&lt;br /&gt;
string.&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
{{#invoke:String|find|source_str|target_string|start_index|plain_flag}}&lt;br /&gt;
OR&lt;br /&gt;
{{#invoke:String|find|source=source_str|target=target_str|start=start_index|plain=plain_flag}}&lt;br /&gt;
&lt;br /&gt;
Parameters&lt;br /&gt;
    source: The string to search&lt;br /&gt;
    target: The string or pattern to find within source&lt;br /&gt;
    start: The index within the source string to start the search, defaults to 1&lt;br /&gt;
    plain: Boolean flag indicating that target should be understood as plain&lt;br /&gt;
        text and not as a Lua style regular expression, defaults to true&lt;br /&gt;
&lt;br /&gt;
If invoked using named parameters, Mediawiki will automatically remove any leading or&lt;br /&gt;
trailing whitespace from the parameter.  In some circumstances this is desirable, in&lt;br /&gt;
other cases one may want to preserve the whitespace.&lt;br /&gt;
&lt;br /&gt;
This function returns the first index &amp;gt;= &amp;quot;start&amp;quot; where &amp;quot;target&amp;quot; can be found&lt;br /&gt;
within &amp;quot;source&amp;quot;.  Indices are 1-based.  If &amp;quot;target&amp;quot; is not found, then this&lt;br /&gt;
function returns 0.  If either &amp;quot;source&amp;quot; or &amp;quot;target&amp;quot; are missing / empty, this&lt;br /&gt;
function also returns 0.&lt;br /&gt;
&lt;br /&gt;
This function should be safe for UTF-8 strings.&lt;br /&gt;
]]&lt;br /&gt;
function str.find( frame )&lt;br /&gt;
	local new_args = str._getParameters( frame.args, {&#039;source&#039;, &#039;target&#039;, &#039;start&#039;, &#039;plain&#039; } )&lt;br /&gt;
	local source_str = new_args[&#039;source&#039;] or &#039;&#039;&lt;br /&gt;
	local pattern = new_args[&#039;target&#039;] or &#039;&#039;&lt;br /&gt;
	local start_pos = tonumber(new_args[&#039;start&#039;]) or 1&lt;br /&gt;
	local plain = new_args[&#039;plain&#039;] or true&lt;br /&gt;
&lt;br /&gt;
	if source_str == &#039;&#039; or pattern == &#039;&#039; then&lt;br /&gt;
		return 0&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	plain = str._getBoolean( plain )&lt;br /&gt;
&lt;br /&gt;
	local start = mw.ustring.find( source_str, pattern, start_pos, plain )&lt;br /&gt;
	if start == nil then&lt;br /&gt;
		start = 0&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return start&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
replace&lt;br /&gt;
&lt;br /&gt;
This function allows one to replace a target string or pattern within another&lt;br /&gt;
string.&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
{{#invoke:String|replace|source_str|pattern_string|replace_string|replacement_count|plain_flag}}&lt;br /&gt;
OR&lt;br /&gt;
{{#invoke:String|replace|source=source_string|pattern=pattern_string|replace=replace_string|&lt;br /&gt;
   count=replacement_count|plain=plain_flag}}&lt;br /&gt;
&lt;br /&gt;
Parameters&lt;br /&gt;
    source: The string to search&lt;br /&gt;
    pattern: The string or pattern to find within source&lt;br /&gt;
    replace: The replacement text&lt;br /&gt;
    count: The number of occurences to replace, defaults to all.&lt;br /&gt;
    plain: Boolean flag indicating that pattern should be understood as plain&lt;br /&gt;
        text and not as a Lua style regular expression, defaults to true&lt;br /&gt;
]]&lt;br /&gt;
function str.replace( frame )&lt;br /&gt;
	local new_args = str._getParameters( frame.args, {&#039;source&#039;, &#039;pattern&#039;, &#039;replace&#039;, &#039;count&#039;, &#039;plain&#039; } )&lt;br /&gt;
	local source_str = new_args[&#039;source&#039;] or &#039;&#039;&lt;br /&gt;
	local pattern = new_args[&#039;pattern&#039;] or &#039;&#039;&lt;br /&gt;
	local replace = new_args[&#039;replace&#039;] or &#039;&#039;&lt;br /&gt;
	local count = tonumber( new_args[&#039;count&#039;] )&lt;br /&gt;
	local plain = new_args[&#039;plain&#039;] or true&lt;br /&gt;
&lt;br /&gt;
	if source_str == &#039;&#039; or pattern == &#039;&#039; then&lt;br /&gt;
		return source_str&lt;br /&gt;
	end&lt;br /&gt;
	plain = str._getBoolean( plain )&lt;br /&gt;
&lt;br /&gt;
	if plain then&lt;br /&gt;
		pattern = str._escapePattern( pattern )&lt;br /&gt;
		replace = mw.ustring.gsub( replace, &amp;quot;%%&amp;quot;, &amp;quot;%%%%&amp;quot; ) --Only need to escape replacement sequences.&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local result&lt;br /&gt;
&lt;br /&gt;
	if count ~= nil then&lt;br /&gt;
		result = mw.ustring.gsub( source_str, pattern, replace, count )&lt;br /&gt;
	else&lt;br /&gt;
		result = mw.ustring.gsub( source_str, pattern, replace )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return result&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
    simple function to pipe string.rep to templates.&lt;br /&gt;
]]&lt;br /&gt;
function str.rep( frame )&lt;br /&gt;
	local repetitions = tonumber( frame.args[2] )&lt;br /&gt;
	if not repetitions then&lt;br /&gt;
		return str._error( &#039;function rep expects a number as second parameter, received &amp;quot;&#039; .. ( frame.args[2] or &#039;&#039; ) .. &#039;&amp;quot;&#039; )&lt;br /&gt;
	end&lt;br /&gt;
	return string.rep( frame.args[1] or &#039;&#039;, repetitions )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
escapePattern&lt;br /&gt;
&lt;br /&gt;
This function escapes special characters from a Lua string pattern. See [1]&lt;br /&gt;
for details on how patterns work.&lt;br /&gt;
&lt;br /&gt;
[1] https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
{{#invoke:String|escapePattern|pattern_string}}&lt;br /&gt;
&lt;br /&gt;
Parameters&lt;br /&gt;
    pattern_string: The pattern string to escape.&lt;br /&gt;
]]&lt;br /&gt;
function str.escapePattern( frame )&lt;br /&gt;
	local pattern_str = frame.args[1]&lt;br /&gt;
	if not pattern_str then&lt;br /&gt;
		return str._error( &#039;No pattern string specified&#039; )&lt;br /&gt;
	end&lt;br /&gt;
	local result = str._escapePattern( pattern_str )&lt;br /&gt;
	return result&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
count&lt;br /&gt;
This function counts the number of occurrences of one string in another.&lt;br /&gt;
]]&lt;br /&gt;
function str.count(frame)&lt;br /&gt;
	local args = str._getParameters(frame.args, {&#039;source&#039;, &#039;pattern&#039;, &#039;plain&#039;})&lt;br /&gt;
	local source = args.source or &#039;&#039;&lt;br /&gt;
	local pattern = args.pattern or &#039;&#039;&lt;br /&gt;
	local plain = str._getBoolean(args.plain or true)&lt;br /&gt;
	if plain then&lt;br /&gt;
		pattern = str._escapePattern(pattern)&lt;br /&gt;
	end&lt;br /&gt;
	local _, count = mw.ustring.gsub(source, pattern, &#039;&#039;)&lt;br /&gt;
	return count&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
endswith&lt;br /&gt;
This function determines whether a string ends with another string.&lt;br /&gt;
]]&lt;br /&gt;
function str.endswith(frame)&lt;br /&gt;
	local args = str._getParameters(frame.args, {&#039;source&#039;, &#039;pattern&#039;})&lt;br /&gt;
	local source = args.source or &#039;&#039;&lt;br /&gt;
	local pattern = args.pattern or &#039;&#039;&lt;br /&gt;
	if pattern == &#039;&#039; then&lt;br /&gt;
		-- All strings end with the empty string.&lt;br /&gt;
		return &amp;quot;yes&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	if mw.ustring.sub(source, -mw.ustring.len(pattern), -1) == pattern then&lt;br /&gt;
		return &amp;quot;yes&amp;quot;&lt;br /&gt;
	else&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
join&lt;br /&gt;
&lt;br /&gt;
Join all non empty arguments together; the first argument is the separator.&lt;br /&gt;
Usage:&lt;br /&gt;
{{#invoke:String|join|sep|one|two|three}}&lt;br /&gt;
]]&lt;br /&gt;
function str.join(frame)&lt;br /&gt;
	local args = {}&lt;br /&gt;
	local sep&lt;br /&gt;
	for _, v in ipairs( frame.args ) do&lt;br /&gt;
		if sep then&lt;br /&gt;
			if v ~= &#039;&#039; then&lt;br /&gt;
				table.insert(args, v)&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			sep = v&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return table.concat( args, sep or &#039;&#039; )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
Helper function that populates the argument list given that user may need to use a mix of&lt;br /&gt;
named and unnamed parameters.  This is relevant because named parameters are not&lt;br /&gt;
identical to unnamed parameters due to string trimming, and when dealing with strings&lt;br /&gt;
we sometimes want to either preserve or remove that whitespace depending on the application.&lt;br /&gt;
]]&lt;br /&gt;
function str._getParameters( frame_args, arg_list )&lt;br /&gt;
	local new_args = {}&lt;br /&gt;
	local index = 1&lt;br /&gt;
	local value&lt;br /&gt;
&lt;br /&gt;
	for _, arg in ipairs( arg_list ) do&lt;br /&gt;
		value = frame_args[arg]&lt;br /&gt;
		if value == nil then&lt;br /&gt;
			value = frame_args[index]&lt;br /&gt;
			index = index + 1&lt;br /&gt;
		end&lt;br /&gt;
		new_args[arg] = value&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return new_args&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
Helper function to handle error messages.&lt;br /&gt;
]]&lt;br /&gt;
function str._error( error_str )&lt;br /&gt;
	local frame = mw.getCurrentFrame()&lt;br /&gt;
	local error_category = frame.args.error_category or &#039;String 모듈에 의해 보고된 오류&#039;&lt;br /&gt;
	local ignore_errors = frame.args.ignore_errors or false&lt;br /&gt;
	local no_category = frame.args.no_category or false&lt;br /&gt;
&lt;br /&gt;
	if str._getBoolean(ignore_errors) then&lt;br /&gt;
		return &#039;&#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local error_str = &#039;&amp;lt;strong class=&amp;quot;error&amp;quot;&amp;gt;String Module Error: &#039; .. error_str .. &#039;&amp;lt;/strong&amp;gt;&#039;&lt;br /&gt;
	if error_category ~= &#039;&#039; and not str._getBoolean( no_category ) then&lt;br /&gt;
		error_str = &#039;[[Category:&#039; .. error_category .. &#039;]]&#039; .. error_str&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return error_str&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
Helper Function to interpret boolean strings&lt;br /&gt;
]]&lt;br /&gt;
function str._getBoolean( boolean_str )&lt;br /&gt;
	local boolean_value&lt;br /&gt;
&lt;br /&gt;
	if type( boolean_str ) == &#039;string&#039; then&lt;br /&gt;
		boolean_str = boolean_str:lower()&lt;br /&gt;
		if boolean_str == &#039;false&#039; or boolean_str == &#039;no&#039; or boolean_str == &#039;0&#039;&lt;br /&gt;
				or boolean_str == &#039;&#039; then&lt;br /&gt;
			boolean_value = false&lt;br /&gt;
		else&lt;br /&gt;
			boolean_value = true&lt;br /&gt;
		end&lt;br /&gt;
	elseif type( boolean_str ) == &#039;boolean&#039; then&lt;br /&gt;
		boolean_value = boolean_str&lt;br /&gt;
	else&lt;br /&gt;
		error( &#039;No boolean value found&#039; )&lt;br /&gt;
	end&lt;br /&gt;
	return boolean_value&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
Helper function that escapes all pattern characters so that they will be treated&lt;br /&gt;
as plain text.&lt;br /&gt;
]]&lt;br /&gt;
function str._escapePattern( pattern_str )&lt;br /&gt;
	return mw.ustring.gsub( pattern_str, &amp;quot;([%(%)%.%%%+%-%*%?%[%^%$%]])&amp;quot;, &amp;quot;%%%1&amp;quot; )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return str&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Abusefilter-disallowed-wikidata-tracking&amp;diff=62805</id>
		<title>미디어위키:Abusefilter-disallowed-wikidata-tracking</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Abusefilter-disallowed-wikidata-tracking&amp;diff=62805"/>
		<updated>2026-07-05T12:57:44Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Escape template syntax in AbuseFilter disallow message&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;이 문서에는 ITWiki에서 지원하지 않는 &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{위키데이터 속성 추적}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; 틀이 포함되어 있어 저장할 수 없습니다.&lt;br /&gt;
&lt;br /&gt;
해당 틀은 외부 위키에서 사용하는 위키데이터 추적용 틀이며, ITWiki에서는 정상 동작하지 않아 불필요한 추적 분류를 대량으로 생성합니다.&lt;br /&gt;
&lt;br /&gt;
문서에서 &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;{{위키데이터 속성 추적}}&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; 줄을 제거한 뒤 다시 저장해 주세요.&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Abusefilter-disallowed-wikidata-tracking&amp;diff=62804</id>
		<title>미디어위키:Abusefilter-disallowed-wikidata-tracking</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Abusefilter-disallowed-wikidata-tracking&amp;diff=62804"/>
		<updated>2026-07-05T12:55:03Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Add AbuseFilter disallow message for Wikidata tracking template&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;이 문서에는 ITWiki에서 지원하지 않는 &amp;lt;code&amp;gt;{{위키데이터 속성 추적}}&amp;lt;/code&amp;gt; 틀이 포함되어 있어 저장할 수 없습니다.&lt;br /&gt;
&lt;br /&gt;
해당 틀은 외부 위키에서 사용하는 위키데이터 추적용 틀이며, ITWiki에서는 정상 동작하지 않아 불필요한 추적 분류를 대량으로 생성합니다.&lt;br /&gt;
&lt;br /&gt;
문서에서 &amp;lt;code&amp;gt;{{위키데이터 속성 추적}}&amp;lt;/code&amp;gt; 줄을 제거한 뒤 다시 저장해 주세요.&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Sidebar&amp;diff=46951</id>
		<title>미디어위키:Sidebar</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EB%AF%B8%EB%94%94%EC%96%B4%EC%9C%84%ED%82%A4:Sidebar&amp;diff=46951"/>
		<updated>2026-04-13T03:32:03Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: WimaAdvertising sidebar slots AD1/AD2&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* navigation&lt;br /&gt;
** mainpage|mainpage-description&lt;br /&gt;
** recentchanges-url|recentchanges&lt;br /&gt;
&lt;br /&gt;
{{:Sidebar_English}} &lt;br /&gt;
&lt;br /&gt;
{{#ifeq: {{#time:Y-m-d H|now + 9 hours}} | {{#time:Y-m-d H|now||1}} &lt;br /&gt;
| {{:Sidebar_Korean}} &lt;br /&gt;
| {{:Sidebar_English}} &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
* SEARCH&lt;br /&gt;
* TOOLBOX&lt;br /&gt;
* LANGUAGES&lt;br /&gt;
* AD1&lt;br /&gt;
* AD2&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_9%EB%B2%88&amp;diff=37835</id>
		<title>산업안전기사 2022년 2월 9번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_9%EB%B2%88&amp;diff=37835"/>
		<updated>2022-10-21T16:42:37Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 안전관리론&lt;br /&gt;
== 문제 ==&lt;br /&gt;
9. 하인리히의 사고예방원리 5단계 중 교육 및 훈련의 개선, 인사조정, 안전관리규정 및 수칙의 개선 등을 행하는 단계는?&lt;br /&gt;
* ① 사실의 발견&lt;br /&gt;
* ② 분석 평가&lt;br /&gt;
* ③ 시정방법의 선정&lt;br /&gt;
* ④ 시정책의 적용&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21912 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;3번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_99%EB%B2%88&amp;diff=37834</id>
		<title>산업안전기사 2022년 2월 99번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_99%EB%B2%88&amp;diff=37834"/>
		<updated>2022-10-21T16:42:37Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 화학설비위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
99. 메탄, 에탄, 프로판의 폭발하한계가 각각 5vol%, 2vol%, 2.1vol%일 때 다음 중 폭발하한계가 가장 낮은 것은? (단, Le Chatelier의 법칙을 이용한다.)&lt;br /&gt;
* ① 메탄 20vol%, 에탄 30vol%, 프로판 50vol%의 혼합가스&lt;br /&gt;
* ② 메탄 30vol%, 에탄 30vol%, 프로판 40vol%의 혼합가스&lt;br /&gt;
* ③ 메탄 40vol%, 에탄 30vol%, 프로판 30vol%의 혼합가스&lt;br /&gt;
* ④ 메탄 50vol%, 에탄 30vol%, 프로판 20vol%의 혼합가스&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/22001 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;1번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_98%EB%B2%88&amp;diff=37833</id>
		<title>산업안전기사 2022년 2월 98번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_98%EB%B2%88&amp;diff=37833"/>
		<updated>2022-10-21T16:42:37Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 화학설비위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
98. 알루미늄분이 고온의 물과 반응하였을 때 생성되는 가스는?&lt;br /&gt;
* ① 이산화탄소&lt;br /&gt;
* ② 수소&lt;br /&gt;
* ③ 메탄&lt;br /&gt;
* ④ 에탄&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/22000 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;2번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_97%EB%B2%88&amp;diff=37832</id>
		<title>산업안전기사 2022년 2월 97번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_97%EB%B2%88&amp;diff=37832"/>
		<updated>2022-10-21T16:42:37Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 화학설비위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
97. 다음 표의 가스(A~D)를 위험도가 큰 것부터 작은 순으로 나열한 것은?&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;lt;table&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;  &amp;lt;tr&amp;gt;&amp;lt;br /&amp;gt;    &amp;lt;th&amp;gt;　&amp;lt;/th&amp;gt;&amp;lt;br /&amp;gt;    &amp;lt;th&amp;gt;폭발하한값&amp;lt;/th&amp;gt;&amp;lt;br /&amp;gt;    &amp;lt;th&amp;gt;폭발상한값&amp;lt;/th&amp;gt;&amp;lt;br /&amp;gt;  &amp;lt;/tr&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;  &amp;lt;tr&amp;gt;&amp;lt;br /&amp;gt;    &amp;lt;td&amp;gt;A&amp;lt;/td&amp;gt;&amp;lt;br /&amp;gt;    &amp;lt;td&amp;gt;4.0vol%&amp;lt;/td&amp;gt;&amp;lt;br /&amp;gt;    &amp;lt;td&amp;gt;75.0vol%&amp;lt;/td&amp;gt;&amp;lt;br /&amp;gt;  &amp;lt;/tr&amp;gt;&amp;lt;br /&amp;gt;  &amp;lt;tr&amp;gt;&amp;lt;br /&amp;gt;    &amp;lt;td&amp;gt;B&amp;lt;/td&amp;gt;&amp;lt;br /&amp;gt;    &amp;lt;td&amp;gt;3.0vol%&amp;lt;/td&amp;gt;&amp;lt;br /&amp;gt;    &amp;lt;td&amp;gt;80.0vol%&amp;lt;/td&amp;gt;&amp;lt;br /&amp;gt;  &amp;lt;/tr&amp;gt;&amp;lt;br /&amp;gt;  &amp;lt;tr&amp;gt;&amp;lt;br /&amp;gt;    &amp;lt;td&amp;gt;C&amp;lt;/td&amp;gt;&amp;lt;br /&amp;gt;    &amp;lt;td&amp;gt;1.25vol%&amp;lt;/td&amp;gt;&amp;lt;br /&amp;gt;    &amp;lt;td&amp;gt;44.0vol%&amp;lt;/td&amp;gt;&amp;lt;br /&amp;gt;  &amp;lt;/tr&amp;gt;&amp;lt;br /&amp;gt;  &amp;lt;tr&amp;gt;&amp;lt;br /&amp;gt;    &amp;lt;td&amp;gt;D&amp;lt;/td&amp;gt;&amp;lt;br /&amp;gt;    &amp;lt;td&amp;gt;2.5vol%&amp;lt;/td&amp;gt;&amp;lt;br /&amp;gt;    &amp;lt;td&amp;gt;81.0vol%&amp;lt;/td&amp;gt;&amp;lt;br /&amp;gt;  &amp;lt;/tr&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;/table&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* ① D – B – C - A&lt;br /&gt;
* ② D – B – A - C&lt;br /&gt;
* ③ C – D – A - B&lt;br /&gt;
* ④ C – D – B – A&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21999 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;4번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_96%EB%B2%88&amp;diff=37831</id>
		<title>산업안전기사 2022년 2월 96번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_96%EB%B2%88&amp;diff=37831"/>
		<updated>2022-10-21T16:42:37Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 화학설비위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
96. 다음 중 공기 중 최소 발화에너지 값이 가장 작은 물질은?&lt;br /&gt;
* ① 에틸렌&lt;br /&gt;
* ② 아세트알데히드&lt;br /&gt;
* ③ 메탄&lt;br /&gt;
* ④ 에탄&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21998 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;1번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_95%EB%B2%88&amp;diff=37830</id>
		<title>산업안전기사 2022년 2월 95번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_95%EB%B2%88&amp;diff=37830"/>
		<updated>2022-10-21T16:42:37Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 화학설비위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
95. 다음 중 반응기의 구조 방식에 의한 분류에 해당하는 것은?&lt;br /&gt;
* ① 탑형 반응기&lt;br /&gt;
* ② 연속식 반응기&lt;br /&gt;
* ③ 반회분식 반응기&lt;br /&gt;
* ④ 회분식 균일상반응기&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21997 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;1번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_94%EB%B2%88&amp;diff=37829</id>
		<title>산업안전기사 2022년 2월 94번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_94%EB%B2%88&amp;diff=37829"/>
		<updated>2022-10-21T16:42:37Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 화학설비위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
94. 다음 중 열교환기의 보수에 있어 일상점검항목과 정기적 개방점검항목으로 구분할 때 일상점검항목으로 거리가 먼 것은?&lt;br /&gt;
* ① 도장의 노후상황&lt;br /&gt;
* ② 부착물에 의한 오염의 상황&lt;br /&gt;
* ③ 보온재, 보냉재의 파손여부&lt;br /&gt;
* ④ 기초볼트의 체결정도&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21996 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;2번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_93%EB%B2%88&amp;diff=37828</id>
		<title>산업안전기사 2022년 2월 93번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_93%EB%B2%88&amp;diff=37828"/>
		<updated>2022-10-21T16:42:36Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 화학설비위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
93. 위험물의 저장방법으로 적절하지 않은 것은?&lt;br /&gt;
* ① 탄화칼슘은 물 속에 저장한다.&lt;br /&gt;
* ② 벤젠은 산화성 물질과 격리시킨다.&lt;br /&gt;
* ③ 금속나트륨은 석유 속에 저장한다.&lt;br /&gt;
* ④ 질산은 갈색병에 넣어 냉암소에 보관한다.&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21995 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;1번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_92%EB%B2%88&amp;diff=37827</id>
		<title>산업안전기사 2022년 2월 92번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_92%EB%B2%88&amp;diff=37827"/>
		<updated>2022-10-21T16:42:36Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 화학설비위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
92. 액체 표면에서 발생한 증기농도가 공기 중에서 연소하한농도가 될 수 있는 가장 낮은 액체온도를 무엇이라 하는가?&lt;br /&gt;
* ① 인화점&lt;br /&gt;
* ② 비등점&lt;br /&gt;
* ③ 연소점&lt;br /&gt;
* ④ 발화온도&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21994 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;1번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_91%EB%B2%88&amp;diff=37826</id>
		<title>산업안전기사 2022년 2월 91번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_91%EB%B2%88&amp;diff=37826"/>
		<updated>2022-10-21T16:42:36Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 화학설비위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
91. 산업안전보건법령상 다음 인화성 가스의 정의에서 ( ) 안에 알맞은 값은?&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;quot;인화성 가스&amp;quot;란 인화한계 농도의 최저한도가 ( ㉠ )% 이하 또는 최고한도와 최저한도의 차가 ( ㉡ )% 이상인 것으로서 표준압력(101.3kPa), 20℃에서 가스 상태인 물질을 말한다.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* ① ㉠ 13, ㉡ 12&lt;br /&gt;
* ② ㉠ 13, ㉡ 15&lt;br /&gt;
* ③ ㉠ 12, ㉡ 13&lt;br /&gt;
* ④ ㉠ 12, ㉡ 15&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21993 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;1번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_90%EB%B2%88&amp;diff=37825</id>
		<title>산업안전기사 2022년 2월 90번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_90%EB%B2%88&amp;diff=37825"/>
		<updated>2022-10-21T16:42:36Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 화학설비위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
90. 열교환탱크 외부를 두께 0.2m의 단열재(열전도율 k=0.037 kcal/m·h·℃)로 보온하였더니 단열재 내면은 40℃, 외면은 20℃ 이었다. 면적 1m&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt; 당 1시간에 손실되는 열량(kcal)은?&lt;br /&gt;
* ① 0.0037&lt;br /&gt;
* ② 0.037&lt;br /&gt;
* ③ 1.37&lt;br /&gt;
* ④ 3.7&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21992 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;4번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_8%EB%B2%88&amp;diff=37824</id>
		<title>산업안전기사 2022년 2월 8번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_8%EB%B2%88&amp;diff=37824"/>
		<updated>2022-10-21T16:42:36Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 안전관리론&lt;br /&gt;
== 문제 ==&lt;br /&gt;
8. 억측판단이 발생하는 배경으로 볼 수 없는 것은?&lt;br /&gt;
* ① 정보가 불확실할 때&lt;br /&gt;
* ② 타인의 의견에 동조할 때&lt;br /&gt;
* ③ 희망적인 관측이 있을 때&lt;br /&gt;
* ④ 과거에 성공한 경험이 있을 때&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21910 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;2번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_89%EB%B2%88&amp;diff=37823</id>
		<title>산업안전기사 2022년 2월 89번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_89%EB%B2%88&amp;diff=37823"/>
		<updated>2022-10-21T16:42:36Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 화학설비위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
89. 사업주는 인화성 액체 및 인화성 가스를 저장 취급하는 화학설비에서 증기나 가스를 대기로 방출하는 경우에는 외부로부터의 화염을 방지하기 위하여 화염방지기를 설치하여야 한다. 다음 중 화염방지기의 설치 위치로 옳은 것은?&lt;br /&gt;
* ① 설비의 상단&lt;br /&gt;
* ② 설비의 하단&lt;br /&gt;
* ③ 설비의 측면&lt;br /&gt;
* ④ 설비의 조작부&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21991 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;1번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_88%EB%B2%88&amp;diff=37822</id>
		<title>산업안전기사 2022년 2월 88번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_88%EB%B2%88&amp;diff=37822"/>
		<updated>2022-10-21T16:42:36Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 화학설비위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
88. 크롬에 대한 설명으로 옳은 것은?&lt;br /&gt;
* ① 은백색 광택이 있는 금속이다.&lt;br /&gt;
* ② 중독 시 미나마타병이 발병한다.&lt;br /&gt;
* ③ 비중이 물보다 작은 값을 나타낸다.&lt;br /&gt;
* ④ 3가 크롬이 인체에 가장 유해하다.&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21990 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;1번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_87%EB%B2%88&amp;diff=37821</id>
		<title>산업안전기사 2022년 2월 87번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_87%EB%B2%88&amp;diff=37821"/>
		<updated>2022-10-21T16:42:35Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 화학설비위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
87. 분진폭발의 특징으로 옳은 것은?&lt;br /&gt;
* ① 연소속도가 가스폭발보다 크다.&lt;br /&gt;
* ② 완전연소로 가스중독의 위험이 작다.&lt;br /&gt;
* ③ 화염의 파급속도보다 압력의 파급속도가 빠르다.&lt;br /&gt;
* ④ 가스폭발보다 연소시간은 짧고 발생에너지는 작다.&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21989 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;3번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_86%EB%B2%88&amp;diff=37820</id>
		<title>산업안전기사 2022년 2월 86번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_86%EB%B2%88&amp;diff=37820"/>
		<updated>2022-10-21T16:42:35Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 화학설비위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
86. 질화면(Nitrocellulose)은 저장·취급 중에는 에틸알코올 등으로 습면상태를 유지해야 한다. 그 이유를 옳게 설명한 것은?&lt;br /&gt;
* ① 질화면은 건조 상태에서는 자연적으로 분해하면서 발화할 위험이 있기 때문이다.&lt;br /&gt;
* ② 질화면은 알코올과 반응하여 안정한 물질을 만들기 때문이다.&lt;br /&gt;
* ③ 질화면은 건조 상태에서 공기 중의 산소와 환원반응을 하기 때문이다.&lt;br /&gt;
* ④ 질화면은 건조 상태에서 유독한 중합물을 형성하기 때문이다.&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21988 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;1번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_85%EB%B2%88&amp;diff=37819</id>
		<title>산업안전기사 2022년 2월 85번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_85%EB%B2%88&amp;diff=37819"/>
		<updated>2022-10-21T16:42:35Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 화학설비위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
85. 다음중 폭발 방호 대책과 가장 거리가 먼 것은?&lt;br /&gt;
* ① 불활성화&lt;br /&gt;
* ② 억제&lt;br /&gt;
* ③ 방산&lt;br /&gt;
* ④ 봉쇄&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21987 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;1번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_84%EB%B2%88&amp;diff=37818</id>
		<title>산업안전기사 2022년 2월 84번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_84%EB%B2%88&amp;diff=37818"/>
		<updated>2022-10-21T16:42:35Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 화학설비위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
84. 가스를 분류할 때 독성가스에 해당하지 않는 것은?&lt;br /&gt;
* ① 황화수소&lt;br /&gt;
* ② 시안화수소&lt;br /&gt;
* ③ 이산화탄소&lt;br /&gt;
* ④ 산화에틸렌&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21986 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;3번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_83%EB%B2%88&amp;diff=37817</id>
		<title>산업안전기사 2022년 2월 83번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_83%EB%B2%88&amp;diff=37817"/>
		<updated>2022-10-21T16:42:35Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 화학설비위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
83. 폭발한계와 완전 연소 조정 관계인 Jones식을 이용하여 부탄(C&amp;lt;sub&amp;gt;4&amp;lt;/sub&amp;gt;H&amp;lt;sub&amp;gt;10&amp;lt;/sub&amp;gt;)의 폭발하한계를 구하면 몇 vol% 인가?&lt;br /&gt;
* ① 1.4&lt;br /&gt;
* ② 1.7&lt;br /&gt;
* ③ 2.0&lt;br /&gt;
* ④ 2.3&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21985 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;2번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_82%EB%B2%88&amp;diff=37816</id>
		<title>산업안전기사 2022년 2월 82번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_82%EB%B2%88&amp;diff=37816"/>
		<updated>2022-10-21T16:42:35Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 화학설비위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
82. 다음 중 퍼지(purge)의 종류에 해당하지 않는 것은?&lt;br /&gt;
* ① 압력퍼지&lt;br /&gt;
* ② 진공퍼지&lt;br /&gt;
* ③ 스위프퍼지&lt;br /&gt;
* ④ 가열퍼지&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21984 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;4번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_81%EB%B2%88&amp;diff=37815</id>
		<title>산업안전기사 2022년 2월 81번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_81%EB%B2%88&amp;diff=37815"/>
		<updated>2022-10-21T16:42:35Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 화학설비위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
81. 산업안전보건법에서 정한 위험물질을 기준량 이상 제조하거나 취급하는 화학설비로서 내부의 이상상태를 조기에 파악히기 위하여 필요한 온도계·유량계·압력계 등의 계측자잋를 설치하여야 하는 대상이 아닌 것은?&lt;br /&gt;
* ① 가열로 또는 가열기&lt;br /&gt;
* ② 증류·정류·증발·추출 등 분리를 하는 장치&lt;br /&gt;
* ③ 반응폭주 등 이상 화학반응에 의하여 위험물질이 발생할 우려가 있는 설비&lt;br /&gt;
* ④ 흡열반응이 일어나는 반응장치&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21983 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;4번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_80%EB%B2%88&amp;diff=37814</id>
		<title>산업안전기사 2022년 2월 80번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_80%EB%B2%88&amp;diff=37814"/>
		<updated>2022-10-21T16:42:34Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 전기위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
80. 정전기로 인한 화재 폭발의 위험이 가장 높은 것은?&lt;br /&gt;
* ① 드라이클리닝설비&lt;br /&gt;
* ② 농작물 건조기&lt;br /&gt;
* ③ 가습기&lt;br /&gt;
* ④ 전동기&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21982 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;1번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_7%EB%B2%88&amp;diff=37813</id>
		<title>산업안전기사 2022년 2월 7번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_7%EB%B2%88&amp;diff=37813"/>
		<updated>2022-10-21T16:42:34Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 안전관리론&lt;br /&gt;
== 문제 ==&lt;br /&gt;
7. 산업안전보건법령상 안전보건관리규정 작성 시 포함되어야 하는 사항을 모두 고른 것은? (단, 그 밖에 안전 및 보건에 관한 사항은 제외한다.)&lt;br /&gt;
&amp;lt;blockquote&amp;gt;ㄱ. 안전보건교육에 관한 사항&amp;lt;br /&amp;gt;ㄴ. 재해사례 연구·토의결과에 관한 사항&amp;lt;br /&amp;gt;ㄷ. 사고 조사 및 대책 수립에 관한 사항&amp;lt;br /&amp;gt;ㄹ. 작업장의 안전 및 보건 관리에 관한 사항&amp;lt;br /&amp;gt;ㅁ. 안전 및 보건에 관한 관리 조직과 그 직무에 관한 사항&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* ① ㄱ, ㄴ, ㄷ, ㄹ&lt;br /&gt;
* ② ㄱ, ㄴ, ㄹ, ㅁ&lt;br /&gt;
* ③ ㄱ, ㄷ, ㄹ, ㅁ&lt;br /&gt;
* ④ ㄴ, ㄷ, ㄹ, ㅁ&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21909 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;3번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_79%EB%B2%88&amp;diff=37812</id>
		<title>산업안전기사 2022년 2월 79번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_79%EB%B2%88&amp;diff=37812"/>
		<updated>2022-10-21T16:42:34Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 전기위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
79. 정전작업 시 조치사항으로 틀린 것은?&lt;br /&gt;
* ① 작업 전 전기설비의 잔류 전하를 확실히 방전한다.&lt;br /&gt;
* ② 개로된 전로의 충전여부를 검전기구에 의하여 확인한다.&lt;br /&gt;
* ③ 개폐기에 잠금장치를 하고 통전금지에 관한 표지판은 제거한다.&lt;br /&gt;
* ④ 예비 동력원의 역송전에 의한 감전의 위험을 방지하기 위해 단락접지 기구를 사용하여 단락 접지를 한다.&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21981 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;3번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_78%EB%B2%88&amp;diff=37811</id>
		<title>산업안전기사 2022년 2월 78번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_78%EB%B2%88&amp;diff=37811"/>
		<updated>2022-10-21T16:42:34Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 전기위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
78. 산업안전보건기준에 관한 규칙에 따른 전기기계·기구에 설치 시 고려할 사항으로 거리가 먼 것은?&lt;br /&gt;
* ① 전기기계·기구의 충분한 전기적 용량 및 기계적 강도&lt;br /&gt;
* ② 전기기계·기구의 안전효율을 높이기 위한 시간 가동율&lt;br /&gt;
* ③ 습기·분진 등 사용장소의 주위 환경&lt;br /&gt;
* ④ 전기적·기계적 방호수단의 적정성&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21980 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;2번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_77%EB%B2%88&amp;diff=37810</id>
		<title>산업안전기사 2022년 2월 77번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_77%EB%B2%88&amp;diff=37810"/>
		<updated>2022-10-21T16:42:34Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 전기위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
77. 심실세동 전류 I＝165 / √t(㎃)라면 심실세동 시 인체에 직접 받는 전기에너지(cal)는 약 얼마인가? (단, t는 통전시간으로 1초이며, 인체의 저항은 500Ω으로 한다.)&lt;br /&gt;
* ① 0.52&lt;br /&gt;
* ② 1.35&lt;br /&gt;
* ③ 2.14&lt;br /&gt;
* ④ 3.27&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21979 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;4번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_76%EB%B2%88&amp;diff=37809</id>
		<title>산업안전기사 2022년 2월 76번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_76%EB%B2%88&amp;diff=37809"/>
		<updated>2022-10-21T16:42:34Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 전기위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
76. 다음 중 방폭구조의 종류가 아닌 것은?&lt;br /&gt;
* ① 본질안전 방폭구조&lt;br /&gt;
* ② 고압 방폭구조&lt;br /&gt;
* ③ 압력 방폭구조&lt;br /&gt;
* ④ 내압 방폭구조&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21978 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;2번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_75%EB%B2%88&amp;diff=37808</id>
		<title>산업안전기사 2022년 2월 75번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_75%EB%B2%88&amp;diff=37808"/>
		<updated>2022-10-21T16:42:34Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 전기위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
75. 다음 설명이 나타내는 현상은?&lt;br /&gt;
&amp;lt;blockquote&amp;gt;전압이 인가된 이극 도체 간의 고체 절연물 표면에 이물질이 부착되면 미소방전이 일어난다. 이 미소방전이 반복되면서 절연물 표면에 도전성 통로가 형성되는 현상이다.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
* ① 흑연화현상&lt;br /&gt;
* ② 트래킹현상&lt;br /&gt;
* ③ 반단선현상&lt;br /&gt;
* ④ 절연이동현상&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21977 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;2번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_74%EB%B2%88&amp;diff=37807</id>
		<title>산업안전기사 2022년 2월 74번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_74%EB%B2%88&amp;diff=37807"/>
		<updated>2022-10-21T16:42:34Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 전기위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
74. 다음 중 산업안전보건기준에 관한 규칙에 따라 누전차단기를 설치하지 않아도 되는 곳은?&lt;br /&gt;
* ① 철판·철골 위 등 도전성이 높은 장소에서 사용하는 이동형 전기기계·기구&lt;br /&gt;
* ② 대지전아이 220V인 휴대형 전기기계·기구&lt;br /&gt;
* ③ 임시배선이 전로가 설치되는 장소에서 사용하는 이동형 전기기계·기구&lt;br /&gt;
* ④ 절연대 위에서 사용하는 전기기계·기구&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21976 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;4번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_73%EB%B2%88&amp;diff=37806</id>
		<title>산업안전기사 2022년 2월 73번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_73%EB%B2%88&amp;diff=37806"/>
		<updated>2022-10-21T16:42:33Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 전기위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
73. 다음 중 기기보호등급(EPL)에 해당하지 않는 것은?&lt;br /&gt;
* ① EPL Ga&lt;br /&gt;
* ② EPL Ma&lt;br /&gt;
* ③ EPL Dc&lt;br /&gt;
* ④ EPL Mc&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21975 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;4번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_72%EB%B2%88&amp;diff=37805</id>
		<title>산업안전기사 2022년 2월 72번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_72%EB%B2%88&amp;diff=37805"/>
		<updated>2022-10-21T16:42:33Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 전기위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
72. 아크방전의 전압전류 특성으로 가장 옳은 것은?&lt;br /&gt;
* ① &lt;br /&gt;
* ② &lt;br /&gt;
* ③ &lt;br /&gt;
* ④ &lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21974 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;3번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_71%EB%B2%88&amp;diff=37804</id>
		<title>산업안전기사 2022년 2월 71번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_71%EB%B2%88&amp;diff=37804"/>
		<updated>2022-10-21T16:42:33Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 전기위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
71. 교류 아크용접기의 사용에서 무부하 전압이 80V, 아크 전압 25V, 아크 전류 300A 일 경우 효율은 약 몇 % 인가? (단, 내부손실은 4kW 이다.)&lt;br /&gt;
* ① 65.2&lt;br /&gt;
* ② 70.5&lt;br /&gt;
* ③ 75.3&lt;br /&gt;
* ④ 80.6&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21973 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;1번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_70%EB%B2%88&amp;diff=37803</id>
		<title>산업안전기사 2022년 2월 70번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_70%EB%B2%88&amp;diff=37803"/>
		<updated>2022-10-21T16:42:33Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 전기위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
70. 접지저항 저감 방법으로 틀린 것은?&lt;br /&gt;
* ① 접지극의 병렬 접지를 실시한다.&lt;br /&gt;
* ② 접지극의 매설 깊이를 증가시킨다.&lt;br /&gt;
* ③ 접지극의 크기를 최대한 작게 한다.&lt;br /&gt;
* ④ 접지극 주변의 토양을 개량하여 대지 저항률을 떨어뜨린다.&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21972 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;3번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_6%EB%B2%88&amp;diff=37802</id>
		<title>산업안전기사 2022년 2월 6번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_6%EB%B2%88&amp;diff=37802"/>
		<updated>2022-10-21T16:42:33Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 안전관리론&lt;br /&gt;
== 문제 ==&lt;br /&gt;
6. 산업재해의 분석 및 평가를 위하여 재해발생 건수 등의 추이에 대해 한계선을 설정하여 목표 관리를 수행하는 재해통계 분석기법은?&lt;br /&gt;
* ① 관리도&lt;br /&gt;
* ② 안전 T점수&lt;br /&gt;
* ③ 파레토도&lt;br /&gt;
* ④ 특성 요인도&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21908 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;1번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_69%EB%B2%88&amp;diff=37801</id>
		<title>산업안전기사 2022년 2월 69번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_69%EB%B2%88&amp;diff=37801"/>
		<updated>2022-10-21T16:42:33Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 전기위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
69. 피뢰기로서 갖추어야 할 성능 중 틀린 것은?&lt;br /&gt;
* ① 충격 방전 개시전압이 낮을 것&lt;br /&gt;
* ② 뇌전류 방전 능력이 클 것&lt;br /&gt;
* ③ 제한전압이 높을 것&lt;br /&gt;
* ④ 속류 차단을 확실하게 할 수 있을 것&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21971 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;3번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_68%EB%B2%88&amp;diff=37800</id>
		<title>산업안전기사 2022년 2월 68번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_68%EB%B2%88&amp;diff=37800"/>
		<updated>2022-10-21T16:42:33Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 전기위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
68. 전기기기, 설비 및 전선로 등의 충전 유무 등을 확인하기 위한 장비는?&lt;br /&gt;
* ① 위상검출기&lt;br /&gt;
* ② 디스콘 스위치&lt;br /&gt;
* ③ COS&lt;br /&gt;
* ④ 저압 및 고압용 검전기&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21970 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;4번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_67%EB%B2%88&amp;diff=37799</id>
		<title>산업안전기사 2022년 2월 67번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_67%EB%B2%88&amp;diff=37799"/>
		<updated>2022-10-21T16:42:32Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 전기위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
67. 정전기 발생에 영향을 주는 요인에 대한 설명으로 틀린 것은?&lt;br /&gt;
* ① 물체의 분리속도가 빠를수록 발생량은 적어진다.&lt;br /&gt;
* ② 접촉면적이 크고 접촉압력이 높을수록 발생량이 많아진다.&lt;br /&gt;
* ③ 물체 표면이 수분이나 기름으로 오염되면 산화 및 부식에 의해 발생량이 많아진다.&lt;br /&gt;
* ④ 정전기의 발생은 처음 접촉, 분리할 때가 최대로 되고 접촉, 분리가 반복됨에 따라 발생량은 감소한다.&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21969 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;1번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_66%EB%B2%88&amp;diff=37798</id>
		<title>산업안전기사 2022년 2월 66번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_66%EB%B2%88&amp;diff=37798"/>
		<updated>2022-10-21T16:42:32Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 전기위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
66. 다음 중 방폭설비의 보호등급(IP)에 대한 설명으로 옳은 것은?&lt;br /&gt;
* ① 제1 특성 숫자가 “1”인 경우 지름 50mm 이상의 외부 분진에 대한 보호&lt;br /&gt;
* ② 제1 특성 숫자가 “2”인 경우 지름 10mm 이상의 외부 분진에 대한 보호&lt;br /&gt;
* ③ 제2 특성 숫자가 “1”인 경우 지름 50mm 이상의 외부 분진에 대한 보호&lt;br /&gt;
* ④ 제2 특성 숫자가 “2”인 경우 지름 10mm 이상의 외부 분진에 대한 보호&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21968 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;1번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_65%EB%B2%88&amp;diff=37797</id>
		<title>산업안전기사 2022년 2월 65번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_65%EB%B2%88&amp;diff=37797"/>
		<updated>2022-10-21T16:42:32Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 전기위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
65. 한국전기설비규정에 따라 사람이 쉽게 접촉할 우려가 있는 곳에 금속제 외함을 가지는 저압의 기계기구가 시설되어 있다. 이 기계기구의 사용전압이 몇 V를 초과할 때 전기를 공급하는 전로에 누전차단기를 시설해야 하는가? (단, 누전차단기를 시설하지 않아도 되는 조건은 제외한다.)&lt;br /&gt;
* ① 30V&lt;br /&gt;
* ② 40V&lt;br /&gt;
* ③ 50V&lt;br /&gt;
* ④ 60V&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21967 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;3번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_64%EB%B2%88&amp;diff=37796</id>
		<title>산업안전기사 2022년 2월 64번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_64%EB%B2%88&amp;diff=37796"/>
		<updated>2022-10-21T16:42:32Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 전기위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
64. 정전기 재해방지에 관한 설명 중 틀린 것은?&lt;br /&gt;
* ① 이황화탄소의 수송 과정에서 배관 내의 유속을 2.5m/s 이상으로 한다.&lt;br /&gt;
* ② 포장 과정에서 용기를 도전성 재료에 접지한다.&lt;br /&gt;
* ③ 인쇄 과정에서 도포량을 소량으로 하고 접지한다.&lt;br /&gt;
* ④ 작업장의 습도를 높여 전하가 제거되기 쉽게 한다.&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21966 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;1번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_63%EB%B2%88&amp;diff=37795</id>
		<title>산업안전기사 2022년 2월 63번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_63%EB%B2%88&amp;diff=37795"/>
		<updated>2022-10-21T16:42:32Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 전기위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
63. 설비의 이상현상에 나타나는 아크(Arc)의 종류가 아닌 것은?&lt;br /&gt;
* ① 단락에 의한 아크&lt;br /&gt;
* ② 지락에 의한 아크&lt;br /&gt;
* ③ 차단기에서의 아크&lt;br /&gt;
* ④ 전선저항에 의한 아크&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21965 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;4번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_62%EB%B2%88&amp;diff=37794</id>
		<title>산업안전기사 2022년 2월 62번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_62%EB%B2%88&amp;diff=37794"/>
		<updated>2022-10-21T16:42:32Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 전기위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
62. KS C IEC 60079-10-2에 따라 공기 중에 분진운의 형태로 폭발성 분진 분위기가 지속적으로 또는 장기간 또는 빈번히 존재하는 장소는?&lt;br /&gt;
* ① 0종 장소&lt;br /&gt;
* ② 1종 장소&lt;br /&gt;
* ③ 20종 장소&lt;br /&gt;
* ④ 21종 장소&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21964 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;3번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_61%EB%B2%88&amp;diff=37793</id>
		<title>산업안전기사 2022년 2월 61번</title>
		<link rel="alternate" type="text/html" href="https://devhrxoobm.itwiki.kr/index.php?title=%EC%82%B0%EC%97%85%EC%95%88%EC%A0%84%EA%B8%B0%EC%82%AC_2022%EB%85%84_2%EC%9B%94_61%EB%B2%88&amp;diff=37793"/>
		<updated>2022-10-21T16:42:32Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Imported from text file&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[분류:기출문제]][[분류:산업안전기사]]&lt;br /&gt;
과목: 전기위험방지기술&lt;br /&gt;
== 문제 ==&lt;br /&gt;
61. 대지에서 용접작업을 하고 있는 작업자가 용접봉에 접촉한 경우 통전전류는? (단, 용접기의 출력 측 무부하전압 : 90v, 접촉저항(손, 용접봉 등 포함) : 10kΩ, 인체의 내부저항 : 1kΩ, 발과 대지의 접촉저항 : 20kΩ 이다.)&lt;br /&gt;
* ① 약 0.19 mA&lt;br /&gt;
* ② 약 0.29 mA&lt;br /&gt;
* ③ 약 1.96 mA&lt;br /&gt;
* ④ 약 2.90 mA&lt;br /&gt;
== 풀어보기 ==&lt;br /&gt;
* [https://q.fran.kr/문제/21963 해당 문제 풀어보기]&lt;br /&gt;
* [https://q.fran.kr/시험/산업안전기사/2022년_2월 산업안전기사 2022년 2월 시험 풀기]&lt;br /&gt;
== 정답 ==&lt;br /&gt;
* &#039;&#039;&#039;4번&#039;&#039;&#039;&lt;br /&gt;
== 해설 ==&lt;br /&gt;
&lt;br /&gt;
== 같이 보기 ==&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
</feed>