Module:Medical cases chart
local yesno = require('Module:Yesno')
 local barBox = require('Module:Bar box')
 
 local lang = mw.getContentLanguage()
 local language = lang:getCode()
 local i18n = require('Module:Medical cases chart/i18n')[language]
 assert(i18n, 'no chart translations to: ' .. mw.language.fetchLanguageName(language, 'ta'))
 local monthAbbrs = {}
 for i = 1, 12 do
 	monthAbbrs[i] = lang:formatDate('M', '2020-' .. ('%02d'):format(i))
 end
 
 local p = {}
 
 function p._toggleButton(active, customtoggles, id, label)
 	local on  = active and '' or ' mw-collapsed'
 	local off = active and ' mw-collapsed' or ''
 	local outString =
 		'&lt;span class=&quot;mw-collapsible' .. on  .. customtoggles .. '&quot; id=&quot;mw-customcollapsible-' .. id .. '&quot; ' ..
 		'style=&quot;border:2px solid lightblue&quot;&gt;' .. label .. '&lt;/span&gt;' ..
 		'&lt;span class=&quot;mw-collapsible' .. off .. customtoggles .. '&quot; id=&quot;mw-customcollapsible-' .. id .. '&quot;&gt;' .. label  .. '&lt;/span&gt;'
 	return outString
 end
 
 function p._yearToggleButton(year)
 	return p._toggleButton(year.l, ' mw-customtoggle-' .. year.year, year.year, year.year)
 end
 
 function p._monthToggleButton(year, month)
 	local lmon, label = lang:lc(month.mon), month.mon
 	local id = (year or '') .. lmon
 	local customtoggles = ' mw-customtoggle-' .. id
 
 	if month.s then
 		label = label .. '&amp;nbsp;' .. month.s -- &quot;Mmm ##&quot;
 		if month.s ~= month.e then -- &quot;Mmm ##–##&quot;
 			label = label .. '–' .. month.e
 		end
 	else
 		customtoggles = customtoggles .. (month.l and customtoggles .. month.l or '')
 	end
 
 	for i, combination in ipairs(month.combinations) do
 		customtoggles = customtoggles .. ' mw-customtoggle-' .. combination -- up to 2 combinations per month so no need to table.concat()
 	end
 
 	return p._toggleButton(false, customtoggles, id, label)
 end
 
 function p._lastXToggleButton(years, duration, combinationsL)
 	local months, id = years[#years].months, 'l' .. duration
 	local i, customtoggles = #months, {' mw-customtoggle-' .. id}
 
 	if #years &gt; 1 then
 		local year = years[#years].year
 		while months[i].l do
 			customtoggles[#customtoggles+1] = ' mw-customtoggle-' .. year .. lang:lc(months[i].mon) .. '-' .. id
 			if i == 1 then
 				if year == years[#years].year then
 					year = years[#years-1].year
 					months = years[#years-1].months
 					i = #months
 				else -- either first month is also lastX month or lastX spans more than 2 years, which is not intended yet
 					break
 				end
 			else
 				i = i - 1
 			end
 		end
 	else
 		while i &gt; 0 and months[i].l do
 			customtoggles[#customtoggles+1] = ' mw-customtoggle-' .. lang:lc(months[i].mon) .. '-' .. id
 			i = i - 1
 		end
 	end
 
 	for i, combinationL in ipairs(combinationsL) do
 		customtoggles[#customtoggles+1] = ' mw-customtoggle-' .. combinationL -- up to 3 combinationsL in 90 days
 	end
 
 	return p._toggleButton(true, table.concat(customtoggles), id, mw.ustring.format(i18n.lastXDays, duration))
 end
 
 function p._buildTogglesBar(dateList, duration, nooverlap)
 	local years = {{year=dateList[1].year, months={{mon=dateList[1].mon, combinations={}}}}}
 	local months, combinationsL = years[1].months, {}
 
 	local function addMonth(month)
 		if month.mon ~= months[#months].mon then -- new month
 			if month.year ~= years[#years].year then -- new year
 				years[#years+1] = {year=month.year, months={}}
 				months = years[#years].months -- switch months list
 			end
 			months[#months+1] = {mon=month.mon, combinations={}}
 		end
 	end
 	for i = 2, #dateList do -- deduplicate years and months
 		if #dateList[i] == 0 then -- specific date
 			addMonth(dateList[i])
 			months[#months].l = months[#months].l or dateList[i].l -- so that both ...-mon and ...-mon-lX classes are created
 		elseif #dateList[i] == 1 then -- interval within month
 			addMonth(dateList[i][1])
 			months[#months].l = months[#months].l or dateList[i].l
 		else -- multimonth interval
 			for j, month in ipairs(dateList[i]) do
 				addMonth(month)
 				months[#months].combinations[#months[#months].combinations+1] = dateList[i].id
 			end
 			combinationsL[#combinationsL+1] = dateList[i].id:find('-l%d+$') and dateList[i].id
 		end
 	end
 
 	if nooverlap then
 		local lastDate = dateList[#dateList]
 		months[#months].e = tonumber(os.date('%d', lastDate.nDate or lastDate.nEndDate or lastDate.nAltEndDate)) -- end of final month
 
 		local i = #dateList
 		repeat
 			i = i - 1
 		until i == 0 or (dateList[i].mon or dateList[i][1].mon) ~= months[#months].mon
 		if i == 0 then -- start of first and final month
 			months[#months].s = tonumber(os.date('%d', dateList[1].nDate))
 		else
 			months[#months].s = 1
 		end
 	end
 
 	years[#years].l = true -- to activate toggle and respective months bar
 
 	local monthToggles, divs = {}, nil
 	if #years &gt; 1 then
 		local yearToggles, monthsDivs = {}, {}
 		for i, year in ipairs(years) do
 			yearToggles[#yearToggles+1] = p._yearToggleButton(year)
 			monthToggles = {}
 			months = year.months
 			for j, month in ipairs(months) do
 				monthToggles[#monthToggles+1] = p._monthToggleButton(year.year, month)
 			end
 			monthsDivs[#monthsDivs+1] =
 				'&lt;div class=&quot;mw-collapsible' .. (year.l and '' or ' mw-collapsed') ..
 				'&quot; id=&quot;mw-customcollapsible-' .. year.year .. '&quot;&gt;' .. table.concat(monthToggles) .. '&lt;/div&gt;'
 		end
 		divs = '&lt;div&gt;' .. table.concat(yearToggles) .. '&lt;/div&gt;' .. table.concat(monthsDivs)
 	else
 		for i, month in ipairs(months) do
 			monthToggles[#monthToggles+1] = p._monthToggleButton(nil, month)
 		end
 		divs = '&lt;div&gt;' .. table.concat(monthToggles) .. '&lt;/div&gt;'
 	end
 	divs = divs .. '&lt;div&gt;' .. p._lastXToggleButton(years, duration, combinationsL) .. '&lt;/div&gt;'
 	return '&lt;div class=&quot;nomobile&quot; style=&quot;text-align:center&quot;&gt;' .. divs .. '&lt;/div&gt;'
 end
 
 p._barColors = {
 	'#A50026',  --deaths
 	'SkyBlue',  --recoveries
 	'Tomato',   --cases or altlbl1
 	'Gold',     --altlbl2
 	'OrangeRed' --altlbl3
 }
 
 function p._customBarStacked(args)
 	local barargs = {}
 
 	barargs[1] = args[1]
 
 	local function _numwidth(i)
 		local nw = args.numwidth:sub(i, i)
 		if nw == 'n' then
 			return 0
 		elseif nw == 't' then
 			return 2.45
 		elseif nw == 'm' or nw == 'd' then
 			return 3.5
 		elseif nw == 'w' then
 			return 4.55
 		elseif nw == 'x' then
 			return 5.6
 		end
 	end
 
 	barargs[2] =
 		'&lt;span class=&quot;cbs-ibr&quot; style=&quot;padding:0 0.3em 0 0; width:' .. _numwidth(1) .. 'em&quot;&gt;' .. (args[7] or '') .. '&lt;/span&gt;' ..
 		'&lt;span class=&quot;cbs-ibl&quot; style=&quot;width:' .. _numwidth(2) .. 'em&quot;&gt;' .. (args[8] or '') .. '&lt;/span&gt;'
 
 	if #args.numwidth == 4 then
 		local pad = args.numwidth:sub(3, 3) == 'n' and '0' or '0.3em'
 		barargs.note2 =
 			'&lt;span class=&quot;cbs-ibr&quot; style=&quot;padding:0 ' .. pad .. ' 0 0; width:' .. _numwidth(3) .. 'em&quot;&gt;' .. (args[9] or '') .. '&lt;/span&gt;' ..
 			'&lt;span class=&quot;cbs-ibl&quot; style=&quot;width:' .. _numwidth(4) .. 'em&quot;&gt;' .. (args[10] or '') .. '&lt;/span&gt;'
 	end
 
 	for i = 1, 5 do
 		barargs[2*i + 1] = p._barColors[i]
 		barargs[2*i + 2] = args[i+1] / args.divisor
 		barargs['title' .. i] = args[i+1]
 	end
 
 	barargs.align = 'cdcc'
 	barargs.collapsed = args.collapsed
 	barargs.id = args.id
 	barargs.rowstyle = args.rowheight and 'line-height:'.. args.rowheight ..';'
 
 	return barBox._stacked(barargs)
 end
 
 function p._row(args)
 	local barargs = {}
 
 	barargs[1] = (args[1] or '⋮') .. (args.note0 or '')
 	barargs[2] = args[2] or 0
 	barargs[3] = args[3] or 0
 
 	if args['alttot1'] then
 		barargs[4] = args['alttot1']
 	elseif args[4] then
 		barargs[4] = (args[4] or 0) - (barargs[2] or 0) - (barargs[3] or 0)
 	else
 		barargs[4] = 0
 	end
 
 	barargs[5] = args[5] or 0
 
 	if args['alttot2'] then
 		barargs[6] = args['alttot2']
 	elseif args[6] then
 		barargs[6] = (args[6] or 0) - (barargs[2] or 0) - (barargs[3] or 0)
 	else
 		barargs[6] = 0
 	end
 
 	barargs[7] = args[7]
 
 	local function changeArg(firstright, valuecol, changecol)
 		local change = ''
 		if args['firstright' .. firstright] then
 			change = '(' .. i18n.na .. ')'
 		elseif not args[1] and args[valuecol] then
 			change = '(=)'
 		else
 			change = args[changecol] and '(' .. args[changecol] .. ')' or ''
 		end
 		change = change .. (args['note' .. firstright] or '')
 
 		return change
 	end
 
 	barargs[8] = changeArg(1, 7, 8)
 	barargs[9] = args[9]
 	barargs[10] = changeArg(2, 9, 10)
 
 	barargs.divisor = args.divisor
 	barargs.numwidth = args.numwidth
 	barargs.rowheight = args.rowheight
 
 	local dates
 	if args.collapsible then
 		local duration = args.duration
 		if args.daysToEnd &gt;= duration then
 			barargs.collapsed = 'y'
 		else
 			barargs.collapsed = ''
 		end
 
 		if args.nooverlap and args.daysToEnd &lt; duration then
 			barargs.id = 'l' .. duration
 		elseif args.nDate then
 			dates = {year=tonumber(os.date('%Y', args.nDate)), mon=lang:formatDate('M', os.date('%Y-%m', args.nDate)),
 				l=args.daysToEnd &lt; duration and '-l' .. duration, nDate=args.nDate}
 			barargs.id = (args.multiyear and dates.year or '') .. lang:lc(dates.mon) .. (dates.l or '')
 		else
 			local id, y, m, ey, em = {},
 				tonumber(os.date('%Y', args.nStartDate or args.nAltStartDate)),
 				tonumber(os.date('%m', args.nStartDate or args.nAltStartDate)),
 				tonumber(os.date('%Y', args.nEndDate   or args.nAltEndDate  )),
 				tonumber(os.date('%m', args.nEndDate   or args.nAltEndDate  ))
 			dates = {nStartDate=args.nStartDate, nAltStartDate=args.nAltStartDate, nEndDate=args.nEndDate, nAltEndDate=args.nAltEndDate}
 
 			repeat
 				id[#id+1] = (args.multiyear and y or '') .. lang:lc(monthAbbrs[m])
 				dates[#dates+1] = {year=y, mon=monthAbbrs[m]}
 				y = y + math.floor(m / 12)
 				m = m % 12 + 1
 			until y == ey and m &gt; em or y &gt; ey
 
 			dates.l = args.daysToEnd &lt; duration and '-l' .. duration
 			id = table.concat(id, '-') .. (dates.l or '')
 			barargs.id = id
 			dates.id = id
 		end
 	else
 		barargs.collapsed = ''
 		barargs.id = ''
 	end
 
 	return p._customBarStacked(barargs), dates
 end
 
 function p._buildBars(args)
 	local frame = mw.getCurrentFrame()
 	local updatePeriod = 86400 -- temporary implementation only supports daily updates
 
 	local function getUnix(timestamp)
 		return lang:formatDate('U', timestamp)
 	end
 
 	local rows, prevRow = {}, {}
 	for line in mw.text.gsplit(args.data, '\n') do
 		local i, barargs = 1, {}
 		-- parameter parsing, basic type/missing value handling
 		for parameter in mw.text.gsplit(line, ';') do
 			if parameter:find('^%s*%a') then
 				parameter = mw.text.split(parameter, '=')
 				parameter[1] = mw.text.trim(parameter[1])
 				if parameter[1]:find('^alttot') then
 					parameter[2] = tonumber(frame:callParserFunction('#expr', parameter[2]))
 				else
 					parameter[2] = mw.text.trim(parameter[2])
 					if parameter[1]:find('^firstright') then
 						parameter[2] = yesno(parameter[2])
 					elseif parameter[2] == '' then
 						parameter[2] = nil
 					end
 				end
 				barargs[parameter[1]] = parameter[2]
 			else
 				parameter = mw.text.trim(parameter)
 				if parameter ~= '' then
 					if i &gt;= 2 and i &lt;= 6 then
 						parameter = tonumber(frame:callParserFunction('#expr', parameter))
 						assert(parameter, 'data parameters 2 to 6 must not be formatted')
 					end
 					barargs[i] = parameter
 				end
 				i = i + 1
 			end
 		end
 
 		local bValid, nDateDiff
 		-- get relevant date info based on previous row
 		if barargs[1] then
 			bValid, barargs.nDate = pcall(getUnix, barargs[1])
 			assert(bValid, 'invalid date &quot;' .. barargs[1] .. '&quot;')
 			if prevRow.nDate or prevRow.nEndDate then
 				nDateDiff = barargs.nDate - (prevRow.nDate or prevRow.nEndDate)
 				if nDateDiff &gt; updatePeriod then
 					if nDateDiff == 2 * updatePeriod then
 						prevRow = {nDate=barargs.nDate-updatePeriod}
 						prevRow[1] = os.date('%Y-%m-%d', prevRow.nDate)
 					else
 						prevRow = {nStartDate=(prevRow.nDate or prevRow.nEndDate)+updatePeriod, nEndDate=barargs.nDate-updatePeriod}
 					end
 					rows[#rows+1] = prevRow
 				end
 			else
 				prevRow.nEndDate = barargs.nDate - updatePeriod
 				if prevRow.nStartDate == prevRow.nEndDate then
 					prevRow.nDate = prevRow.nEndDate
 					prevRow[1] = os.date('%Y-%m-%d', prevRow.nDate)
 				-- as nAltStartDate assumes a minimal multiday interval, it's possible for it to be greater if a true previous span is 1 day
 				elseif prevRow.nAltStartDate and prevRow.nAltStartDate &gt;= prevRow.nEndDate then
 					error('a row in a consecutive intervals group is 1 day long and misses the date parameter')
 				end
 			end
 		else
 			if barargs.enddate then
 				bValid, barargs.nEndDate = pcall(getUnix, barargs.enddate)
 				assert(bValid, 'invalid enddate &quot;' .. barargs.enddate .. '&quot;')
 			end
 			if prevRow.nDate or prevRow.nEndDate then
 				barargs.nStartDate = (prevRow.nDate or prevRow.nEndDate) + updatePeriod
 				if barargs.nStartDate == barargs.nEndDate then
 					barargs.nDate = barargs.nEndDate
 					barargs[1] = os.date('%Y-%m-%d', barargs.nDate)
 				end
 			else
 				prevRow.nAltEndDate = (prevRow.nStartDate or prevRow.nAltStartDate) + updatePeriod
 				barargs.nAltStartDate = prevRow.nAltEndDate + updatePeriod
 				if barargs.nEndDate and barargs.nAltStartDate &gt;= barargs.nEndDate then
 					error('a row in a consecutive intervals group is 1 day long and misses the date parameter')
 				end
 			end
 		end
 
 		local function fillCols(col, change)
 			local data = args['right' .. col .. 'data']
 			local changetype = args['changetype' .. col]
 			local value, num, prevnum
 
 			if data == 'alttot1' then
 				num = barargs.alttot1 or barargs[4]
 				prevnum = prevRow.alttot1 or prevRow[4]
 			elseif data == 'alttot2' then
 				num = barargs.alttot2 or barargs[6]
 				prevnum = prevRow.alttot2 or prevRow[6]
 			elseif data then
 				num = barargs[data+1]
 				prevnum = prevRow[data+1]
 			end
 
 			if data and num then -- nothing in column, source found, and data exists
 				value = changetype == 'o' and '' or lang:formatNum(num) -- set value to num if changetype isn't 'o'
 
 				if not change and not barargs['firstright' .. col] then
 					if prevnum and prevnum ~= 0 then -- data on previous row
 						if num - prevnum ~= 0 then --data has changed since previous row
 							change = num-prevnum
 							if changetype == 'a' then -- change type is &quot;absolute&quot;
 								if change &gt; 0 then
 									change = '+' .. lang:formatNum(change)
 								end
 							else -- change type is &quot;percent&quot;, &quot;only percent&quot; or undefined
 								local percent = 100 * change / prevnum -- calculate percent
 								local rounding = math.abs(percent) &gt;= 10 and '%.0f' or math.abs(percent) &gt;= 1 and '%.1f' or '%.2f'
 								percent = tonumber(rounding:format(percent)) -- round to two sigfigs
 
 								if percent &gt; 0 then
 									change = '+' .. lang:formatNum(percent) .. '%'
 								elseif percent &lt; 0 then
 									change = lang:formatNum(percent) .. '%'
 								else
 									change = '='
 								end
 							end
 						else -- data has not changed since previous row
 							change = '='
 						end
 					else -- no data on previous row
 						barargs['firstright' .. col] = true -- set to (n.a.)
 					end
 				end
 			end
 
 			return value, change
 		end
 
 		if not barargs[7] then
 			barargs[7], barargs[8] = fillCols(1, barargs[8])
 		end
 		if not barargs[9] then
 			barargs[9], barargs[10] = fillCols(2, barargs[10])
 		end
 
 		rows[#rows+1] = barargs
 		prevRow = barargs
 	end
 
 	-- calculate and pass repetitive (except daysToEnd) parameters to each row
 	local lastRow = rows[#rows]
 	local total = {lastRow[2] or 0, lastRow[3] or 0, [4]=lastRow[5] or 0}
 	total[3] = lastRow.alttot1 or lastRow[4] and lastRow[4] - total[1] - total[2] or 0
 	total[5] = lastRow.alttot2 or lastRow[6] and lastRow[6] - total[1] - total[2] or 0
 	local divisor = (total[1] + total[2] + total[3] + total[4] + total[5]) / (0.95 * args.barwidth)
 	local firstDate, lastDate = rows[1].nDate, lastRow.nDate or lastRow.nEndDate
 	local multiyear = os.date('%Y', firstDate) ~= os.date('%Y', lastDate - (args.nooverlap and args.duration * 86400 or 0))
 	if args.collapsible ~= false then
 		args.collapsible = (lastDate - firstDate) / 86400 &gt;= args.duration
 	end
 
 	local bars, dateList = {}, {}
 	for i, row in ipairs(rows) do -- build rows
 		row.divisor = divisor
 		row.numwidth = args.numwidth
 		row.rowheight = args.rowheight
 		row.collapsible = args.collapsible
 		row.duration = args.duration
 		row.nooverlap = args.nooverlap
 		row.daysToEnd = (lastDate - (row.nDate or row.nEndDate or row.nAltEndDate)) / 86400
 		row.multiyear = multiyear
 
 		bars[#bars+1], dateList[#dateList+1] = p._row(row)
 	end
 
 	return table.concat(bars), dateList
 end
 
 function p._legend0(args)
 	return
 		'&lt;span style=&quot;font-size:90%; margin:0px&quot;&gt;' ..
 			'&lt;span style=&quot;background-color:' .. (args[1] or 'none') ..
 			'; border:' .. (args.border or 'none') ..
 			'; color:' .. (args[1] or 'none') .. '&quot;&gt;' ..
 				'&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;' .. '&lt;/span&gt;' ..
 			'&amp;nbsp;' .. (args[2] or '') .. '&lt;/span&gt;'
 end
 
 function p._chart(args)
 	for key, value in pairs(args) do
 		if ({float=1, barwidth=1, numwidth=1, changetype=1})[key:gsub('%d', '')] then
 			args[key] = value:lower()
 		end
 	end
 
 	local barargs = {}
 
 	barargs.css = 'Module:Medical cases chart/styles.css'
 	barargs.float = args.float or 'right'
 
 	args.barwidth = args.barwidth or 'medium'
 	local barwidth
 	if args.barwidth == 'thin' then
 		barwidth = 120
 	elseif args.barwidth == 'medium' then
 		barwidth = 280
 	elseif args.barwidth == 'wide' then
 		barwidth = 400
 	elseif args.barwidth == 'auto' then
 		barwidth = 'auto'
 	else
 		error('unrecognized barwidth')
 	end
 
 	local function _numwidth(i)
 		local nw = args.numwidth:sub(i, i)
 		if nw == 'n' then
 			return 0
 		elseif nw == 't' then
 			return 40
 		elseif nw == 'm' or nw == 'd' then
 			return 55
 		elseif nw == 'w' then
 			return 70
 		elseif nw == 'x' then
 			return 85
 		else
 			error('unrecognized numwidth[' .. i .. ']')
 		end
 	end
 
 	args.numwidth = args.numwidth or 'mm'
 	local numwidth = _numwidth(1) + 10 + _numwidth(2)
 	local right1width = numwidth
 	if #args.numwidth == 4 then
 		numwidth = numwidth + _numwidth(3) + _numwidth(4)
 		if args.numwidth:sub(3, 3) == 'n' then
 			numwidth = numwidth + 6
 		else
 			numwidth = numwidth + 10
 		end
 		if not args.right2 then
 			right1width = numwidth
 		end
 	end
 	right1width = right1width - 8 -- -8 because of padding
 
 	if tonumber(barwidth) then
 		barargs.width = 85 + barwidth + numwidth .. 'px'
 		barargs.barwidth = barwidth .. 'px'
 	else
 		barargs.width = 'auto'
 		barargs.barwidth = 'auto'
 	end
 
 	local title = {}
 
 	local function spaces(n)
 		local nbsp = '&amp;nbsp;'
 		return '&lt;span class=&quot;nowrap&quot;&gt;' .. nbsp:rep(n) .. '&lt;/span&gt;'
 	end
 
 	local location = lang:ucfirst(mw.ustring.gsub(args.location, i18n.the_, ''))
 	local navbartitle = args.outbreak .. i18n._data .. '/' ..
 		(args.location3 and args.location3 .. '/' or '') ..
 		(args.location2 and args.location2 .. '/' or '') ..
 		location .. i18n._medicalCasesChart
 
 	local navbar = require('Module:Navbar')._navbar
 	title[1] = (args.pretitle and args.pretitle .. ' ' or '') ..
 		args.disease .. ' ' .. i18n.casesIn .. ' ' .. args.location ..
 		(args.location2 and ', ' .. args.location2 or '') ..
 		(args.location3 and ', ' .. args.location3 or '') ..
 		(args.posttitle and ' ' .. args.posttitle or '') .. spaces(2) ..'(' ..
 		navbar({navbartitle, titleArg=':' .. mw.getCurrentFrame():getParent():getTitle(), mini=1, nodiv=1}) ..
 		')&lt;br /&gt;'
 
 	title[2] = p._legend0({p._barColors[1], i18n.deaths})
 	args.recoveries = args.recoveries == nil and true or args.recoveries
 	title[3] = args.recoveries and spaces(3) .. p._legend0({p._barColors[2], args.reclbl or i18n.recoveries}) or ''
 	title[4] = args.altlbl1 ~= 'hide' and spaces(3) .. p._legend0({p._barColors[3], args.altlbl1 or i18n.activeCases}) or ''
 	title[5] = args.altlbl2 and spaces(3) .. p._legend0({p._barColors[4], args.altlbl2}) or ''
 	title[6] = args.altlbl3 and spaces(3) .. p._legend0({p._barColors[5], args.altlbl3}) or ''
 
 	local togglesbar, buildargs = nil, {}
 
 	args.right1 = args.right1 or i18n.noOfCases
 	args.duration = args.duration or 15
 	args.nooverlap = args.nooverlap or false
 
 	buildargs.barwidth = tonumber(barwidth) or 280
 	buildargs.numwidth = args.numwidth
 	buildargs.rowheight = args.rowheight
 	if args.datapage then
 		local externalData = require('Module:Medical cases chart/data')._externalData
 		buildargs.data = externalData(args)
 	else
 		buildargs.data = args.data
 	end
 	-- if no right1data and right1 title is cases, use 3rd classification
 	buildargs.right1data = args.right1data or args.right1 == i18n.noOfCases and 3
 	-- if no right2data and right2 title is deaths, use 1st classification
 	buildargs.right2data = args.right2data or (args.right2 == i18n.noOfDeaths or args.right2 == i18n.noOfDeaths2) and 1
 	buildargs.changetype1 = (args.changetype1 or args.changetype or ''):sub(1, 1) -- 1st letter
 	buildargs.changetype2 = (args.changetype2 or args.changetype or ''):sub(1, 1) -- 1st letter
 	buildargs.collapsible = args.collapsible
 	buildargs.duration = args.duration
 	buildargs.nooverlap = args.nooverlap
 
 	local dateList
 	barargs.bars, dateList = p._buildBars(buildargs)
 
 	if buildargs.collapsible then
 		togglesbar = p._buildTogglesBar(dateList, args.duration, args.nooverlap)
 	end
 
 	title[7] = togglesbar and '&lt;br /&gt;' .. togglesbar or ''
 	barargs.title = table.concat(title)
 
 	barargs.left1 =
 		'&lt;div class=&quot;center&quot; style=&quot;width:77px&quot;&gt;' .. -- 85-8 because of padding
 			&quot;'''&quot; .. i18n.date .. &quot;'''&quot; .. '&lt;/div&gt;'
 
 	barargs.right1 =
 		'&lt;div class=&quot;center&quot; style=&quot;width:' .. right1width .. 'px&quot;&gt;' ..
 			&quot;'''&quot; .. args.right1 .. &quot;'''&quot; .. '&lt;/div&gt;'
 
 	if args.right2 then
 		local right2width = numwidth - right1width - 16 -- -8-8...
 		barargs.right2 =
 			'&lt;div class=&quot;center&quot; style=&quot;width:' .. right2width ..'px&quot;&gt;' ..
 				&quot;'''&quot; .. args.right2 .. &quot;'''&quot; .. '&lt;/div&gt;'
 	end
 
 	barargs.caption = args.caption
 	return barBox._box(barargs)
 end
 
 function p.chart(frame)
 	local getArgs = require('Module:Arguments').getArgs
 	local args = getArgs(frame, {
 		valueFunc = function (key, value)
 			if value and value ~= '' then
 				key = key:gsub('%d', '')
 				if ({rowheight=1, duration=1, rightdata=1})[key] then -- if key in {...}
 					return tonumber(value) or value
 				end
 				if ({recoveries=1, collapsible=1, nooverlap=1})[key] then
 					return yesno(value)
 				end
 				return value
 			end
 			return nil
 		end
 	})
 	return p._chart(args)
 end