Module:Year in various calendars
-- Load dependencies.
 local getArgs = require('Module:Arguments').getArgs
 local numToRoman = require( 'Module:Roman' ).main
 local getOlympiad = require( 'Module:Ancient Olympiads' )._main
 local getDynasty = require( 'Module:Ancient Egypt era' )._main
 local getPharaoh = require( 'Module:Ancient Egypt kings' )._main
 local numToArmenian = require( 'Module:Armenian' ).main
 local getRegnal = require( 'Module:British regnal year' ).main
 local japaneseEra = require( 'Module:Japanese calendar' ).era()
 
 -- Define constants.
 local lang = mw.language.getContentLanguage()
 local currentYear = tonumber( lang:formatDate( 'Y' ) )
 
 --------------------------------------------------------------------
 -- Helper functions
 --------------------------------------------------------------------
 
 local function isInteger( num )
 	-- Checks if a value is an integer. If so, returns the value converted to a number.
 	-- If not, returns false.
 	num = tonumber( num )
 	if num and math.floor( num ) == num and num ~= math.huge then
 		return num
 	else
 		return false
 	end
 end
 
 local function BCToNum( s )
 	-- Converts strings of the format &quot;n BC&quot; to their corresponding
 	-- numerical values.
 	if type( s ) ~= 'string' then
 		return nil
 	end
 	s = mw.ustring.match( mw.ustring.upper( s ), '^([1-9]%d*)%s*கிமு$' )
 	if not s then
 		return nil
 	end
 	local num = tonumber( s )
 	num = ( num - 1 ) * -1
 	return num
 end
 
 local function numToBC( num )
 	-- For BC years, returns a string with the year name appended with &quot; BC&quot;.
 	-- Otherwise returns nil.
 	num = isInteger( num )
 	if not num then return end
 	if num &lt;= 0 then
 		return string.format( '%d BC', 1 - num )
 	end
 end
 
 local function ADToNum( s )
 	-- Converts strings of the format &quot;AD n&quot;
 	-- to their corresponding numerical values.
 	if type( s ) ~= 'string' then
 		return nil
 	end
 	s = mw.ustring.match( mw.ustring.upper( s ), '^AD%s*([1-9]%d*)$' )
 	if not s then
 		return nil
 	end
 	local num = tonumber( s )
 	return num
 end
 
 local function numToAD( num )
 	-- For AD years up to 100, returns a string with the year name prepended with &quot;AD &quot;.
 	-- Otherwise returns nil.
 	num = isInteger( num )
 	if not num then return end
 	if (num &lt;= 100) then
 		return string.format( 'AD %d', num )
 	end
 end
 
 local function formatNegative(s)
 	-- Replaces hyphens in a string with minus signs if the hyphen comes before a number.
 	s = mw.ustring.gsub( s, '%-(%d)', '−%1' )
 	return s
 end
 
 --------------------------------------------------------------------
 -- Calendar box class definition
 --------------------------------------------------------------------
 
 local calendarBox = {}
 calendarBox.__index = calendarBox
 
 function calendarBox:new( init )
 	init = type( init ) == 'table' and init or {}
 	local obj = {}
 	local pagename = mw.title.getCurrentTitle().text
 
 	-- Set the year. If the year is specified as an argument, use that.
 	-- Otherwise, use the page name if it is valid. If the pagename isn't
 	-- valid, use the current year.
 	local yearNum = isInteger( init.year )
 	local yearBC = BCToNum( init.year )
 	local yearAD = ADToNum( init.year )
 	local pageNum = isInteger( pagename )
 	local pageBC = BCToNum( pagename )
 	local pageAD = ADToNum( pagename )
 	if yearNum then -- First, see if the year parameter is a number.
 		self.year = yearNum
 	elseif yearBC then -- Second, see if the year parameter is a &quot;yyyy BC&quot; string.
 		self.year = yearBC
 	elseif yearAD then -- Third, see if the year parameter is an AD/CE/year string.
 		self.year = yearAD
 	elseif pageNum then -- Fourth, see if the pagename is an integer.
 		self.year = pageNum
 	elseif pageBC then -- Fifth, see if the pagename is a &quot;yyyy BC&quot; string.
 		self.year = pageBC
 	elseif pageAD then -- Sixth, see if the pagename is an AD/CE/year string.
 		self.year = pageAD
 	else
 		self.year = currentYear -- If none of the above apply, use the current year.
 	end
 
 	-- Set year text values.
 	self.BCYearName = numToBC( self.year )
 	self.ADYearName = numToAD( self.year )
 	if self.BCYearName then
 		self.yearText = self.BCYearName
 	elseif self.ADYearName then
 		self.yearText = self.ADYearName
 	else
 		self.yearText = tostring( self.year )
 	end
 
 	-- Set other fields.
 	self.caption = self.yearText
 	self.footnotes = init.footnotes
 
 	return setmetatable( obj, {
 			__index = self
 		})
 end
 
 function calendarBox:setCaption( s )
 	-- Sets the calendar box caption.
 	if type( s ) ~= 'string' or s == '' then return end
 	self.caption = s
 end
 
 function calendarBox:addCalendar( obj )
 	-- Adds a calendar or a calendar group.
 	if type( obj ) ~= 'table' and type( obj.new ) ~= 'function' then return end -- Exit if the object is invalid.
 	self.calendars = self.calendars or {}
 	table.insert( self.calendars, obj )
 end
 
 -- Add an alias for adding calendar groups. The function is the same, but it might be confusing for users
 -- to have to use the name &quot;addCalendar&quot; for a calendar group.
 calendarBox.addCalendarGroup = calendarBox.addCalendar
 
 function calendarBox:export()
 	-- Outputs the calendar box wikitext.
 	local root = mw.html.create( 'table' )
 	-- Export the calendar box headers.
 	root
 	:addClass( 'infobox vevent' )
 	:css( 'width', '22em' )
 	:tag( 'caption' )
 	:css( 'font-size', '125%' )
 	:tag( 'span' )
 	:addClass( 'summary dtstart' )
 	:wikitext( self.caption )
 
 	-- Export the calendars and calendar groups. &quot;calendar:export()&quot; works for both kinds
 	-- of objects. Some export functions can return nil, so we need to check for that.
 	if type( self.calendars ) == 'table' then
 		for _, calendar in ipairs( self.calendars ) do
 			local calendarText = calendar:export()
 			if type( calendarText ) == 'string' then
 				root:wikitext( calendarText )
 			end
 		end
 	end
 
 	-- Add footnotes.
 	if type( self.footnotes ) == 'string' and self.footnotes ~= '' then
 		root
 		:tag( 'tr' )
 		:tag( 'td' )
 		:attr( 'colspan', '2' )
 		:wikitext( string.format( '%s', self.footnotes ) )
 	end
 
 	return tostring( root )
 end
 
 --------------------------------------------------------------------
 -- Calendar group class definition
 --------------------------------------------------------------------
 
 --  Calendar groups are used to group different calendars together. 
 --  Previously, the template did this by including a table row with
 --  no year value. By using objects we can do the same thing more
 --  semantically.
 
 local calendarGroup = {}
 calendarGroup.__index = calendarGroup
 
 function calendarGroup:new( init )
 	init = type( init ) == 'table' and init or {}
 	local obj = {}
 
 	-- Get the heading and throw an error if it is invalid.
 	obj.heading = init.heading
 	if type( obj.heading ) ~= 'string' then
 		error( 'calendarGroup: no heading detected' )
 	end
 
 	-- Set the metatable and return the object.
 	self.__index = self
 	return setmetatable( obj, {
 			__index = self
 		})
 end
 
 function calendarGroup:addCalendar( calendar )
 	-- Adds a calendar object to the calendar group.
 	self.calendars = self.calendars or {}
 	if type( calendar ) == 'table' and type( calendar.getLink ) == 'function' then
 		table.insert( self.calendars, calendar )
 	end
 end
 
 function calendarGroup:export()
 	-- Exports the calendar group's wikitext.
 	-- Indent and italicise each calendar's link if it exists.
 	for i, calendar in ipairs( self.calendars ) do
 		local link = calendar:getLink()
 		if type( link ) == 'string' then
 			self.calendars[ i ]:setRawLink( string.format( &quot;&amp;nbsp;- ''%s''&quot;, link ) )
 		end
 	end
 	-- Create the heading row html and export the calendar objects.
 	local ret = mw.html.create()
 	ret
 	:tag( 'tr' )
 	:tag( 'td' )
 	:wikitext( self.heading )
 	:done()
 	:tag( 'td' ) -- Use a blank tag to make the html look nice.
 	:allDone()
 	for _, calendar in ipairs( self.calendars ) do
 		ret:wikitext( calendar:export() )
 	end
 	return tostring( ret )
 end
 
 --------------------------------------------------------------------
 -- Calendar class definition
 --------------------------------------------------------------------
 
 local calendar = {}
 calendar.__index = calendar
 calendar.type = 'calendar'
 
 function calendar:new()
 	local obj = {}
 	return setmetatable( obj, {
 			__index = self
 		})
 end
 
 function calendar:setLink( link, display )
 	-- Sets the calendar's wikilink, with optional display text and italics.
 	if type( link ) ~= 'string' or link == '' then return end
 	display = type( display ) == 'string' and display ~= '' and display
 	if display then
 		self.link = string.format( '[[%s|%s]]', link, display )
 	else
 		self.link = string.format( '[[%s]]', link )
 	end
 end
 
 function calendar:setRawLink( s )
 	-- Sets the calendar's wikilink as raw wikitext.
 	if type( s ) ~= 'string' or s == '' then return end
 	self.link = s
 end
 
 function calendar:getLink()
 	-- Returns the calendar's link value.
 	return self.link
 end
 
 function calendar:setYear( year )
 	-- Sets a single year. Can be passed either a string or a number.
 	-- If passed as a number, it is formatted with minus signs instead of hyphens.
 	-- If passed as a string, no minus-sign formatting occurs; this should be done in the individual calendar definitions.
 	if type( year ) == 'number' then
 		year = tostring( year )
 		self.year = formatNegative( year )
 	elseif type( year ) == 'string' then
 		self.year = year
 	end
 end
 
 function calendar:setYearRange( year1, year2 )
 	-- Sets a year range. Must be passed two numbers.
 	if type( year1 ) == 'number' and type( year2 ) == 'number' then
 		local year
 		if year1 &lt; 0 or year2 &lt; 0 then -- Leave a gap for negative years to avoid having a minus sign and a dash right next to each other.
 			year = string.format( '%d – %d', year1, year2 )
 			year = formatNegative( year )
 		else
 			year = string.format( '%d–%d', year1, year2 )
 		end
 		self.year = year
 	end
 end
 
 function calendar:setYearCouple( year1, year2, addtext )
 	-- Same as setYearRange, only with a slash (/) in the middle. Must be passed two numbers. 
 	-- Additional text possible, must be defined as follows: addtext = string.format( 'additional text or link')
 	-- See example in Seleucid era calendar
 	if type( year1 ) == 'number' and type( year2 ) == 'number' then
 		local year
 		if year1 &lt; 0 or year2 &lt; 0 then -- Leave no gap for negative years.
 			year = string.format( '%d/%d %s', year1, year2, addtext )
 			year = formatNegative( year )
 		else
 			year = string.format( '%d/%d %s', year1, year2, addtext )
 		end
 		self.year = year
 	end
 end
 
 function calendar:export()
 	-- Outputs the calendar wikitext.
 	-- Exit if no link has been specified.
 	local link = self.link
 	if type( link ) ~= 'string' or link == '' then return end
 
 	-- If no year has been specified, set the year value to N/A.
 	local year = self.year
 	if type( year ) ~= 'string' or year == '' then
 		year = &quot;''N/A''&quot;
 	end
 
 	-- Build the table row.
 	local ret = mw.html.create()
 	ret
 	:tag( 'tr' )
 	:tag( 'td' )
 	:wikitext( link )
 	:done()
 	:tag( 'td' )
 	:wikitext( year )
 	:allDone()
 	return tostring( ret )
 end
 
 --------------------------------------------------------------------
 -- Build the box
 --------------------------------------------------------------------
 
 local function makeCalendarBox( args )
 	-- Initiate the box and get the year values.
 	local init = args
 	local box = calendarBox:new( init )
 	local year = box.year
 	local yearText = box.yearText
 
 	-- Set the caption.
 	box:setCaption( box.caption .. ' in various [[Calendar era|calendars]]' )
 
 	----------------------------------------------------------------------
 	-- Gregorian calendar
 	----------------------------------------------------------------------
 
 	local gregorian = calendar:new()
 	gregorian:setLink( 'கிரெகொரியின் நாட்காட்டி' )
 	-- Get the year link.
 	local gregcal = args.gregcal
 	if type( gregcal ) == 'string' and gregcal ~= '' then
 		gregorian.yearLink = string.format( '[[%s|%s]]', gregcal, yearText )
 	else
 		gregorian.yearLink = yearText
 	end
 	-- Set the year.
 	gregorian.romanYear = numToRoman{ math.abs(year) } .. (year &lt; 0 and ' BC' or '')
 	if gregorian.romanYear then
 		gregorian:setYear( string.format(
 				[[%s&lt;br /&gt;&lt;span style=&quot;font-family: serif;&quot;&gt;''%s''&lt;/span&gt;]],
 				gregorian.yearLink, gregorian.romanYear
 				) )
 	else
 		gregorian:setYear( gregorian.yearLink )
 	end
 	box:addCalendar( gregorian ) 
 	
 	----------------------------------------------------------------------
 	-- French Republican calendar
 	-- displays only in years 1793 - 1805 and 1871
 	-- This calendar was in use and had defined years only for the short period on display.
 	-- Its importance during these few years is also the reason why it should stay out of the alphabetic order.
 	-- See discussion on talk page.
 	----------------------------------------------------------------------
 	
 	if year &gt;= 1793 and year &lt; 1806 or year == 1871 then
 		local republican = calendar:new()
 		republican:setLink('French Republican calendar')
 		if year &lt;= 1870 then
 			republican:setYearRange( year - 1792, year - 1791 )
 		elseif year == 1871 then
 			republican:setYear( year - 1792 ) -- Paris Commune, May
 		end
 		box:addCalendar( republican )
 	end
 	
 	
 	----------------------------------------------------------------------
 	-- திருவள்ளுவர் ஆண்டு
 	-- Gregorian +31 years
 	----------------------------------------------------------------------
 	local ThiruAandu = calendar:new()
 	ThiruAandu:setLink( 'திருவள்ளுவர் ஆண்டு' )
 	ThiruAandu:setYear( year + 31 )
 	box:addCalendar( ThiruAandu )
 
 	----------------------------------------------------------------------
 	-- Ab urbe condita
 	-- Varro's correlation, from 1 AUC
 	----------------------------------------------------------------------
 	if year &gt;= -752 then
 		local abUrbe = calendar:new()
 		abUrbe:setLink( 'அப் ஊர்பி கொண்டிட்டா' )
 		abUrbe:setYear( year + 753 )
 		box:addCalendar( abUrbe )
 	end
 	
 	----------------------------------------------------------------------
 	-- Ancient Egypt era 
 	-- Displays dynasty between 1549 BC and 30 BC
 	-- Displays pharaoh or king between 752 BC and 30 BC
 	----------------------------------------------------------------------
 	if year &gt; -1549 and year &lt;= -29 then
 	local ancEgypt = calendar:new()
 	ancEgypt:setLink(
 			'Egyptian chronology',
 			'Ancient Egypt era'
 		)
 	ancEgypt:setYear( getDynasty( year ) )
 	box:addCalendar( ancEgypt )
 	end
 	if year &gt; - 752 and year &lt;= -29 then
 	local ancPharaoh = calendar:new()
 	ancPharaoh:setLink(
 			'List of pharaohs',
 			'&lt;i&gt;- Pharaoh&lt;/i&gt;'
 		)
 	ancPharaoh:setYear( getPharaoh( year ) )
 	box:addCalendar( ancPharaoh )
 	end
 
 	----------------------------------------------------------------------
 	-- Ancient Olympiads 
 	-- Currently only the first 194 Olympiads
 	-- May be expanded until 394 AD when data available
 	----------------------------------------------------------------------
 	if year &gt;= -1300 and year &lt; 1 then
 	local ancOlympiads = calendar:new()
 	ancOlympiads:setLink(
 			'Ancient Greek calendar',
 			'Ancient Greek era'
 		)
 	ancOlympiads:setYear( getOlympiad( year ) )
 	box:addCalendar( ancOlympiads )
 	end
 
 	----------------------------------------------------------------------
 	-- Armenian calendar
 	----------------------------------------------------------------------
 
 	if year &gt; 551 then
 	local armenian = calendar:new()
 	armenian:setLink( 'அர்மீனிய நாட்காட்டி' )
 		local armenianYear = year - 551
 		armenian:setYear( string.format( '%s&lt;br /&gt;ԹՎ %s', armenianYear, numToArmenian( armenianYear ) ) )
 	box:addCalendar( armenian )
 	end
 
 	----------------------------------------------------------------------
 	-- Assyrian calendar
 	----------------------------------------------------------------------
 
 	local assyrian = calendar:new()
 	assyrian:setLink( 'அசிரிய நாட்காட்டி' )
 	assyrian:setYear( year + 4750 )
 	box:addCalendar( assyrian )
 
 	----------------------------------------------------------------------
 	-- Bahá'í calendar
 	-- displays only after 1843
 	----------------------------------------------------------------------
 	
 	if year &gt;= 1844 then
 		local bahai = calendar:new()
 		bahai:setLink( &quot;Baháʼí calendar&quot; )
 		bahai:setYearRange( year - 1844, year - 1843 )
 		box:addCalendar( bahai )
 	end
 	
     ----------------------------------------------------------------------
     -- Balinese saka calendar
     ---------------------------------------------------------------------- 
     local balinese = calendar:new()
     balinese:setLink( 'Balinese saka calendar' )
     if year - 76 &gt; 0 then
     	balinese:setYearRange( year - 79, year - 78 )
     end
     box:addCalendar( balinese )
 
 	----------------------------------------------------------------------
 	-- Bengali calendar
 	----------------------------------------------------------------------
 
 	local bengali = calendar:new()
 	bengali:setLink( 'Bengali calendar' )
 	bengali:setYear( year - 593 )
 	box:addCalendar( bengali )
 
 	----------------------------------------------------------------------
 	-- Berber calendar
 	----------------------------------------------------------------------
 
 	local berber = calendar:new()
 	berber:setLink( 'Berber calendar' )
 	berber:setYear( year + 950 )
 	box:addCalendar( berber )
 
 	----------------------------------------------------------------------
 	-- Regnal year
 	----------------------------------------------------------------------
 
 	if year &gt;= 1000 then
 		local regnal = calendar:new()
 		local regnalName
 		if year &gt; 1706 then
 			regnalName = 'British'
 		else
 			regnalName = 'English'
 		end
 		regnal:setLink( 'Regnal years of English monarchs', regnalName .. ' Regnal year' )
 		regnal:setYear( getRegnal( year ) )
 		box:addCalendar( regnal )
 	end
 
 	----------------------------------------------------------------------
 	-- Buddhist calendar
 	----------------------------------------------------------------------
 
 	local buddhist = calendar:new()
 	buddhist:setLink( 'Buddhist calendar' )
 	buddhist:setYear( year + 544 )
 	box:addCalendar( buddhist )
 
 	----------------------------------------------------------------------
 	-- Burmese calendar
 	----------------------------------------------------------------------
 
 	local burmese = calendar:new()
 	burmese:setLink( 'Burmese calendar' )
 	burmese:setYear( year - 638 )
 	box:addCalendar( burmese )
 
 	----------------------------------------------------------------------
 	-- Byzantine calendar
 	----------------------------------------------------------------------
 
 	local byzantine = calendar:new()
 	byzantine:setLink( 'Byzantine calendar' )
 	byzantine:setYearRange( year + 5508, year + 5509 )
 	box:addCalendar( byzantine )
 
 	----------------------------------------------------------------------
 	-- Chinese calendar
 	----------------------------------------------------------------------
 
 	local chinese = calendar:new()
 	chinese:setLink( 'சீன நாட்காட்டி' )
 
 	-- Define the information for the &quot;heavenly stems&quot; and &quot;earthly branches&quot; year cycles.
 	-- See [[Chinese calendar#Cycle of years]] for information.
 
 	local heavenlyStems = {
 		{ '甲', 'Wood' },   -- 1
 		{ '乙', 'Wood' },   -- 2
 		{ '丙', 'Fire' },   -- 3
 		{ '丁', 'Fire' },   -- 4
 		{ '戊', 'Earth' },  -- 5
 		{ '己', 'Earth' },  -- 6
 		{ '庚', 'Metal' },  -- 7
 		{ '辛', 'Metal' },  -- 8
 		{ '壬', 'Water' },  -- 9
 		{ '癸', 'Water' }   -- 10
 	}
 
 	local earthlyBranches = {
 		{ '子', '[[Rat (zodiac)|Rat]]' },           -- 1
 		{ '丑', '[[Ox (zodiac)|Ox]]' },             -- 2
 		{ '寅', '[[Tiger (zodiac)|Tiger]]' },       -- 3
 		{ '卯', '[[Rabbit (zodiac)|Rabbit]]' },     -- 4
 		{ '辰', '[[Dragon (zodiac)|Dragon]]' },     -- 5
 		{ '巳', '[[Snake (zodiac)|Snake]]' },       -- 6
 		{ '午', '[[Horse (zodiac)|Horse]]' },       -- 7
 		{ '未', '[[Goat (zodiac)|Goat]]' },         -- 8
 		{ '申', '[[Monkey (zodiac)|Monkey]]' },     -- 9
 		{ '酉', '[[Rooster (zodiac)|Rooster]]' },   -- 10
 		{ '戌', '[[Dog (zodiac)|Dog]]' },           -- 11
 		{ '亥', '[[Pig (zodiac)|Pig]]' }            -- 12
 	}
 
 	-- Calculate the cycle numbers from the year. The first sexagenary year corresponds to the ''previous'' year's entry
 	-- in [[Chinese calendar correspondence table]], as the Chinese New Year doesn't happen until Jan/Feb in
 	-- Gregorian years.
 	local sexagenaryYear1 = ( year - 4 ) % 60
 	local sexagenaryYear2 = ( year - 3 ) % 60
 	local heavenlyNum1 = (sexagenaryYear1 - 1) % 10 + 1 -- amod, since lua arrays are 1-indexed
 	local heavenlyNum2 = (sexagenaryYear2 - 1) % 10 + 1
 	local earthlyNum1 = (sexagenaryYear1 - 1) % 12 + 1
 	local earthlyNum2 = (sexagenaryYear2 - 1) % 12 + 1
 
 	-- Get the data tables for each permutation.
 	local heavenlyTable1 = heavenlyStems[ heavenlyNum1 ]
 	local heavenlyTable2 = heavenlyStems[ heavenlyNum2 ]
 	local earthlyTable1 = earthlyBranches[ earthlyNum1 ]
 	local earthlyTable2 = earthlyBranches[ earthlyNum2 ]
 
 	-- Work out the continously-numbered year. (See [[Chinese calendar#Continuously numbered years]].)
 	local year1 = year + 2696
 	local year2 = year + 2697
 	local year1Alt = year1 - 60
 	local year2Alt = year2 - 60
 
 	-- Format any negative numbers.
 	year1 = formatNegative( tostring( year1 ) )
 	year2 = formatNegative( tostring( year2 ) )
 	year1Alt = formatNegative( tostring( year1Alt ) )
 	year2Alt = formatNegative( tostring( year2Alt ) )
 
 	-- Return all of that data in a (hopefully) reader-friendly format.
 	chinese:setYear( string.format(
 			[=[[[Sexagenary cycle|%s%s]]年 (%s&amp;nbsp;%s)&lt;br /&gt;%s or %s&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;''—&amp;nbsp;to&amp;nbsp;—''&lt;br /&gt;%s%s年 (%s&amp;nbsp;%s)&lt;br /&gt;%s or %s]=],
 			heavenlyTable1[ 1 ],
 			earthlyTable1[ 1 ],
 			heavenlyTable1[ 2 ],
 			earthlyTable1[ 2 ],
 			year1,
 			year1Alt,
 			heavenlyTable2[ 1 ],
 			earthlyTable2[ 1 ],
 			heavenlyTable2[ 2 ],
 			earthlyTable2[ 2 ],
 			year2,
 			year2Alt
 			) )
 
 	box:addCalendar( chinese )
 
 	----------------------------------------------------------------------
 	-- Coptic calendar
 	----------------------------------------------------------------------
 
 	local coptic = calendar:new()
 	coptic:setLink( 'Coptic calendar' )
 	coptic:setYearRange( year - 284, year - 283 )
 	box:addCalendar( coptic )
 
 	----------------------------------------------------------------------
 	-- Discordian calendar
 	----------------------------------------------------------------------
 
 	local discordian = calendar:new()
 	discordian:setLink( 'Discordian calendar' )
 	discordian:setYear( year + 1166 )
 	box:addCalendar( discordian )
 
 	----------------------------------------------------------------------
 	-- Ethiopian calendar
 	----------------------------------------------------------------------
 
 	local ethiopian = calendar:new()
 	ethiopian:setLink( 'Ethiopian calendar' )
 	ethiopian:setYearRange( year - 8, year - 7 )
 	box:addCalendar( ethiopian )
 
 	----------------------------------------------------------------------
 	-- Hebrew calendar
 	----------------------------------------------------------------------
 
 	local hebrew = calendar:new()
 	hebrew:setLink( 'எபிரேய நாட்காட்டி' )
 	hebrew:setYearRange( year + 3760, year + 3761 )
 	box:addCalendar( hebrew )
 
 	----------------------------------------------------------------------
 	-- Hindu calendars
 	----------------------------------------------------------------------
 
 	local hindu = calendarGroup:new{ heading = '[[இந்து நாட்காட்டி]]கள்' }
 
 	-- Vikram Samvat
 
 	local vikramSamvat = calendar:new()
 	vikramSamvat:setLink( 'விக்ரம் நாட்காட்டி' )
 	vikramSamvat:setYearRange( year + 56, year + 57 )
 	hindu:addCalendar( vikramSamvat )
 
 	-- Shaka Samvat
 
 	local shakaSamvat = calendar:new()
 	shakaSamvat:setLink( 'இந்தியத் தேசிய நாட்காட்டி', 'சக சம்வாட்' )
 	if year &gt;= 78 then
 		shakaSamvat:setYearRange( year - 79, year - 78 )
 	end
 	hindu:addCalendar( shakaSamvat )
 
 	-- Kali Yuga
 
 	local kaliYuga = calendar:new()
 	kaliYuga:setLink( 'கலி யுகம்' ) -- use italics
 	kaliYuga:setYearRange( year + 3100, year + 3101 )
 	hindu:addCalendar( kaliYuga )
 
 	box:addCalendarGroup( hindu )
 
 	----------------------------------------------------------------------
 	-- Holocene calendar
 	----------------------------------------------------------------------
 
 	local holocene = calendar:new()
 	holocene:setLink( 'Holocene calendar' )
 	holocene:setYear( year + 10000 )
 	box:addCalendar( holocene )
 
 	----------------------------------------------------------------------
 	-- Igbo calendar
 	----------------------------------------------------------------------
 
 	-- In the old template this was a calendar group with just one calendar; intentionally adding this as a single
 	-- calendar here, as the previous behaviour looked like a mistake.
 	if year &gt;= 1000 then
 		local igbo = calendar:new()
 		igbo:setLink( 'Igbo calendar' )
 		igbo:setYearRange( year - 1000, year - 999 )
 		box:addCalendar( igbo )
 	end
 
 	----------------------------------------------------------------------
 	-- Iranian calendar
 	----------------------------------------------------------------------
 
 	local iranian = calendar:new()
 	iranian:setLink( 'இரானிய நாட்காட்டிகள்', 'இரானிய நாட்காட்டி' )
 	if year - 621 &gt; 0 then
 		iranian:setYearRange( year - 622, year - 621 )
 	else
 		iranian:setYear( string.format( '%d BP&amp;nbsp;– %d BP', 622 - year, 621 - year ) )
 	end
 	box:addCalendar( iranian )
 
 	----------------------------------------------------------------------
 	-- Islamic calendar
 	----------------------------------------------------------------------
 
 	local islamic = calendar:new()
 	islamic:setLink( 'இசுலாமிய நாட்காட்டி' )
 	local islamicMult = 1.030684 -- the factor to multiply by
 	local islamicSub = 621.5643 -- the factor to subtract by
 	if year - 621 &gt; 0 then
 		local year1 = math.floor( islamicMult * ( year - islamicSub ) )
 		local year2 = math.floor( islamicMult * ( year - islamicSub + 1 ) )
 		islamic:setYearRange( year1, year2 )
 	else
 		local year1 = math.ceil( -islamicMult * ( year - islamicSub ) )
 		local year2 = math.ceil( -islamicMult * ( year - islamicSub + 1 ) )
 		islamic:setYear( string.format( '%d BH&amp;nbsp;– %d BH', year1, year2 ) )
 	end
 	box:addCalendar( islamic )
 
 	----------------------------------------------------------------------
 	-- Japanese calendar
 	-- starting 600
 	----------------------------------------------------------------------
 	
 	if year &gt;= 600 then
 	local japanese = calendar:new()
 	japanese:setLink( 'சப்பானிய நாட்காட்டி' )
 
 	japanese.thisEra = japaneseEra:new{ year = year }
 	if japanese.thisEra then
 		local japaneseYearText = {}
 		japanese.oldEra = japanese.thisEra:getOldEra()
 		if japanese.oldEra and japanese.oldEra.eraYear and japanese.thisEra.article ~= japanese.oldEra.article then
 			japanese.oldText = string.format( '%s %d', japanese.oldEra.link, japanese.oldEra.eraYear )
 			table.insert( japaneseYearText, japanese.oldText )
 			table.insert( japaneseYearText, ' / ' )
 		end
 		if japanese.thisEra.eraYear then
 			table.insert( japaneseYearText, string.format( '%s %d', japanese.thisEra.link, japanese.thisEra.eraYear ) )
 		end
 		table.insert( japaneseYearText, string.format( '&lt;br /&gt;(%s%s年)', japanese.thisEra.kanji, japanese.thisEra.eraYearKanji ) )
 		japanese:setYear( table.concat( japaneseYearText ) )
 	end
 
 	box:addCalendar( japanese )
 	end
 
 	----------------------------------------------------------------------
 	-- Javanese calendar
 	----------------------------------------------------------------------
 
 	local javanese = calendar:new()
 	javanese:setLink( 'Javanese calendar' )
 	local javaneseMult = 1.030684 -- the factor to multiply by
 	local javaneseSub = 124.9 -- the factor to subtract by
 	if year - 124 &gt; 0 then
 		local year1 = math.floor( javaneseMult * ( year - javaneseSub ) )
 		local year2 = math.floor( javaneseMult * ( year - javaneseSub + 1 ) )
 		javanese:setYearRange( year1, year2 )
 	else
 		local year1 = math.ceil( -javaneseMult * ( year - javaneseSub ) )
 		local year2 = math.ceil( -javaneseMult * ( year - javaneseSub + 1 ) )
 	end
 	box:addCalendar( javanese )
 	
 	----------------------------------------------------------------------
 	-- Juche calendar
 	-- displays only after 1910
 	----------------------------------------------------------------------
 
 	if year &gt;= 1910 then
 		local juche = calendar:new()
 		juche:setLink( 'Juche calendar' )
 		if year &gt; 1911 then
 			juche:setYear( year - 1911 )
 		end
 		box:addCalendar( juche )
 	end
 
 	----------------------------------------------------------------------
 	-- Julian calendar
 	----------------------------------------------------------------------
 
 	local julian = calendar:new()
 	julian:setLink( 'யூலியன் நாட்காட்டி' )
 
 	if year &gt;= -45 and year &lt; 1582 then
 		julian:setYear(gregorian.year)
 	elseif year &gt;= 1582 then
 		local diff = math.floor(year/100-2) - math.floor(year/400)
 		if year % 100 == 0 and year % 400 ~= 0 then
 			julian:setYear('Gregorian minus ' .. diff-1 .. ' or ' .. diff .. ' days')
 		else
 			julian:setYear('Gregorian minus ' .. diff .. ' days')
 		end
 	end
 
 	box:addCalendar( julian )
 
 	----------------------------------------------------------------------
 	-- Korean calendar
 	----------------------------------------------------------------------
 
 	local korean = calendar:new()
 	korean:setLink( 'கொரியன் நாட்காட்டி' )
 	korean:setYear( year + 2333 )
 	box:addCalendar( korean )
 
 	----------------------------------------------------------------------
 	-- Minguo calendar
 	----------------------------------------------------------------------
 
 	local minguo = calendar:new()
 	minguo:setLink( 'Minguo calendar' )
 	if year &gt; 1949 then
 		local minguoYear = year - 1911
 		minguo:setYear( string.format( '[[Taiwan|ROC]] %d&lt;br /&gt;民國%d年', minguoYear, minguoYear ) )
 	elseif year &gt; 1911 then
 		local minguoYear = year - 1911
 		minguo:setYear( string.format( '[[Republic of China (1912–1949)|ROC]] %d&lt;br /&gt;民國%d年', minguoYear, minguoYear ) )
 	else
 		local minguoYear = 1911 - year + 1
 		minguo:setYear( string.format( '%d before [[Republic of China (1912–1949)|ROC]]&lt;br /&gt;民前%d年', minguoYear, minguoYear ) )
 	end
 	box:addCalendar( minguo )
 	
 	----------------------------------------------------------------------
 	-- Nanakshahi calendar
 	----------------------------------------------------------------------
 
 	local nanakshahi = calendar:new()
 	nanakshahi:setLink( 'Nanakshahi calendar' )
 	nanakshahi:setYear( year - 1468 )
 	box:addCalendar( nanakshahi )
 	
 	----------------------------------------------------------------------
 	-- Seleucid era
 	-- displays from 312 BC until 1200 AD
 	----------------------------------------------------------------------
 	
 	if year &gt;= -311 and year &lt; 1200 then
 		local seleucid = calendar:new()
 			seleucid:setLink( 'Seleucid era' )
 			local addtext = string.format( '[[Anno Graecorum|AG]]')
 		seleucid:setYearCouple( year + 311, year + 312, addtext )
 		box:addCalendar( seleucid )
 	end
 
 	----------------------------------------------------------------------
 	-- Thai solar calendar
 	----------------------------------------------------------------------
 
 	local thai = calendar:new()
 	thai:setLink( 'Thai solar calendar' )
 	if year &gt;= 1941 then
 		thai:setYear( year + 543 )
 	else -- if year &gt;= 1912 or year &lt;= 1887 -- year started in March/April
 		thai:setYearRange( year + 542, year + 543 )
 	-- else -- Rattanakosin Era, 1888?-1912
 	--			thai:setYear( string.format( '%d &amp;nbsp;– %d ([[Rattanakosin Kingdom|Rattanakosin Era]])', year - 1782 , year - 1781 ) )
 	end
 	box:addCalendar( thai )
 
 	----------------------------------------------------------------------
 	-- Tibetan calendar
 	----------------------------------------------------------------------
 
 	local tibetan = calendar:new()
 	tibetan:setLink( 'Tibetan calendar' )
 
 	-- Define the information for the &quot;heavenly stems&quot; and &quot;earthly branches&quot; year cycles.
 	-- See [[Tibetan calendar#Years]] for information.
 
 	local heavenlyStems = {
 		{ '阳木', 'male Wood' },   -- 1
 		{ '阴木', 'female Wood' },   -- 2
 		{ '阳火', 'male Fire' },   -- 3
 		{ '阴火', 'female Fire' },   -- 4
 		{ '阳土', 'male Earth' },  -- 5
 		{ '阴土', 'female Earth' },  -- 6
 		{ '阳金', 'male Iron' },  -- 7
 		{ '阴金', 'female Iron' },  -- 8
 		{ '阳水', 'male Water' },  -- 9
 		{ '阴水', 'female Water' }   -- 10
 	}
 
 	local earthlyBranches = {
 		{ '鼠', '[[Rat (zodiac)|Rat]]' },           -- 1
 		{ '牛', '[[Ox (zodiac)|Ox]]' },             -- 2
 		{ '虎', '[[Tiger (zodiac)|Tiger]]' },       -- 3
 		{ '兔', '[[Rabbit (zodiac)|Rabbit]]' },     -- 4
 		{ '龙', '[[Dragon (zodiac)|Dragon]]' },     -- 5
 		{ '蛇', '[[Snake (zodiac)|Snake]]' },       -- 6
 		{ '马', '[[Horse (zodiac)|Horse]]' },       -- 7
 		{ '羊', '[[Goat (zodiac)|Goat]]' },         -- 8
 		{ '猴', '[[Monkey (zodiac)|Monkey]]' },     -- 9
 		{ '鸡', '[[Rooster (zodiac)|Rooster]]' },   -- 10
 		{ '狗', '[[Dog (zodiac)|Dog]]' },           -- 11
 		{ '猪', '[[Pig (zodiac)|Pig]]' }            -- 12
 	}
 
 	-- Calculate the cycle numbers from the year. The first sexagenary year corresponds to the ''previous'' year's entry
 	-- in [[Tibetan calendar correspondence table]], as the Tibetan New Year doesn't happen until Feb/Mar in
 	-- Gregorian years.
 	local sexagenaryYear1 = ( year - 4 ) % 60
 	local sexagenaryYear2 = ( year - 3 ) % 60
 	local heavenlyNum1 = (sexagenaryYear1 - 1) % 10 + 1 -- amod, since lua arrays are 1-indexed
 	local heavenlyNum2 = (sexagenaryYear2 - 1) % 10 + 1
 	local earthlyNum1 = (sexagenaryYear1 - 1) % 12 + 1
 	local earthlyNum2 = (sexagenaryYear2 - 1) % 12 + 1
 
 	-- Get the data tables for each permutation.
 	local heavenlyTable1 = heavenlyStems[ heavenlyNum1 ]
 	local heavenlyTable2 = heavenlyStems[ heavenlyNum2 ]
 	local earthlyTable1 = earthlyBranches[ earthlyNum1 ]
 	local earthlyTable2 = earthlyBranches[ earthlyNum2 ]
 
 	-- Work out the continously-numbered year. (See [[Tibetan calendar#Years with cardinal numbers]].)
 	local year1 = year + 126
 	local year2 = year + 127
 	local year1Alt1 = year1 - 381
 	local year1Alt2 = year1 - 1153
 	local year2Alt1 = year2 - 381
 	local year2Alt2 = year2 - 1153
 
 	-- Format any negative numbers.
 	year1 = formatNegative( tostring( year1 ) )
 	year2 = formatNegative( tostring( year2 ) )
 	year1Alt1 = formatNegative( tostring( year1Alt1 ) )
 	year1Alt2 = formatNegative( tostring( year1Alt2 ) )
 	year2Alt1 = formatNegative( tostring( year2Alt1 ) )
 	year2Alt2 = formatNegative( tostring( year2Alt2 ) )
 
 	-- Return all of that data in a (hopefully) reader-friendly format.
 	tibetan:setYear( string.format(
 			[=[%s%s年&lt;br /&gt;(%s-%s)&lt;br /&gt;%s or %s or %s&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;''—&amp;nbsp;to&amp;nbsp;—''&lt;br /&gt;%s%s年&lt;br /&gt;(%s-%s)&lt;br /&gt;%s or %s or %s]=],
 			heavenlyTable1[ 1 ],
 			earthlyTable1[ 1 ],
 			heavenlyTable1[ 2 ],
 			earthlyTable1[ 2 ],
 			year1,
 			year1Alt1,
 			year1Alt2,
 			heavenlyTable2[ 1 ],
 			earthlyTable2[ 1 ],
 			heavenlyTable2[ 2 ],
 			earthlyTable2[ 2 ],
 			year2,
 			year2Alt1,
 			year2Alt2
 			) )
 
 	box:addCalendar( tibetan )
 
 	----------------------------------------------------------------------
 	-- Unix time
 	----------------------------------------------------------------------
 
 	local unix = calendar:new()
 
 	local function getUnixTime( year )
 		if year &lt; 1970 then return end
 		local noError, unixTime = pcall( lang.formatDate, lang, 'U', '1 Jan ' .. tostring( year ) )
 		if not noError or noError and not unixTime then return end
 		unixTime = tonumber( unixTime )
 		if unixTime and unixTime &gt;= 0 then
 			return unixTime - 1
 		end
 	end
 	unix.thisYear = getUnixTime( year )
 	unix.nextYear = getUnixTime( year + 1 )
 	if unix.thisYear and unix.nextYear then
 		unix:setLink( 'Unix time' )
 		unix:setYear( (unix.thisYear + 1) .. &quot; – &quot; .. unix.nextYear )
 	end
 
 	box:addCalendar( unix )
 
 	return box:export()
 end
 
 --------------------------------------------------------------------
 -- Process arguments from #invoke
 --------------------------------------------------------------------
 
 local p = {}
 
 function p.main( frame )
 	-- Process the arguments and pass them to the box-building function.
 	local args = getArgs( frame )
 	-- Pass year argument with 'year' parameter or without any name but first argument
 	args.year = args.year or args[1]
 	return makeCalendarBox( args )
 end