<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://wiki.democracycraft.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=AmityBlamity</id>
	<title>DemocracyCraft Wiki - User contributions [en-gb]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.democracycraft.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=AmityBlamity"/>
	<link rel="alternate" type="text/html" href="https://wiki.democracycraft.net/Special:Contributions/AmityBlamity"/>
	<updated>2026-04-15T11:39:37Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.1</generator>
	<entry>
		<id>https://wiki.democracycraft.net/index.php?title=List_of_magistrates&amp;diff=6521</id>
		<title>List of magistrates</title>
		<link rel="alternate" type="text/html" href="https://wiki.democracycraft.net/index.php?title=List_of_magistrates&amp;diff=6521"/>
		<updated>2025-07-19T19:48:24Z</updated>

		<summary type="html">&lt;p&gt;AmityBlamity: Added auto updating number of days&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Magistrates are the name of the [[judicial officers]] that preside over the [[District Court]]. They are appointed by the [[Supreme Court]].&amp;lt;ref&amp;gt;https://www.democracycraft.net/threads/constitution.6/ Sections 15 and 21.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The position of magistrate was created on 10 June 2021 with the ratification of the [https://www.democracycraft.net/threads/judicial%E2%80%8C-%E2%80%8Crestructuring%E2%80%8C-%E2%80%8Camendment.6231/ Judicial Restructuring Amendment Act].&amp;lt;ref name=&amp;quot;:02&amp;quot;&amp;gt;https://www.democracycraft.net/threads/referendum-for-the-judicial-restructuring-amendment-act.6532/&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;https://www.democracycraft.net/threads/judicial%E2%80%8C-%E2%80%8Crestructuring%E2%80%8C-%E2%80%8Camendment.6231/&amp;lt;/ref&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Note: dates are in UTC. &lt;br /&gt;
&lt;br /&gt;
== Magistrates of the District Court ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Number&lt;br /&gt;
!Magistrate&lt;br /&gt;
!Date of appointment&lt;br /&gt;
!End of tenure (Reason)&lt;br /&gt;
!Tenure length&lt;br /&gt;
!Highest ranking prior position in the judiciary&lt;br /&gt;
!Ref.&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|[[wuutie]]&lt;br /&gt;
|10 July 2021&lt;br /&gt;
|5 October 2021 (Continued as judge)&lt;br /&gt;
|87 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/673612908868927498/686158870435201035/863546399773294632 [[File:Wuutie_magistrate_appointment.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/794283346565922847/894779409540739092 https://discord.com/channels/794162227837534208/794283346565922847/894780168948817931 [[File:Wuutie_judge_nomination.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|[[dygyee]]&lt;br /&gt;
|30 September 2021&lt;br /&gt;
|9 April 2022 (Continued as judge)&lt;br /&gt;
|191 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/673612908868927498/686158870435201035/892948693987246080 [[File:Dygyee_magistrate_appointment.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/962119066544390284 https://discord.com/channels/794162227837534208/918003510795202640/962302649674366996 [[File:Dygyee_judge_nomination.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|[[BananaNova]]&lt;br /&gt;
|5 December 2021&lt;br /&gt;
|10 June 2022 (Continued as judge)&lt;br /&gt;
|187 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/673612908868927498/686158870435201035/916872456394932264 [[File:BananaNova_magistrate_appointment.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/984685138396983336 https://discord.com/channels/794162227837534208/918003510795202640/984852984921980948 [[File:Bananamuffinmc_(banananova)_judge_nomination.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|[[Nacholebraa]]&lt;br /&gt;
|17 April 2022&lt;br /&gt;
|2 July 2022 (Continued as judge)&lt;br /&gt;
|76 days&lt;br /&gt;
|Judge&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/965295602466447440&lt;br /&gt;
&lt;br /&gt;
[[File:Nacholebraa magistrate appointment.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref name=&amp;quot;:6&amp;quot;&amp;gt;Screenshot taken in EST: https://discord.com/channels/673612908868927498/686158870435201035/774333278726783037 [[File:Judge_nacholebraa_confirmation_announcement.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/990986495080923217 https://discord.com/channels/794162227837534208/918003510795202640/991090595550339112 [[File:Nacholebraa_judge_nomination.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|[[Kanne]]&lt;br /&gt;
|29 May 2022&lt;br /&gt;
|9 August 2022 (Resigned)&lt;br /&gt;
|72 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/980516181045809193&lt;br /&gt;
&lt;br /&gt;
[[File:Kanne magistrate appointment.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/794162227837534208/918003510795202640/1006612133867433994&amp;lt;nowiki/&amp;gt;https://discord.com/channels/794162227837534208/918003510795202640/1006689199845556224[[File:Xlayzur CRB and Kanne attorney general nomination.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|6&lt;br /&gt;
|[[Aladeen22]]&lt;br /&gt;
|4 July 2022&lt;br /&gt;
|6 or 7 November 2022. It is most likely that he resigned on the 7th in order to run in an election.&lt;br /&gt;
|125 or 126 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/673612908868927498/686158870435201035/993576135143198840 [[File:Aladeen22_magistrate_appointment.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST&lt;br /&gt;
&lt;br /&gt;
Aladeen22&#039;s final in-game message as a magistrate on 7 November 2022 (UTC) before they were reappointed in 2024.&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686103036057485318/1038985104875343983[[File:Er89tuhwuehrih5.png]]&lt;br /&gt;
&lt;br /&gt;
Aladeen22&#039;s first in-game message as something other than magistrate after that previous message&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686103036057485318/1039370061984571454&lt;br /&gt;
&lt;br /&gt;
[[File:As9us8v89fdf.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Aladeen22&#039;s declaration for the House of Representatives on 7 November 2022 (UTC).https://www.democracycraft.net/threads/house-of-representatives-elections-november-2022.15056/post-56259&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|7&lt;br /&gt;
|[[Dartanboy]]&lt;br /&gt;
|6 December 2022&lt;br /&gt;
|20 March 2023 (Resigned)&lt;br /&gt;
|104 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1049737694990835855&lt;br /&gt;
&lt;br /&gt;
[[File:Dartanboy solicitor general resignation edit time.png]]&lt;br /&gt;
&lt;br /&gt;
[[File:Dartanboy solicitor general resignation.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1087259492527382568&lt;br /&gt;
&lt;br /&gt;
[[File:Dartanman Dartanboy Public Defenders Program Director appointment.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|[[Mask3D_WOLF]]&lt;br /&gt;
|24 July 2023&lt;br /&gt;
|Between 19 and 29 February 2024 (Fired)&lt;br /&gt;
|210 to 220 days&lt;br /&gt;
|Judge&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1133017800210907258&lt;br /&gt;
&lt;br /&gt;
[[File:Mask3D WOLF magistrate appointment 1.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref name=&amp;quot;:0&amp;quot;&amp;gt;Screenshots taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1117150109017309306 https://discord.com/channels/794162227837534208/918003510795202640/1117210234306445424 [[File:Mask3D_WOLF_Judge_nomination.png|[[File:Mask3D WOLF Judge nomination votes.png]]]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
Mask3D_WOLF&#039;s final message as a magistrate, and their first message without the magistrate tag after their final message as a magistrate.&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686103036057485318/1209197468177141861&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686103036057485318/1215869740967399455[[File:8s9dugdusf.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Filed 29 February 2024 (UTC). &lt;br /&gt;
&lt;br /&gt;
https://www.democracycraft.net/threads/mask3d_wolf-v-commonwealth-of-redmont-2024-fcr-28.20410/&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|9&lt;br /&gt;
|[[RelaxedGV]]&lt;br /&gt;
|15 September 2023&lt;br /&gt;
|Unknown&lt;br /&gt;
|Unknown&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1152331726190813266&lt;br /&gt;
&lt;br /&gt;
[[File:RelaxedGV magistrate appointment.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt; &lt;br /&gt;
|-&lt;br /&gt;
|10&lt;br /&gt;
|[[ko531]]&lt;br /&gt;
|28 November 2023&lt;br /&gt;
|23 February 2024 (Fired)&lt;br /&gt;
|87 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref name=&amp;quot;:1&amp;quot;&amp;gt;Screenshot taken in CST&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/901465377895251988/1395644755311984660[[File:Ko531 magistrate appointment 1.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in CST&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/901465377895251988/1395642991204372520[[File:Ko531 magistrate firing message.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|11&lt;br /&gt;
|[[xtub12345]]&lt;br /&gt;
|17 March 2024&lt;br /&gt;
|28 June 2024 (Resigned)&lt;br /&gt;
|103 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1219031400150466652&lt;br /&gt;
&lt;br /&gt;
[[File:Xtub12345 magistrate appointment and Taelor court clerk appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1256311971868053504&lt;br /&gt;
&lt;br /&gt;
[[File:Xtub12345 magistrate resignation.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|12&lt;br /&gt;
|Aladeen22&lt;br /&gt;
|14 July 2025&lt;br /&gt;
|15 August 2024 (Resigned)&lt;br /&gt;
|32 days&lt;br /&gt;
|Judge&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1263646850624389234&lt;br /&gt;
&lt;br /&gt;
[[File:19 July 2024 house special election announcement.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1063381292214910998 [[File:Aladeen22_judge_nomination.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1064034944726343781 [[File:Aladeen22_judge_nomination_passing.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in GMT-5&lt;br /&gt;
&lt;br /&gt;
[[File:Aladeen magistrate resignation 2024.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref name=&amp;quot;:2&amp;quot;&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1262055468407197748&lt;br /&gt;
[[File:Aladeen22 and xAntho ny magistrate appointment.png|thumb]]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|12&lt;br /&gt;
|[[xAntho_ny]]&lt;br /&gt;
|14 July 2025&lt;br /&gt;
|Unknown&lt;br /&gt;
|Unknown&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref name=&amp;quot;:2&amp;quot; /&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|14&lt;br /&gt;
|[[Jakovus]]&lt;br /&gt;
|15 September 2024&lt;br /&gt;
|30 October 2024 (Continued as judge)&lt;br /&gt;
|45 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1284827968249532436&lt;br /&gt;
&lt;br /&gt;
[[File:Jakovus magistrate appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1301187947206283275 [[File:Jakovus_judge_nomination.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|15&lt;br /&gt;
|ko531&lt;br /&gt;
|27 October 2024&lt;br /&gt;
|14 May 2025 (Continued as judge)&lt;br /&gt;
|199 days&lt;br /&gt;
|Magistrate&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1300175019384639609&lt;br /&gt;
&lt;br /&gt;
[[File:Ko531 magistrate appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1371308258165395466 [[File:Ko531_judge_nomination_.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref name=&amp;quot;:1&amp;quot; /&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|Mask3D_WOLF&lt;br /&gt;
|26 January 2025&lt;br /&gt;
|7 April 2025 (Fired)&lt;br /&gt;
|71 days&lt;br /&gt;
|Judge&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1332897754078384198&lt;br /&gt;
&lt;br /&gt;
[[File:Mask3D WOLF magistrate appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref name=&amp;quot;:0&amp;quot; /&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/901465377895251988/1395630886652739625&lt;br /&gt;
&lt;br /&gt;
[[File:Ahsd8v8ud.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|17&lt;br /&gt;
|[[JunkCereal]]&lt;br /&gt;
|4 June 2025&lt;br /&gt;
|16 July 2025 (Continued as judge)&lt;br /&gt;
|42 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1379945184925847613&lt;br /&gt;
&lt;br /&gt;
[[File:JunkCereal magistrate appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1394090359138684970 [[File:JunkCereal_judge_nomination_.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|18&lt;br /&gt;
|[[AmityBlamity]]&lt;br /&gt;
|3 July 2025&lt;br /&gt;
|Current&lt;br /&gt;
|{{Age in days|3 July 2025}} days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1390426816057049109&lt;br /&gt;
&lt;br /&gt;
[[File:AmityBlamity magistrate appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
If the images are overlapping, zoom out and try refreshing.&lt;/div&gt;</summary>
		<author><name>AmityBlamity</name></author>
	</entry>
	<entry>
		<id>https://wiki.democracycraft.net/index.php?title=Template:Age_in_days&amp;diff=6520</id>
		<title>Template:Age in days</title>
		<link rel="alternate" type="text/html" href="https://wiki.democracycraft.net/index.php?title=Template:Age_in_days&amp;diff=6520"/>
		<updated>2025-07-19T19:40:57Z</updated>

		<summary type="html">&lt;p&gt;AmityBlamity: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;{{#invoke:age|age_generic|template=age_days}}&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;{{documentation}}&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>AmityBlamity</name></author>
	</entry>
	<entry>
		<id>https://wiki.democracycraft.net/index.php?title=Module:Age&amp;diff=6519</id>
		<title>Module:Age</title>
		<link rel="alternate" type="text/html" href="https://wiki.democracycraft.net/index.php?title=Module:Age&amp;diff=6519"/>
		<updated>2025-07-19T19:38:40Z</updated>

		<summary type="html">&lt;p&gt;AmityBlamity: &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;Parameter $1=$2 is invalid&#039;,&lt;br /&gt;
	[&#039;mt-bad-show&#039;] =               &#039;Parameter show=$1 is not supported here&#039;,&lt;br /&gt;
	[&#039;mt-cannot-add&#039;] =             &#039;Cannot add &amp;quot;$1&amp;quot;&#039;,&lt;br /&gt;
	[&#039;mt-conflicting-show&#039;] =       &#039;Parameter show=$1 conflicts with round=$2&#039;,&lt;br /&gt;
	[&#039;mt-date-wrong-order&#039;] =       &#039;The second date must be later in time than the first date&#039;,&lt;br /&gt;
	[&#039;mt-dd-future&#039;] =              &#039;Death date (first date) must not be in the future&#039;,&lt;br /&gt;
	[&#039;mt-dd-wrong-order&#039;] =         &#039;Death date (first date) must be later in time than the birth date (second date)&#039;,&lt;br /&gt;
	[&#039;mt-invalid-bd-age&#039;] =         &#039;Invalid birth date for calculating age&#039;,&lt;br /&gt;
	[&#039;mt-invalid-dates-age&#039;] =      &#039;Invalid dates for calculating age&#039;,&lt;br /&gt;
	[&#039;mt-invalid-end&#039;] =            &#039;Invalid end date in second parameter&#039;,&lt;br /&gt;
	[&#039;mt-invalid-start&#039;] =          &#039;Invalid start date in first parameter&#039;,&lt;br /&gt;
	[&#039;mt-need-jdn&#039;] =               &#039;Need valid Julian date number&#039;,&lt;br /&gt;
	[&#039;mt-need-valid-bd&#039;] =          &#039;Need valid birth date: year, month, day&#039;,&lt;br /&gt;
	[&#039;mt-need-valid-bd2&#039;] =         &#039;Need valid birth date (second date): year, month, day&#039;,&lt;br /&gt;
	[&#039;mt-need-valid-date&#039;] =        &#039;Need valid date&#039;,&lt;br /&gt;
	[&#039;mt-need-valid-dd&#039;] =          &#039;Need valid death date (first date): year, month, day&#039;,&lt;br /&gt;
	[&#039;mt-need-valid-ymd&#039;] =         &#039;Need valid year, month, day&#039;,&lt;br /&gt;
	[&#039;mt-need-valid-ymd-current&#039;] = &#039;Need valid year|month|day or &amp;quot;currentdate&amp;quot;&#039;,&lt;br /&gt;
	[&#039;mt-need-valid-ymd2&#039;] =        &#039;Second date should be year, month, day&#039;,&lt;br /&gt;
	[&#039;mt-template-bad-name&#039;] =      &#039;The specified template name is not valid&#039;,&lt;br /&gt;
	[&#039;mt-template-x&#039;] =             &#039;The template invoking this must have &amp;quot;|template=x&amp;quot; where x is the wanted operation&#039;,&lt;br /&gt;
	[&#039;mt-warn-param1&#039;] =            &#039;Invalid parameter $1&#039;,&lt;br /&gt;
	[&#039;mt-warn-param2&#039;] =            &#039;Parameter $1=$2 is invalid&#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; and &#039;,&lt;br /&gt;
	[&#039;txt-or&#039;] =                    &#039;&amp;amp;nbsp;or &#039;,&lt;br /&gt;
	[&#039;txt-category&#039;] =              &#039;Category:Age error&#039;,&lt;br /&gt;
	[&#039;txt-comma-and&#039;] =             &#039;, and &#039;,&lt;br /&gt;
	[&#039;txt-error&#039;] =                 &#039;Error: &#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;Module:ConvertNumeric&#039;,&lt;br /&gt;
	[&#039;txt-module-date&#039;] =           &#039;Module:Date&#039;,&lt;br /&gt;
	[&#039;txt-sandbox&#039;] =               &#039;sandbox&#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; (age&amp;amp;nbsp;$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; (aged&amp;amp;nbsp;$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;
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)&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 problem&lt;br /&gt;
	local wanted = mtext[&#039;txt-format-default&#039;]&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;&amp;amp;nbsp;&#039;,&lt;br /&gt;
			y = {&#039;year&#039;, &#039;years&#039;},&lt;br /&gt;
			m = {&#039;month&#039;, &#039;months&#039;},&lt;br /&gt;
			w = {&#039;week&#039;, &#039;weeks&#039;},&lt;br /&gt;
			d = {&#039;day&#039;, &#039;days&#039;},&lt;br /&gt;
			H = {&#039;hour&#039;, &#039;hours&#039;},&lt;br /&gt;
			M = {&#039;minute&#039;, &#039;minutes&#039;},&lt;br /&gt;
			S = {&#039;second&#039;, &#039;seconds&#039;},&lt;br /&gt;
		},&lt;br /&gt;
		abbr_on = {&lt;br /&gt;
			y = &#039;y&#039;,&lt;br /&gt;
			m = &#039;m&#039;,&lt;br /&gt;
			w = &#039;w&#039;,&lt;br /&gt;
			d = &#039;d&#039;,&lt;br /&gt;
			H = &#039;h&#039;,&lt;br /&gt;
			M = &#039;m&#039;,&lt;br /&gt;
			S = &#039;s&#039;,&lt;br /&gt;
		},&lt;br /&gt;
		abbr_infant = {      -- for {{age for infant}}&lt;br /&gt;
			sep = &#039;&amp;amp;nbsp;&#039;,&lt;br /&gt;
			y = {&#039;yr&#039;, &#039;yrs&#039;},&lt;br /&gt;
			m = {&#039;mo&#039;, &#039;mos&#039;},&lt;br /&gt;
			w = {&#039;wk&#039;, &#039;wks&#039;},&lt;br /&gt;
			d = {&#039;day&#039;, &#039;days&#039;},&lt;br /&gt;
			H = {&#039;hr&#039;, &#039;hrs&#039;},&lt;br /&gt;
			M = {&#039;min&#039;, &#039;mins&#039;},&lt;br /&gt;
			S = {&#039;sec&#039;, &#039;secs&#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.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; 150 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)&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; 150 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)&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;
	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,           -- Template:Birth_date_and_age&lt;br /&gt;
	death_date_and_age = dda,           -- Template:Death_date_and_age&lt;br /&gt;
	gsd = dateToGsd,                    -- Template:Gregorian_serial_date&lt;br /&gt;
	extract = dateExtract,              -- Template:Extract&lt;br /&gt;
	jd_to_date = jdToDate,              -- Template:?&lt;br /&gt;
	JULIANDAY = dateToJd,               -- Template:JULIANDAY&lt;br /&gt;
	time_interval = timeInterval,       -- Template: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>AmityBlamity</name></author>
	</entry>
	<entry>
		<id>https://wiki.democracycraft.net/index.php?title=Module:Date&amp;diff=6518</id>
		<title>Module:Date</title>
		<link rel="alternate" type="text/html" href="https://wiki.democracycraft.net/index.php?title=Module:Date&amp;diff=6518"/>
		<updated>2025-07-19T19:38:17Z</updated>

		<summary type="html">&lt;p&gt;AmityBlamity: &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, {&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;
-- A table to get the current date/time (UTC), but only if needed.&lt;br /&gt;
local current = setmetatable({}, {&lt;br /&gt;
	__index = function (self, key)&lt;br /&gt;
		local d = os.date(&#039;!*t&#039;)&lt;br /&gt;
		self.year = d.year&lt;br /&gt;
		self.month = d.month&lt;br /&gt;
		self.day = d.day&lt;br /&gt;
		self.hour = d.hour&lt;br /&gt;
		self.minute = d.min&lt;br /&gt;
		self.second = d.sec&lt;br /&gt;
		return rawget(self, key)&lt;br /&gt;
	end })&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.minute&lt;br /&gt;
			newdate.second = current.second&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>AmityBlamity</name></author>
	</entry>
	<entry>
		<id>https://wiki.democracycraft.net/index.php?title=Module:ConvertNumeric&amp;diff=6517</id>
		<title>Module:ConvertNumeric</title>
		<link rel="alternate" type="text/html" href="https://wiki.democracycraft.net/index.php?title=Module:ConvertNumeric&amp;diff=6517"/>
		<updated>2025-07-19T19:37:43Z</updated>

		<summary type="html">&lt;p&gt;AmityBlamity: Adding ConvertNumeric module from Wikipedia&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>AmityBlamity</name></author>
	</entry>
	<entry>
		<id>https://wiki.democracycraft.net/index.php?title=List_of_magistrates&amp;diff=6505</id>
		<title>List of magistrates</title>
		<link rel="alternate" type="text/html" href="https://wiki.democracycraft.net/index.php?title=List_of_magistrates&amp;diff=6505"/>
		<updated>2025-07-19T16:55:21Z</updated>

		<summary type="html">&lt;p&gt;AmityBlamity: /* Magistrates of the District Court */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Magistrates are the name of the [[judicial officers]] that preside over the [[District Court]]. They are appointed by the [[Supreme Court]].&amp;lt;ref&amp;gt;https://www.democracycraft.net/threads/constitution.6/ Sections 15 and 21.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The position of magistrate was created on 10 June 2021 with the ratification of the [https://www.democracycraft.net/threads/judicial%E2%80%8C-%E2%80%8Crestructuring%E2%80%8C-%E2%80%8Camendment.6231/ Judicial Restructuring Amendment Act].&amp;lt;ref name=&amp;quot;:02&amp;quot;&amp;gt;https://www.democracycraft.net/threads/referendum-for-the-judicial-restructuring-amendment-act.6532/&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;https://www.democracycraft.net/threads/judicial%E2%80%8C-%E2%80%8Crestructuring%E2%80%8C-%E2%80%8Camendment.6231/&amp;lt;/ref&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Note: dates are in UTC. &lt;br /&gt;
&lt;br /&gt;
== Magistrates of the District Court ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Number&lt;br /&gt;
!Magistrate&lt;br /&gt;
!Date of appointment&lt;br /&gt;
!End of tenure (Reason)&lt;br /&gt;
!Tenure length&lt;br /&gt;
!Highest ranking prior position in the judiciary&lt;br /&gt;
!Ref.&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|[[wuutie]]&lt;br /&gt;
|10 July 2021&lt;br /&gt;
|5 October 2021 (Continued as judge)&lt;br /&gt;
|87 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/673612908868927498/686158870435201035/863546399773294632 [[File:Wuutie_magistrate_appointment.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/794283346565922847/894779409540739092 https://discord.com/channels/794162227837534208/794283346565922847/894780168948817931 [[File:Wuutie_judge_nomination.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|[[dygyee]]&lt;br /&gt;
|30 September 2021&lt;br /&gt;
|9 April 2022 (Continued as judge)&lt;br /&gt;
|191 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/673612908868927498/686158870435201035/892948693987246080 [[File:Dygyee_magistrate_appointment.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/962119066544390284 https://discord.com/channels/794162227837534208/918003510795202640/962302649674366996 [[File:Dygyee_judge_nomination.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|[[BananaNova]]&lt;br /&gt;
|5 December 2021&lt;br /&gt;
|10 June 2022 (Continued as judge)&lt;br /&gt;
|187 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/673612908868927498/686158870435201035/916872456394932264 [[File:BananaNova_magistrate_appointment.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/984685138396983336 https://discord.com/channels/794162227837534208/918003510795202640/984852984921980948 [[File:Bananamuffinmc_(banananova)_judge_nomination.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|[[Nacholebraa]]&lt;br /&gt;
|17 April 2022&lt;br /&gt;
|2 July 2022 (Continued as judge)&lt;br /&gt;
|76 days&lt;br /&gt;
|Judge&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/965295602466447440&lt;br /&gt;
&lt;br /&gt;
[[File:Nacholebraa magistrate appointment.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref name=&amp;quot;:6&amp;quot;&amp;gt;Screenshot taken in EST: https://discord.com/channels/673612908868927498/686158870435201035/774333278726783037 [[File:Judge_nacholebraa_confirmation_announcement.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/990986495080923217 https://discord.com/channels/794162227837534208/918003510795202640/991090595550339112 [[File:Nacholebraa_judge_nomination.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|[[Kanne]]&lt;br /&gt;
|29 May 2022&lt;br /&gt;
|9 August 2022 (Resigned)&lt;br /&gt;
|72 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/980516181045809193&lt;br /&gt;
&lt;br /&gt;
[[File:Kanne magistrate appointment.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/794162227837534208/918003510795202640/1006612133867433994&amp;lt;nowiki/&amp;gt;https://discord.com/channels/794162227837534208/918003510795202640/1006689199845556224[[File:Xlayzur CRB and Kanne attorney general nomination.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|6&lt;br /&gt;
|[[Aladeen22]]&lt;br /&gt;
|4 July 2022&lt;br /&gt;
|6 or 7 November 2022. It is most likely that he resigned on the 7th in order to run in an election.&lt;br /&gt;
|125 or 126 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/673612908868927498/686158870435201035/993576135143198840 [[File:Aladeen22_magistrate_appointment.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST&lt;br /&gt;
&lt;br /&gt;
Aladeen22&#039;s final in-game message as a magistrate on 7 November 2022 (UTC) before they were reappointed in 2024.&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686103036057485318/1038985104875343983[[File:Er89tuhwuehrih5.png]]&lt;br /&gt;
&lt;br /&gt;
Aladeen22&#039;s first in-game message as something other than magistrate after that previous message&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686103036057485318/1039370061984571454&lt;br /&gt;
&lt;br /&gt;
[[File:As9us8v89fdf.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Aladeen22&#039;s declaration for the House of Representatives on 7 November 2022 (UTC).https://www.democracycraft.net/threads/house-of-representatives-elections-november-2022.15056/post-56259&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|7&lt;br /&gt;
|[[Dartanboy]]&lt;br /&gt;
|6 December 2022&lt;br /&gt;
|20 March 2023 (Resigned)&lt;br /&gt;
|104 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1049737694990835855&lt;br /&gt;
&lt;br /&gt;
[[File:Dartanboy solicitor general resignation edit time.png]]&lt;br /&gt;
&lt;br /&gt;
[[File:Dartanboy solicitor general resignation.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1087259492527382568&lt;br /&gt;
&lt;br /&gt;
[[File:Dartanman Dartanboy Public Defenders Program Director appointment.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|[[Mask3D_WOLF]]&lt;br /&gt;
|24 July 2023&lt;br /&gt;
|Between 19 and 29 February 2024 (Fired)&lt;br /&gt;
|210 to 220 days&lt;br /&gt;
|Judge&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1133017800210907258&lt;br /&gt;
&lt;br /&gt;
[[File:Mask3D WOLF magistrate appointment 1.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref name=&amp;quot;:0&amp;quot;&amp;gt;Screenshots taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1117150109017309306 https://discord.com/channels/794162227837534208/918003510795202640/1117210234306445424 [[File:Mask3D_WOLF_Judge_nomination.png|[[File:Mask3D WOLF Judge nomination votes.png]]]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
Mask3D_WOLF&#039;s final message as a magistrate, and their first message without the magistrate tag after their final message as a magistrate.&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686103036057485318/1209197468177141861&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686103036057485318/1215869740967399455[[File:8s9dugdusf.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Filed 29 February 2024 (UTC). &lt;br /&gt;
&lt;br /&gt;
https://www.democracycraft.net/threads/mask3d_wolf-v-commonwealth-of-redmont-2024-fcr-28.20410/&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|9&lt;br /&gt;
|[[RelaxedGV]]&lt;br /&gt;
|15 September 2023&lt;br /&gt;
|Unknown&lt;br /&gt;
|Unknown&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1152331726190813266&lt;br /&gt;
&lt;br /&gt;
[[File:RelaxedGV magistrate appointment.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt; &lt;br /&gt;
|-&lt;br /&gt;
|10&lt;br /&gt;
|[[ko531]]&lt;br /&gt;
|28 November 2023&lt;br /&gt;
|23 February 2024 (Fired)&lt;br /&gt;
|87 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref name=&amp;quot;:1&amp;quot;&amp;gt;Screenshot taken in CST&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/901465377895251988/1395644755311984660[[File:Ko531 magistrate appointment 1.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in CST&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/901465377895251988/1395642991204372520[[File:Ko531 magistrate firing message.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|11&lt;br /&gt;
|[[xtub12345]]&lt;br /&gt;
|17 March 2024&lt;br /&gt;
|28 June 2024 (Resigned)&lt;br /&gt;
|103 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1219031400150466652&lt;br /&gt;
&lt;br /&gt;
[[File:Xtub12345 magistrate appointment and Taelor court clerk appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1256311971868053504&lt;br /&gt;
&lt;br /&gt;
[[File:Xtub12345 magistrate resignation.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|12&lt;br /&gt;
|Aladeen22&lt;br /&gt;
|14 July 2025&lt;br /&gt;
|15 August 2024 (Resigned)&lt;br /&gt;
|32 days&lt;br /&gt;
|Judge&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1263646850624389234&lt;br /&gt;
&lt;br /&gt;
[[File:19 July 2024 house special election announcement.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1063381292214910998 [[File:Aladeen22_judge_nomination.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1064034944726343781 [[File:Aladeen22_judge_nomination_passing.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in GMT-5&lt;br /&gt;
&lt;br /&gt;
[[File:Aladeen magistrate resignation 2024.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref name=&amp;quot;:2&amp;quot;&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1262055468407197748&lt;br /&gt;
[[File:Aladeen22 and xAntho ny magistrate appointment.png|thumb]]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|12&lt;br /&gt;
|[[xAntho_ny]]&lt;br /&gt;
|14 July 2025&lt;br /&gt;
|Unknown&lt;br /&gt;
|Unknown&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref name=&amp;quot;:2&amp;quot; /&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|14&lt;br /&gt;
|[[Jakovus]]&lt;br /&gt;
|15 September 2024&lt;br /&gt;
|30 October 2024 (Continued as judge)&lt;br /&gt;
|45 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1284827968249532436&lt;br /&gt;
&lt;br /&gt;
[[File:Jakovus magistrate appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1301187947206283275 [[File:Jakovus_judge_nomination.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|15&lt;br /&gt;
|ko531&lt;br /&gt;
|27 October 2024&lt;br /&gt;
|14 May 2025 (Continued as judge)&lt;br /&gt;
|199 days&lt;br /&gt;
|Magistrate&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1300175019384639609&lt;br /&gt;
&lt;br /&gt;
[[File:Ko531 magistrate appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1371308258165395466 [[File:Ko531_judge_nomination_.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref name=&amp;quot;:1&amp;quot; /&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|Mask3D_WOLF&lt;br /&gt;
|26 January 2025&lt;br /&gt;
|7 April 2025 (Fired)&lt;br /&gt;
|71 days&lt;br /&gt;
|Judge&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1332897754078384198&lt;br /&gt;
&lt;br /&gt;
[[File:Mask3D WOLF magistrate appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref name=&amp;quot;:0&amp;quot; /&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/901465377895251988/1395630886652739625&lt;br /&gt;
&lt;br /&gt;
[[File:Ahsd8v8ud.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|17&lt;br /&gt;
|[[JunkCereal]]&lt;br /&gt;
|4 June 2025&lt;br /&gt;
|16 July 2025 (Continued as judge)&lt;br /&gt;
|42 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1379945184925847613&lt;br /&gt;
&lt;br /&gt;
[[File:JunkCereal magistrate appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1394090359138684970 [[File:JunkCereal_judge_nomination_.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|18&lt;br /&gt;
|[[AmityBlamity]]&lt;br /&gt;
|3 July 2025&lt;br /&gt;
|Current&lt;br /&gt;
|16 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1390426816057049109&lt;br /&gt;
&lt;br /&gt;
[[File:AmityBlamity magistrate appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
If the images are overlapping, zoom out and try refreshing.&lt;/div&gt;</summary>
		<author><name>AmityBlamity</name></author>
	</entry>
	<entry>
		<id>https://wiki.democracycraft.net/index.php?title=Template:Age_in_days&amp;diff=6504</id>
		<title>Template:Age in days</title>
		<link rel="alternate" type="text/html" href="https://wiki.democracycraft.net/index.php?title=Template:Age_in_days&amp;diff=6504"/>
		<updated>2025-07-19T16:53:31Z</updated>

		<summary type="html">&lt;p&gt;AmityBlamity: Blanked the page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>AmityBlamity</name></author>
	</entry>
	<entry>
		<id>https://wiki.democracycraft.net/index.php?title=Module:ConvertNumeric&amp;diff=6503</id>
		<title>Module:ConvertNumeric</title>
		<link rel="alternate" type="text/html" href="https://wiki.democracycraft.net/index.php?title=Module:ConvertNumeric&amp;diff=6503"/>
		<updated>2025-07-19T16:53:24Z</updated>

		<summary type="html">&lt;p&gt;AmityBlamity: Blanked the page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>AmityBlamity</name></author>
	</entry>
	<entry>
		<id>https://wiki.democracycraft.net/index.php?title=Module:Date&amp;diff=6502</id>
		<title>Module:Date</title>
		<link rel="alternate" type="text/html" href="https://wiki.democracycraft.net/index.php?title=Module:Date&amp;diff=6502"/>
		<updated>2025-07-19T16:53:17Z</updated>

		<summary type="html">&lt;p&gt;AmityBlamity: Blanked the page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>AmityBlamity</name></author>
	</entry>
	<entry>
		<id>https://wiki.democracycraft.net/index.php?title=Module:Age&amp;diff=6501</id>
		<title>Module:Age</title>
		<link rel="alternate" type="text/html" href="https://wiki.democracycraft.net/index.php?title=Module:Age&amp;diff=6501"/>
		<updated>2025-07-19T16:53:05Z</updated>

		<summary type="html">&lt;p&gt;AmityBlamity: Blanked the page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>AmityBlamity</name></author>
	</entry>
	<entry>
		<id>https://wiki.democracycraft.net/index.php?title=List_of_magistrates&amp;diff=6500</id>
		<title>List of magistrates</title>
		<link rel="alternate" type="text/html" href="https://wiki.democracycraft.net/index.php?title=List_of_magistrates&amp;diff=6500"/>
		<updated>2025-07-19T16:49:54Z</updated>

		<summary type="html">&lt;p&gt;AmityBlamity: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Magistrates are the name of the [[judicial officers]] that preside over the [[District Court]]. They are appointed by the [[Supreme Court]].&amp;lt;ref&amp;gt;https://www.democracycraft.net/threads/constitution.6/ Sections 15 and 21.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The position of magistrate was created on 10 June 2021 with the ratification of the [https://www.democracycraft.net/threads/judicial%E2%80%8C-%E2%80%8Crestructuring%E2%80%8C-%E2%80%8Camendment.6231/ Judicial Restructuring Amendment Act].&amp;lt;ref name=&amp;quot;:02&amp;quot;&amp;gt;https://www.democracycraft.net/threads/referendum-for-the-judicial-restructuring-amendment-act.6532/&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;https://www.democracycraft.net/threads/judicial%E2%80%8C-%E2%80%8Crestructuring%E2%80%8C-%E2%80%8Camendment.6231/&amp;lt;/ref&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Note: dates are in UTC. &lt;br /&gt;
&lt;br /&gt;
== Magistrates of the District Court ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Number&lt;br /&gt;
!Magistrate&lt;br /&gt;
!Date of appointment&lt;br /&gt;
!End of tenure (Reason)&lt;br /&gt;
!Tenure length&lt;br /&gt;
!Highest ranking prior position in the judiciary&lt;br /&gt;
!Ref.&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|[[wuutie]]&lt;br /&gt;
|10 July 2021&lt;br /&gt;
|5 October 2021 (Continued as judge)&lt;br /&gt;
|87 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/673612908868927498/686158870435201035/863546399773294632 [[File:Wuutie_magistrate_appointment.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/794283346565922847/894779409540739092 https://discord.com/channels/794162227837534208/794283346565922847/894780168948817931 [[File:Wuutie_judge_nomination.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|[[dygyee]]&lt;br /&gt;
|30 September 2021&lt;br /&gt;
|9 April 2022 (Continued as judge)&lt;br /&gt;
|191 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/673612908868927498/686158870435201035/892948693987246080 [[File:Dygyee_magistrate_appointment.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/962119066544390284 https://discord.com/channels/794162227837534208/918003510795202640/962302649674366996 [[File:Dygyee_judge_nomination.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|[[BananaNova]]&lt;br /&gt;
|5 December 2021&lt;br /&gt;
|10 June 2022 (Continued as judge)&lt;br /&gt;
|187 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/673612908868927498/686158870435201035/916872456394932264 [[File:BananaNova_magistrate_appointment.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/984685138396983336 https://discord.com/channels/794162227837534208/918003510795202640/984852984921980948 [[File:Bananamuffinmc_(banananova)_judge_nomination.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|[[Nacholebraa]]&lt;br /&gt;
|17 April 2022&lt;br /&gt;
|2 July 2022 (Continued as judge)&lt;br /&gt;
|76 days&lt;br /&gt;
|Judge&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/965295602466447440&lt;br /&gt;
&lt;br /&gt;
[[File:Nacholebraa magistrate appointment.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref name=&amp;quot;:6&amp;quot;&amp;gt;Screenshot taken in EST: https://discord.com/channels/673612908868927498/686158870435201035/774333278726783037 [[File:Judge_nacholebraa_confirmation_announcement.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/990986495080923217 https://discord.com/channels/794162227837534208/918003510795202640/991090595550339112 [[File:Nacholebraa_judge_nomination.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|[[Kanne]]&lt;br /&gt;
|29 May 2022&lt;br /&gt;
|9 August 2022 (Resigned)&lt;br /&gt;
|72 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/980516181045809193&lt;br /&gt;
&lt;br /&gt;
[[File:Kanne magistrate appointment.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/794162227837534208/918003510795202640/1006612133867433994&amp;lt;nowiki/&amp;gt;https://discord.com/channels/794162227837534208/918003510795202640/1006689199845556224[[File:Xlayzur CRB and Kanne attorney general nomination.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|6&lt;br /&gt;
|[[Aladeen22]]&lt;br /&gt;
|4 July 2022&lt;br /&gt;
|6 or 7 November 2022. It is most likely that he resigned on the 7th in order to run in an election.&lt;br /&gt;
|125 or 126 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/673612908868927498/686158870435201035/993576135143198840 [[File:Aladeen22_magistrate_appointment.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST&lt;br /&gt;
&lt;br /&gt;
Aladeen22&#039;s final in-game message as a magistrate on 7 November 2022 (UTC) before they were reappointed in 2024.&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686103036057485318/1038985104875343983[[File:Er89tuhwuehrih5.png]]&lt;br /&gt;
&lt;br /&gt;
Aladeen22&#039;s first in-game message as something other than magistrate after that previous message&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686103036057485318/1039370061984571454&lt;br /&gt;
&lt;br /&gt;
[[File:As9us8v89fdf.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Aladeen22&#039;s declaration for the House of Representatives on 7 November 2022 (UTC).https://www.democracycraft.net/threads/house-of-representatives-elections-november-2022.15056/post-56259&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|7&lt;br /&gt;
|[[Dartanboy]]&lt;br /&gt;
|6 December 2022&lt;br /&gt;
|20 March 2023 (Resigned)&lt;br /&gt;
|104 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1049737694990835855&lt;br /&gt;
&lt;br /&gt;
[[File:Dartanboy solicitor general resignation edit time.png]]&lt;br /&gt;
&lt;br /&gt;
[[File:Dartanboy solicitor general resignation.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1087259492527382568&lt;br /&gt;
&lt;br /&gt;
[[File:Dartanman Dartanboy Public Defenders Program Director appointment.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|[[Mask3D_WOLF]]&lt;br /&gt;
|24 July 2023&lt;br /&gt;
|Between 19 and 29 February 2024 (Fired)&lt;br /&gt;
|210 to 220 days&lt;br /&gt;
|Judge&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1133017800210907258&lt;br /&gt;
&lt;br /&gt;
[[File:Mask3D WOLF magistrate appointment 1.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref name=&amp;quot;:0&amp;quot;&amp;gt;Screenshots taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1117150109017309306 https://discord.com/channels/794162227837534208/918003510795202640/1117210234306445424 [[File:Mask3D_WOLF_Judge_nomination.png|[[File:Mask3D WOLF Judge nomination votes.png]]]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
Mask3D_WOLF&#039;s final message as a magistrate, and their first message without the magistrate tag after their final message as a magistrate.&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686103036057485318/1209197468177141861&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686103036057485318/1215869740967399455[[File:8s9dugdusf.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Filed 29 February 2024 (UTC). &lt;br /&gt;
&lt;br /&gt;
https://www.democracycraft.net/threads/mask3d_wolf-v-commonwealth-of-redmont-2024-fcr-28.20410/&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|9&lt;br /&gt;
|[[RelaxedGV]]&lt;br /&gt;
|15 September 2023&lt;br /&gt;
|Unknown&lt;br /&gt;
|Unknown&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1152331726190813266&lt;br /&gt;
&lt;br /&gt;
[[File:RelaxedGV magistrate appointment.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt; &lt;br /&gt;
|-&lt;br /&gt;
|10&lt;br /&gt;
|[[ko531]]&lt;br /&gt;
|28 November 2023&lt;br /&gt;
|23 February 2024 (Fired)&lt;br /&gt;
|87 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref name=&amp;quot;:1&amp;quot;&amp;gt;Screenshot taken in CST&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/901465377895251988/1395644755311984660[[File:Ko531 magistrate appointment 1.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in CST&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/901465377895251988/1395642991204372520[[File:Ko531 magistrate firing message.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|11&lt;br /&gt;
|[[xtub12345]]&lt;br /&gt;
|17 March 2024&lt;br /&gt;
|28 June 2024 (Resigned)&lt;br /&gt;
|103 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1219031400150466652&lt;br /&gt;
&lt;br /&gt;
[[File:Xtub12345 magistrate appointment and Taelor court clerk appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1256311971868053504&lt;br /&gt;
&lt;br /&gt;
[[File:Xtub12345 magistrate resignation.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|12&lt;br /&gt;
|Aladeen22&lt;br /&gt;
|14 July 2025&lt;br /&gt;
|15 August 2024 (Resigned)&lt;br /&gt;
|32 days&lt;br /&gt;
|Judge&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1263646850624389234&lt;br /&gt;
&lt;br /&gt;
[[File:19 July 2024 house special election announcement.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1063381292214910998 [[File:Aladeen22_judge_nomination.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1064034944726343781 [[File:Aladeen22_judge_nomination_passing.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in GMT-5&lt;br /&gt;
&lt;br /&gt;
[[File:Aladeen magistrate resignation 2024.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref name=&amp;quot;:2&amp;quot;&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1262055468407197748&lt;br /&gt;
[[File:Aladeen22 and xAntho ny magistrate appointment.png|thumb]]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|12&lt;br /&gt;
|[[xAntho_ny]]&lt;br /&gt;
|14 July 2025&lt;br /&gt;
|Unknown&lt;br /&gt;
|Unknown&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref name=&amp;quot;:2&amp;quot; /&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|14&lt;br /&gt;
|[[Jakovus]]&lt;br /&gt;
|15 September 2024&lt;br /&gt;
|30 October 2024 (Continued as judge)&lt;br /&gt;
|45 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1284827968249532436&lt;br /&gt;
&lt;br /&gt;
[[File:Jakovus magistrate appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1301187947206283275 [[File:Jakovus_judge_nomination.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|15&lt;br /&gt;
|ko531&lt;br /&gt;
|27 October 2024&lt;br /&gt;
|14 May 2025 (Continued as judge)&lt;br /&gt;
|199 days&lt;br /&gt;
|Magistrate&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1300175019384639609&lt;br /&gt;
&lt;br /&gt;
[[File:Ko531 magistrate appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1371308258165395466 [[File:Ko531_judge_nomination_.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref name=&amp;quot;:1&amp;quot; /&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|Mask3D_WOLF&lt;br /&gt;
|26 January 2025&lt;br /&gt;
|7 April 2025 (Fired)&lt;br /&gt;
|71 days&lt;br /&gt;
|Judge&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1332897754078384198&lt;br /&gt;
&lt;br /&gt;
[[File:Mask3D WOLF magistrate appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref name=&amp;quot;:0&amp;quot; /&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/901465377895251988/1395630886652739625&lt;br /&gt;
&lt;br /&gt;
[[File:Ahsd8v8ud.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|17&lt;br /&gt;
|[[JunkCereal]]&lt;br /&gt;
|4 June 2025&lt;br /&gt;
|16 July 2025 (Continued as judge)&lt;br /&gt;
|42 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1379945184925847613&lt;br /&gt;
&lt;br /&gt;
[[File:JunkCereal magistrate appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1394090359138684970 [[File:JunkCereal_judge_nomination_.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|18&lt;br /&gt;
|[[AmityBlamity]]&lt;br /&gt;
|3 July 2025&lt;br /&gt;
|Current&lt;br /&gt;
|{{age in days|3 July 2025}} days as of {{CURRENTDAY}}/{{CURRENTMONTH}}/{{CURRENTYEAR}}&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1390426816057049109&lt;br /&gt;
&lt;br /&gt;
[[File:AmityBlamity magistrate appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
If the images are overlapping, zoom out and try refreshing.&lt;/div&gt;</summary>
		<author><name>AmityBlamity</name></author>
	</entry>
	<entry>
		<id>https://wiki.democracycraft.net/index.php?title=Module:ConvertNumeric&amp;diff=6499</id>
		<title>Module:ConvertNumeric</title>
		<link rel="alternate" type="text/html" href="https://wiki.democracycraft.net/index.php?title=Module:ConvertNumeric&amp;diff=6499"/>
		<updated>2025-07-19T16:47:53Z</updated>

		<summary type="html">&lt;p&gt;AmityBlamity: Created page with &amp;quot;-- Module for converting between different representations of numbers. See talk page for user documentation. -- For unit tests see: Module:ConvertNumeric/testcases -- When editing, preview with: Module_talk:ConvertNumeric/testcases -- First, edit Module:ConvertNumeric/sandbox, then preview with Module_talk:ConvertNumeric/sandbox/testcases require(&amp;#039;strict&amp;#039;)  local ones_position = { 	[0] = &amp;#039;zero&amp;#039;, 	[1] = &amp;#039;one&amp;#039;, 	[2] = &amp;#039;two&amp;#039;, 	[3] = &amp;#039;three&amp;#039;, 	[4] = &amp;#039;four&amp;#039;,...&amp;quot;&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>AmityBlamity</name></author>
	</entry>
	<entry>
		<id>https://wiki.democracycraft.net/index.php?title=Module:Date&amp;diff=6498</id>
		<title>Module:Date</title>
		<link rel="alternate" type="text/html" href="https://wiki.democracycraft.net/index.php?title=Module:Date&amp;diff=6498"/>
		<updated>2025-07-19T16:47:23Z</updated>

		<summary type="html">&lt;p&gt;AmityBlamity: Created page with &amp;quot;-- Date functions for use by other modules. -- I18N and time zones are not supported.  local MINUS = &amp;#039;−&amp;#039;  -- Unicode U+2212 MINUS SIGN local floor = math.floor  local Date, DateDiff, diffmt  -- forward declarations local uniq = { &amp;#039;unique identifier&amp;#039; }  local function is_date(t) 	-- The system used to make a date read-only means there is no unique 	-- metatable that is conveniently accessible to check. 	return type(t) == &amp;#039;table&amp;#039; and t._id == uniq end  local function is_...&amp;quot;&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, {&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;
-- A table to get the current date/time (UTC), but only if needed.&lt;br /&gt;
local current = setmetatable({}, {&lt;br /&gt;
	__index = function (self, key)&lt;br /&gt;
		local d = os.date(&#039;!*t&#039;)&lt;br /&gt;
		self.year = d.year&lt;br /&gt;
		self.month = d.month&lt;br /&gt;
		self.day = d.day&lt;br /&gt;
		self.hour = d.hour&lt;br /&gt;
		self.minute = d.min&lt;br /&gt;
		self.second = d.sec&lt;br /&gt;
		return rawget(self, key)&lt;br /&gt;
	end })&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.minute&lt;br /&gt;
			newdate.second = current.second&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>AmityBlamity</name></author>
	</entry>
	<entry>
		<id>https://wiki.democracycraft.net/index.php?title=Module:Age&amp;diff=6497</id>
		<title>Module:Age</title>
		<link rel="alternate" type="text/html" href="https://wiki.democracycraft.net/index.php?title=Module:Age&amp;diff=6497"/>
		<updated>2025-07-19T16:46:00Z</updated>

		<summary type="html">&lt;p&gt;AmityBlamity: Created page with &amp;quot;-- Implement various &amp;quot;age of&amp;quot; and other date-related templates.  local mtext = { 	-- Message and other text that should be localized. 	-- Also need to localize text in table names in function dateDifference. 	[&amp;#039;mt-bad-param2&amp;#039;] =             &amp;#039;Parameter $1=$2 is invalid&amp;#039;, 	[&amp;#039;mt-bad-show&amp;#039;] =               &amp;#039;Parameter show=$1 is not supported here&amp;#039;, 	[&amp;#039;mt-cannot-add&amp;#039;] =             &amp;#039;Cannot add &amp;quot;$1&amp;quot;&amp;#039;, 	[&amp;#039;mt-conflicting-show&amp;#039;] =       &amp;#039;Parameter show=$1 conflicts with round=$2&amp;#039;...&amp;quot;&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;Parameter $1=$2 is invalid&#039;,&lt;br /&gt;
	[&#039;mt-bad-show&#039;] =               &#039;Parameter show=$1 is not supported here&#039;,&lt;br /&gt;
	[&#039;mt-cannot-add&#039;] =             &#039;Cannot add &amp;quot;$1&amp;quot;&#039;,&lt;br /&gt;
	[&#039;mt-conflicting-show&#039;] =       &#039;Parameter show=$1 conflicts with round=$2&#039;,&lt;br /&gt;
	[&#039;mt-date-wrong-order&#039;] =       &#039;The second date must be later in time than the first date&#039;,&lt;br /&gt;
	[&#039;mt-dd-future&#039;] =              &#039;Death date (first date) must not be in the future&#039;,&lt;br /&gt;
	[&#039;mt-dd-wrong-order&#039;] =         &#039;Death date (first date) must be later in time than the birth date (second date)&#039;,&lt;br /&gt;
	[&#039;mt-invalid-bd-age&#039;] =         &#039;Invalid birth date for calculating age&#039;,&lt;br /&gt;
	[&#039;mt-invalid-dates-age&#039;] =      &#039;Invalid dates for calculating age&#039;,&lt;br /&gt;
	[&#039;mt-invalid-end&#039;] =            &#039;Invalid end date in second parameter&#039;,&lt;br /&gt;
	[&#039;mt-invalid-start&#039;] =          &#039;Invalid start date in first parameter&#039;,&lt;br /&gt;
	[&#039;mt-need-jdn&#039;] =               &#039;Need valid Julian date number&#039;,&lt;br /&gt;
	[&#039;mt-need-valid-bd&#039;] =          &#039;Need valid birth date: year, month, day&#039;,&lt;br /&gt;
	[&#039;mt-need-valid-bd2&#039;] =         &#039;Need valid birth date (second date): year, month, day&#039;,&lt;br /&gt;
	[&#039;mt-need-valid-date&#039;] =        &#039;Need valid date&#039;,&lt;br /&gt;
	[&#039;mt-need-valid-dd&#039;] =          &#039;Need valid death date (first date): year, month, day&#039;,&lt;br /&gt;
	[&#039;mt-need-valid-ymd&#039;] =         &#039;Need valid year, month, day&#039;,&lt;br /&gt;
	[&#039;mt-need-valid-ymd-current&#039;] = &#039;Need valid year|month|day or &amp;quot;currentdate&amp;quot;&#039;,&lt;br /&gt;
	[&#039;mt-need-valid-ymd2&#039;] =        &#039;Second date should be year, month, day&#039;,&lt;br /&gt;
	[&#039;mt-template-bad-name&#039;] =      &#039;The specified template name is not valid&#039;,&lt;br /&gt;
	[&#039;mt-template-x&#039;] =             &#039;The template invoking this must have &amp;quot;|template=x&amp;quot; where x is the wanted operation&#039;,&lt;br /&gt;
	[&#039;mt-warn-param1&#039;] =            &#039;Invalid parameter $1&#039;,&lt;br /&gt;
	[&#039;mt-warn-param2&#039;] =            &#039;Parameter $1=$2 is invalid&#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; and &#039;,&lt;br /&gt;
	[&#039;txt-or&#039;] =                    &#039;&amp;amp;nbsp;or &#039;,&lt;br /&gt;
	[&#039;txt-category&#039;] =              &#039;Category:Age error&#039;,&lt;br /&gt;
	[&#039;txt-comma-and&#039;] =             &#039;, and &#039;,&lt;br /&gt;
	[&#039;txt-error&#039;] =                 &#039;Error: &#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;Module:ConvertNumeric&#039;,&lt;br /&gt;
	[&#039;txt-module-date&#039;] =           &#039;Module:Date&#039;,&lt;br /&gt;
	[&#039;txt-sandbox&#039;] =               &#039;sandbox&#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; (age&amp;amp;nbsp;$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; (aged&amp;amp;nbsp;$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;
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)&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 problem&lt;br /&gt;
	local wanted = mtext[&#039;txt-format-default&#039;]&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;&amp;amp;nbsp;&#039;,&lt;br /&gt;
			y = {&#039;year&#039;, &#039;years&#039;},&lt;br /&gt;
			m = {&#039;month&#039;, &#039;months&#039;},&lt;br /&gt;
			w = {&#039;week&#039;, &#039;weeks&#039;},&lt;br /&gt;
			d = {&#039;day&#039;, &#039;days&#039;},&lt;br /&gt;
			H = {&#039;hour&#039;, &#039;hours&#039;},&lt;br /&gt;
			M = {&#039;minute&#039;, &#039;minutes&#039;},&lt;br /&gt;
			S = {&#039;second&#039;, &#039;seconds&#039;},&lt;br /&gt;
		},&lt;br /&gt;
		abbr_on = {&lt;br /&gt;
			y = &#039;y&#039;,&lt;br /&gt;
			m = &#039;m&#039;,&lt;br /&gt;
			w = &#039;w&#039;,&lt;br /&gt;
			d = &#039;d&#039;,&lt;br /&gt;
			H = &#039;h&#039;,&lt;br /&gt;
			M = &#039;m&#039;,&lt;br /&gt;
			S = &#039;s&#039;,&lt;br /&gt;
		},&lt;br /&gt;
		abbr_infant = {      -- for {{age for infant}}&lt;br /&gt;
			sep = &#039;&amp;amp;nbsp;&#039;,&lt;br /&gt;
			y = {&#039;yr&#039;, &#039;yrs&#039;},&lt;br /&gt;
			m = {&#039;mo&#039;, &#039;mos&#039;},&lt;br /&gt;
			w = {&#039;wk&#039;, &#039;wks&#039;},&lt;br /&gt;
			d = {&#039;day&#039;, &#039;days&#039;},&lt;br /&gt;
			H = {&#039;hr&#039;, &#039;hrs&#039;},&lt;br /&gt;
			M = {&#039;min&#039;, &#039;mins&#039;},&lt;br /&gt;
			S = {&#039;sec&#039;, &#039;secs&#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.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; 150 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)&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; 150 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)&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;
	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,           -- Template:Birth_date_and_age&lt;br /&gt;
	death_date_and_age = dda,           -- Template:Death_date_and_age&lt;br /&gt;
	gsd = dateToGsd,                    -- Template:Gregorian_serial_date&lt;br /&gt;
	extract = dateExtract,              -- Template:Extract&lt;br /&gt;
	jd_to_date = jdToDate,              -- Template:?&lt;br /&gt;
	JULIANDAY = dateToJd,               -- Template:JULIANDAY&lt;br /&gt;
	time_interval = timeInterval,       -- Template: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>AmityBlamity</name></author>
	</entry>
	<entry>
		<id>https://wiki.democracycraft.net/index.php?title=Template:Age_in_days&amp;diff=6496</id>
		<title>Template:Age in days</title>
		<link rel="alternate" type="text/html" href="https://wiki.democracycraft.net/index.php?title=Template:Age_in_days&amp;diff=6496"/>
		<updated>2025-07-19T16:44:16Z</updated>

		<summary type="html">&lt;p&gt;AmityBlamity: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;{{#invoke:age|age_generic|template=age_days}}&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;{{documentation}}&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>AmityBlamity</name></author>
	</entry>
	<entry>
		<id>https://wiki.democracycraft.net/index.php?title=Template:Age_in_days&amp;diff=6495</id>
		<title>Template:Age in days</title>
		<link rel="alternate" type="text/html" href="https://wiki.democracycraft.net/index.php?title=Template:Age_in_days&amp;diff=6495"/>
		<updated>2025-07-19T16:43:40Z</updated>

		<summary type="html">&lt;p&gt;AmityBlamity: Created page with &amp;quot;{{#invoke:age/sandbox|age_generic|template=age_days}}&amp;lt;noinclude&amp;gt; {{Documentation}} &amp;lt;/noinclude&amp;gt;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{#invoke:age/sandbox|age_generic|template=age_days}}&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{Documentation}}&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>AmityBlamity</name></author>
	</entry>
	<entry>
		<id>https://wiki.democracycraft.net/index.php?title=List_of_magistrates&amp;diff=6494</id>
		<title>List of magistrates</title>
		<link rel="alternate" type="text/html" href="https://wiki.democracycraft.net/index.php?title=List_of_magistrates&amp;diff=6494"/>
		<updated>2025-07-19T16:41:06Z</updated>

		<summary type="html">&lt;p&gt;AmityBlamity: /* Magistrates of the District Court */ Attempting to auto-update date&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Magistrates are the name of the [[judicial officers]] that preside over the [[District Court]]. They are appointed by the [[Supreme Court]].&amp;lt;ref&amp;gt;https://www.democracycraft.net/threads/constitution.6/ Sections 15 and 21.&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The position of magistrate was created on 10 June 2021 with the ratification of the [https://www.democracycraft.net/threads/judicial%E2%80%8C-%E2%80%8Crestructuring%E2%80%8C-%E2%80%8Camendment.6231/ Judicial Restructuring Amendment Act].&amp;lt;ref name=&amp;quot;:02&amp;quot;&amp;gt;https://www.democracycraft.net/threads/referendum-for-the-judicial-restructuring-amendment-act.6532/&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;https://www.democracycraft.net/threads/judicial%E2%80%8C-%E2%80%8Crestructuring%E2%80%8C-%E2%80%8Camendment.6231/&amp;lt;/ref&amp;gt; &lt;br /&gt;
&lt;br /&gt;
Note: dates are in UTC. &lt;br /&gt;
&lt;br /&gt;
== Magistrates of the District Court ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Number&lt;br /&gt;
!Magistrate&lt;br /&gt;
!Date of appointment&lt;br /&gt;
!End of tenure (Reason)&lt;br /&gt;
!Tenure length&lt;br /&gt;
!Highest ranking prior position in the judiciary&lt;br /&gt;
!Ref.&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|[[wuutie]]&lt;br /&gt;
|10 July 2021&lt;br /&gt;
|5 October 2021 (Continued as judge)&lt;br /&gt;
|87 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/673612908868927498/686158870435201035/863546399773294632 [[File:Wuutie_magistrate_appointment.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/794283346565922847/894779409540739092 https://discord.com/channels/794162227837534208/794283346565922847/894780168948817931 [[File:Wuutie_judge_nomination.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|[[dygyee]]&lt;br /&gt;
|30 September 2021&lt;br /&gt;
|9 April 2022 (Continued as judge)&lt;br /&gt;
|191 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/673612908868927498/686158870435201035/892948693987246080 [[File:Dygyee_magistrate_appointment.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/962119066544390284 https://discord.com/channels/794162227837534208/918003510795202640/962302649674366996 [[File:Dygyee_judge_nomination.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|[[BananaNova]]&lt;br /&gt;
|5 December 2021&lt;br /&gt;
|10 June 2022 (Continued as judge)&lt;br /&gt;
|187 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/673612908868927498/686158870435201035/916872456394932264 [[File:BananaNova_magistrate_appointment.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/984685138396983336 https://discord.com/channels/794162227837534208/918003510795202640/984852984921980948 [[File:Bananamuffinmc_(banananova)_judge_nomination.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|[[Nacholebraa]]&lt;br /&gt;
|17 April 2022&lt;br /&gt;
|2 July 2022 (Continued as judge)&lt;br /&gt;
|76 days&lt;br /&gt;
|Judge&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/965295602466447440&lt;br /&gt;
&lt;br /&gt;
[[File:Nacholebraa magistrate appointment.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref name=&amp;quot;:6&amp;quot;&amp;gt;Screenshot taken in EST: https://discord.com/channels/673612908868927498/686158870435201035/774333278726783037 [[File:Judge_nacholebraa_confirmation_announcement.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/990986495080923217 https://discord.com/channels/794162227837534208/918003510795202640/991090595550339112 [[File:Nacholebraa_judge_nomination.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|[[Kanne]]&lt;br /&gt;
|29 May 2022&lt;br /&gt;
|9 August 2022 (Resigned)&lt;br /&gt;
|72 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/980516181045809193&lt;br /&gt;
&lt;br /&gt;
[[File:Kanne magistrate appointment.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/794162227837534208/918003510795202640/1006612133867433994&amp;lt;nowiki/&amp;gt;https://discord.com/channels/794162227837534208/918003510795202640/1006689199845556224[[File:Xlayzur CRB and Kanne attorney general nomination.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|6&lt;br /&gt;
|[[Aladeen22]]&lt;br /&gt;
|4 July 2022&lt;br /&gt;
|6 or 7 November 2022. It is most likely that he resigned on the 7th in order to run in an election.&lt;br /&gt;
|125 or 126 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/673612908868927498/686158870435201035/993576135143198840 [[File:Aladeen22_magistrate_appointment.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST&lt;br /&gt;
&lt;br /&gt;
Aladeen22&#039;s final in-game message as a magistrate on 7 November 2022 (UTC) before they were reappointed in 2024.&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686103036057485318/1038985104875343983[[File:Er89tuhwuehrih5.png]]&lt;br /&gt;
&lt;br /&gt;
Aladeen22&#039;s first in-game message as something other than magistrate after that previous message&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686103036057485318/1039370061984571454&lt;br /&gt;
&lt;br /&gt;
[[File:As9us8v89fdf.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Aladeen22&#039;s declaration for the House of Representatives on 7 November 2022 (UTC).https://www.democracycraft.net/threads/house-of-representatives-elections-november-2022.15056/post-56259&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|7&lt;br /&gt;
|[[Dartanboy]]&lt;br /&gt;
|6 December 2022&lt;br /&gt;
|20 March 2023 (Resigned)&lt;br /&gt;
|104 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1049737694990835855&lt;br /&gt;
&lt;br /&gt;
[[File:Dartanboy solicitor general resignation edit time.png]]&lt;br /&gt;
&lt;br /&gt;
[[File:Dartanboy solicitor general resignation.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1087259492527382568&lt;br /&gt;
&lt;br /&gt;
[[File:Dartanman Dartanboy Public Defenders Program Director appointment.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|[[Mask3D_WOLF]]&lt;br /&gt;
|24 July 2023&lt;br /&gt;
|Between 19 and 29 February 2024 (Fired)&lt;br /&gt;
|210 to 220 days&lt;br /&gt;
|Judge&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1133017800210907258&lt;br /&gt;
&lt;br /&gt;
[[File:Mask3D WOLF magistrate appointment 1.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref name=&amp;quot;:0&amp;quot;&amp;gt;Screenshots taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1117150109017309306 https://discord.com/channels/794162227837534208/918003510795202640/1117210234306445424 [[File:Mask3D_WOLF_Judge_nomination.png|[[File:Mask3D WOLF Judge nomination votes.png]]]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
Mask3D_WOLF&#039;s final message as a magistrate, and their first message without the magistrate tag after their final message as a magistrate.&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686103036057485318/1209197468177141861&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686103036057485318/1215869740967399455[[File:8s9dugdusf.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Filed 29 February 2024 (UTC). &lt;br /&gt;
&lt;br /&gt;
https://www.democracycraft.net/threads/mask3d_wolf-v-commonwealth-of-redmont-2024-fcr-28.20410/&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|9&lt;br /&gt;
|[[RelaxedGV]]&lt;br /&gt;
|15 September 2023&lt;br /&gt;
|Unknown&lt;br /&gt;
|Unknown&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1152331726190813266&lt;br /&gt;
&lt;br /&gt;
[[File:RelaxedGV magistrate appointment.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ref&amp;gt; &lt;br /&gt;
|-&lt;br /&gt;
|10&lt;br /&gt;
|[[ko531]]&lt;br /&gt;
|28 November 2023&lt;br /&gt;
|23 February 2024 (Fired)&lt;br /&gt;
|87 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref name=&amp;quot;:1&amp;quot;&amp;gt;Screenshot taken in CST&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/901465377895251988/1395644755311984660[[File:Ko531 magistrate appointment 1.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in CST&lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/901465377895251988/1395642991204372520[[File:Ko531 magistrate firing message.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|11&lt;br /&gt;
|[[xtub12345]]&lt;br /&gt;
|17 March 2024&lt;br /&gt;
|28 June 2024 (Resigned)&lt;br /&gt;
|103 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1219031400150466652&lt;br /&gt;
&lt;br /&gt;
[[File:Xtub12345 magistrate appointment and Taelor court clerk appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1256311971868053504&lt;br /&gt;
&lt;br /&gt;
[[File:Xtub12345 magistrate resignation.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|12&lt;br /&gt;
|Aladeen22&lt;br /&gt;
|14 July 2025&lt;br /&gt;
|15 August 2024 (Resigned)&lt;br /&gt;
|32 days&lt;br /&gt;
|Judge&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1263646850624389234&lt;br /&gt;
&lt;br /&gt;
[[File:19 July 2024 house special election announcement.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1063381292214910998 [[File:Aladeen22_judge_nomination.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1064034944726343781 [[File:Aladeen22_judge_nomination_passing.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in GMT-5&lt;br /&gt;
&lt;br /&gt;
[[File:Aladeen magistrate resignation 2024.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref name=&amp;quot;:2&amp;quot;&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1262055468407197748&lt;br /&gt;
[[File:Aladeen22 and xAntho ny magistrate appointment.png|thumb]]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|12&lt;br /&gt;
|[[xAntho_ny]]&lt;br /&gt;
|14 July 2025&lt;br /&gt;
|Unknown&lt;br /&gt;
|Unknown&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref name=&amp;quot;:2&amp;quot; /&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|14&lt;br /&gt;
|[[Jakovus]]&lt;br /&gt;
|15 September 2024&lt;br /&gt;
|30 October 2024 (Continued as judge)&lt;br /&gt;
|45 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1284827968249532436&lt;br /&gt;
&lt;br /&gt;
[[File:Jakovus magistrate appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1301187947206283275 [[File:Jakovus_judge_nomination.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|15&lt;br /&gt;
|ko531&lt;br /&gt;
|27 October 2024&lt;br /&gt;
|14 May 2025 (Continued as judge)&lt;br /&gt;
|199 days&lt;br /&gt;
|Magistrate&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1300175019384639609&lt;br /&gt;
&lt;br /&gt;
[[File:Ko531 magistrate appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1371308258165395466 [[File:Ko531_judge_nomination_.png]]&amp;lt;/ref&amp;gt; &amp;lt;ref name=&amp;quot;:1&amp;quot; /&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|Mask3D_WOLF&lt;br /&gt;
|26 January 2025&lt;br /&gt;
|7 April 2025 (Fired)&lt;br /&gt;
|71 days&lt;br /&gt;
|Judge&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1332897754078384198&lt;br /&gt;
&lt;br /&gt;
[[File:Mask3D WOLF magistrate appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref name=&amp;quot;:0&amp;quot; /&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/901465377895251988/1395630886652739625&lt;br /&gt;
&lt;br /&gt;
[[File:Ahsd8v8ud.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|17&lt;br /&gt;
|[[JunkCereal]]&lt;br /&gt;
|4 June 2025&lt;br /&gt;
|16 July 2025 (Continued as judge)&lt;br /&gt;
|42 days&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1379945184925847613&lt;br /&gt;
&lt;br /&gt;
[[File:JunkCereal magistrate appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt; &amp;lt;ref&amp;gt;Screenshot taken in EST https://discord.com/channels/794162227837534208/918003510795202640/1394090359138684970 [[File:JunkCereal_judge_nomination_.png]]&amp;lt;/ref&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|18&lt;br /&gt;
|[[AmityBlamity]]&lt;br /&gt;
|3 July 2025&lt;br /&gt;
|Current&lt;br /&gt;
|15 days as of 18 July 2025&lt;br /&gt;
{{age in days|3 July 2025}}&lt;br /&gt;
|None&lt;br /&gt;
|&amp;lt;ref&amp;gt;Screenshot taken in EST &lt;br /&gt;
&lt;br /&gt;
https://discord.com/channels/673612908868927498/686158870435201035/1390426816057049109&lt;br /&gt;
&lt;br /&gt;
[[File:AmityBlamity magistrate appointment.png]]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
If the images are overlapping, zoom out and try refreshing.&lt;/div&gt;</summary>
		<author><name>AmityBlamity</name></author>
	</entry>
	<entry>
		<id>https://wiki.democracycraft.net/index.php?title=District_Court&amp;diff=5937</id>
		<title>District Court</title>
		<link rel="alternate" type="text/html" href="https://wiki.democracycraft.net/index.php?title=District_Court&amp;diff=5937"/>
		<updated>2025-07-03T21:04:06Z</updated>

		<summary type="html">&lt;p&gt;AmityBlamity: Created the District Court page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &#039;&#039;&#039;District Court&#039;&#039;&#039; (or &amp;quot;DCR&amp;quot;) is the lowest court in the Redmont [[judiciary]], underneath the [[Federal Court]] and [[Supreme Court]]. Cases before the District Court are presided over by a single [[Magistrate]], who are appointed by the [[Chief justice|Chief Justice]]. The Constitution only allows for their to be 3 appointed Federal Court judges at any given time. &lt;br /&gt;
&lt;br /&gt;
== Membership ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Current Magistrates of the District Court&lt;br /&gt;
!Magistrate&lt;br /&gt;
!Appointed by&lt;br /&gt;
!Appointment Date&lt;br /&gt;
|-&lt;br /&gt;
|[[JunkCereal]]&lt;br /&gt;
|[[Aladeen22]]&lt;br /&gt;
|June 5th, 2025&lt;br /&gt;
|-&lt;br /&gt;
|[[AmityBlamity]]&lt;br /&gt;
|[[Aladeen22]]&lt;br /&gt;
|July 3rd, 2025&lt;br /&gt;
|-&lt;br /&gt;
|VACANT&lt;br /&gt;
|VACANT&lt;br /&gt;
|&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>AmityBlamity</name></author>
	</entry>
</feed>