<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://stockhub.co/index.php?action=history&amp;feed=atom&amp;title=Module%3AMedical_cases_chart%2Fsandbox</id>
	<title>Module:Medical cases chart/sandbox - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://stockhub.co/index.php?action=history&amp;feed=atom&amp;title=Module%3AMedical_cases_chart%2Fsandbox"/>
	<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Medical_cases_chart/sandbox&amp;action=history"/>
	<updated>2026-05-24T10:14:57Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://stockhub.co/index.php?title=Module:Medical_cases_chart/sandbox&amp;diff=143951&amp;oldid=prev</id>
		<title>imported&gt;GKFX: Update with fresh copy of Module:Medical cases chart</title>
		<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Medical_cases_chart/sandbox&amp;diff=143951&amp;oldid=prev"/>
		<updated>2022-11-17T00:41:49Z</updated>

		<summary type="html">&lt;p&gt;Update with fresh copy of &lt;a href=&quot;/research/Module:Medical_cases_chart&quot; title=&quot;Module:Medical cases chart&quot;&gt;Module:Medical cases chart&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local yesno = require(&amp;#039;Module:Yesno&amp;#039;)&lt;br /&gt;
local BarBox = unpack(require(&amp;#039;Module:Bar box&amp;#039;))&lt;br /&gt;
&lt;br /&gt;
local lang = mw.getContentLanguage()&lt;br /&gt;
local language = lang:getCode()&lt;br /&gt;
local i18n = require(&amp;#039;Module:Medical cases chart/i18n&amp;#039;)[language]&lt;br /&gt;
assert(i18n, &amp;#039;no chart translations to: &amp;#039; .. mw.language.fetchLanguageName(language, &amp;#039;en&amp;#039;))&lt;br /&gt;
local monthAbbrs = {}&lt;br /&gt;
for i = 1, 12 do&lt;br /&gt;
	monthAbbrs[i] = lang:formatDate(&amp;#039;M&amp;#039;, &amp;#039;2020-&amp;#039; .. (&amp;#039;%02d&amp;#039;):format(i))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function p._findIntervalRow(tRows, nTime, nTol, bAll)&lt;br /&gt;
	-- Loop backwards in tRows, assuming it to have monotonically increasing nDate entries in forward order.&lt;br /&gt;
	-- The first row with nDate within nTime +-nTol is returned.&lt;br /&gt;
	-- If nDate table entry is nil, the row will be skipped.&lt;br /&gt;
	-- If moving backwards a time stamp is found dating back to before tolerance window, nil is returned.&lt;br /&gt;
	-- If the end of tRows is reached without a match for the tolerance window, also nil is returned.&lt;br /&gt;
	-- With bAll present and true all rows back to the specified time window will be returned, or all rows back to&lt;br /&gt;
	-- the first row, that does not lie beyond nTime +-nTol if no match was found.&lt;br /&gt;
	local tRet = nil&lt;br /&gt;
	if bAll then&lt;br /&gt;
		tRet = {}&lt;br /&gt;
	end&lt;br /&gt;
	for nRowNum = #tRows, 1 ,-1 do&lt;br /&gt;
		if tRows[nRowNum] and tRows[nRowNum].nDate then&lt;br /&gt;
			local nDiff = nTime - tRows[nRowNum].nDate&lt;br /&gt;
			if nDiff &amp;gt; -nTol then&lt;br /&gt;
				if nDiff &amp;lt; nTol then&lt;br /&gt;
					if bAll then&lt;br /&gt;
						tRet[#tRet + 1] = tRows[nRowNum]&lt;br /&gt;
						return tRet&lt;br /&gt;
					else&lt;br /&gt;
						return tRows[nRowNum]&lt;br /&gt;
					end&lt;br /&gt;
				else&lt;br /&gt;
					return bAll and tRet or nil&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if bAll then&lt;br /&gt;
			tRet[#tRet + 1] = tRows[nRowNum]&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	--return tRows[nRowNum]&lt;br /&gt;
	return nil&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function p._toggleButton(active, customtoggles, id, label)&lt;br /&gt;
	local on  = active and &amp;#039;&amp;#039; or &amp;#039; mw-collapsed&amp;#039;&lt;br /&gt;
	local off = active and &amp;#039; mw-collapsed&amp;#039; or &amp;#039;&amp;#039;&lt;br /&gt;
	local outString =&lt;br /&gt;
		&amp;#039;&amp;lt;span class=&amp;quot;mw-collapsible&amp;#039; .. on  .. customtoggles .. &amp;#039;&amp;quot; id=&amp;quot;mw-customcollapsible-&amp;#039; .. id .. &amp;#039;&amp;quot; &amp;#039; ..&lt;br /&gt;
		&amp;#039;style=&amp;quot;border:2px solid lightblue&amp;quot;&amp;gt;&amp;#039; .. label .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039; ..&lt;br /&gt;
		&amp;#039;&amp;lt;span class=&amp;quot;mw-collapsible&amp;#039; .. off .. customtoggles .. &amp;#039;&amp;quot; id=&amp;quot;mw-customcollapsible-&amp;#039; .. id .. &amp;#039;&amp;quot;&amp;gt;&amp;#039; .. label  .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
	return outString&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._yearToggleButton(year)&lt;br /&gt;
	return p._toggleButton(year.l, &amp;#039; mw-customtoggle-&amp;#039; .. year.year, year.year, year.year)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._monthToggleButton(year, month)&lt;br /&gt;
	local lmon, label = lang:lc(month.mon), month.mon&lt;br /&gt;
	local id = (year or &amp;#039;&amp;#039;) .. lmon&lt;br /&gt;
	local customtoggles = &amp;#039; mw-customtoggle-&amp;#039; .. id&lt;br /&gt;
&lt;br /&gt;
	if month.s then&lt;br /&gt;
		label = label .. &amp;#039;&amp;amp;nbsp;&amp;#039; .. month.s -- &amp;quot;Mmm ##&amp;quot;&lt;br /&gt;
		if month.s ~= month.e then -- &amp;quot;Mmm ##–##&amp;quot;&lt;br /&gt;
			label = label .. &amp;#039;–&amp;#039; .. month.e&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		customtoggles = customtoggles .. (month.l and customtoggles .. month.l or &amp;#039;&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	for i, combination in ipairs(month.combinations) do&lt;br /&gt;
		customtoggles = customtoggles .. &amp;#039; mw-customtoggle-&amp;#039; .. combination -- up to 2 combinations per month so no need to table.concat()&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return p._toggleButton(false, customtoggles, id, label)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._lastXToggleButton(years, duration, combinationsL)&lt;br /&gt;
	local months, id = years[#years].months, &amp;#039;l&amp;#039; .. duration&lt;br /&gt;
	local i, customtoggles = #months, {&amp;#039; mw-customtoggle-&amp;#039; .. id}&lt;br /&gt;
&lt;br /&gt;
	if #years &amp;gt; 1 then&lt;br /&gt;
		local year = years[#years].year&lt;br /&gt;
		while months[i].l do&lt;br /&gt;
			customtoggles[#customtoggles+1] = &amp;#039; mw-customtoggle-&amp;#039; .. year .. lang:lc(months[i].mon) .. &amp;#039;-&amp;#039; .. id&lt;br /&gt;
			if i == 1 then&lt;br /&gt;
				if year == years[#years].year then&lt;br /&gt;
					year = years[#years-1].year&lt;br /&gt;
					months = years[#years-1].months&lt;br /&gt;
					i = #months&lt;br /&gt;
				else -- either first month is also lastX month or lastX spans more than 2 years, which is not intended yet&lt;br /&gt;
					break&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				i = i - 1&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		while i &amp;gt; 0 and months[i].l do&lt;br /&gt;
			customtoggles[#customtoggles+1] = &amp;#039; mw-customtoggle-&amp;#039; .. lang:lc(months[i].mon) .. &amp;#039;-&amp;#039; .. id&lt;br /&gt;
			i = i - 1&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	for i, combinationL in ipairs(combinationsL) do&lt;br /&gt;
		customtoggles[#customtoggles+1] = &amp;#039; mw-customtoggle-&amp;#039; .. combinationL -- up to 3 combinationsL in 90 days&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return p._toggleButton(true, table.concat(customtoggles), id, mw.ustring.format(i18n.lastXDays, duration))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._buildTogglesBar(dateList, duration, nooverlap)&lt;br /&gt;
	local years = {{year=dateList[1].year, months={{mon=dateList[1].mon, combinations={}}}}}&lt;br /&gt;
	local months, combinationsL = years[1].months, {}&lt;br /&gt;
&lt;br /&gt;
	local function addMonth(month)&lt;br /&gt;
		if month.mon ~= months[#months].mon then -- new month&lt;br /&gt;
			if month.year ~= years[#years].year then -- new year&lt;br /&gt;
				years[#years+1] = {year=month.year, months={}}&lt;br /&gt;
				months = years[#years].months -- switch months list&lt;br /&gt;
			end&lt;br /&gt;
			months[#months+1] = {mon=month.mon, combinations={}}&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	for i = 2, #dateList do -- deduplicate years and months&lt;br /&gt;
		if #dateList[i] == 0 then -- specific date&lt;br /&gt;
			addMonth(dateList[i])&lt;br /&gt;
			months[#months].l = months[#months].l or dateList[i].l -- so that both ...-mon and ...-mon-lX classes are created&lt;br /&gt;
		elseif #dateList[i] == 1 then -- interval within month&lt;br /&gt;
			addMonth(dateList[i][1])&lt;br /&gt;
			months[#months].l = months[#months].l or dateList[i].l&lt;br /&gt;
		else -- multimonth interval&lt;br /&gt;
			for j, month in ipairs(dateList[i]) do&lt;br /&gt;
				addMonth(month)&lt;br /&gt;
				months[#months].combinations[#months[#months].combinations+1] = dateList[i].id&lt;br /&gt;
			end&lt;br /&gt;
			combinationsL[#combinationsL+1] = dateList[i].id:find(&amp;#039;-l%d+$&amp;#039;) and dateList[i].id&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if nooverlap then&lt;br /&gt;
		local lastDate = dateList[#dateList]&lt;br /&gt;
		months[#months].e = tonumber(os.date(&amp;#039;%d&amp;#039;, lastDate.nDate or lastDate.nEndDate or lastDate.nAltEndDate)) -- end of final month&lt;br /&gt;
&lt;br /&gt;
		local i = #dateList&lt;br /&gt;
		repeat&lt;br /&gt;
			i = i - 1&lt;br /&gt;
		until i == 0 or (dateList[i].mon or dateList[i][1].mon) ~= months[#months].mon&lt;br /&gt;
		if i == 0 then -- start of first and final month&lt;br /&gt;
			months[#months].s = tonumber(os.date(&amp;#039;%d&amp;#039;, dateList[1].nDate))&lt;br /&gt;
		else&lt;br /&gt;
			months[#months].s = 1&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	years[#years].l = true -- to activate toggle and respective months bar&lt;br /&gt;
&lt;br /&gt;
	local monthToggles, divs = {}, nil&lt;br /&gt;
	if #years &amp;gt; 1 then&lt;br /&gt;
		local yearToggles, monthsDivs = {}, {}&lt;br /&gt;
		for i, year in ipairs(years) do&lt;br /&gt;
			yearToggles[#yearToggles+1] = p._yearToggleButton(year)&lt;br /&gt;
			monthToggles = {}&lt;br /&gt;
			months = year.months&lt;br /&gt;
			for j, month in ipairs(months) do&lt;br /&gt;
				monthToggles[#monthToggles+1] = p._monthToggleButton(year.year, month)&lt;br /&gt;
			end&lt;br /&gt;
			monthsDivs[#monthsDivs+1] =&lt;br /&gt;
				&amp;#039;&amp;lt;div class=&amp;quot;mw-collapsible&amp;#039; .. (year.l and &amp;#039;&amp;#039; or &amp;#039; mw-collapsed&amp;#039;) ..&lt;br /&gt;
				&amp;#039;&amp;quot; id=&amp;quot;mw-customcollapsible-&amp;#039; .. year.year .. &amp;#039;&amp;quot;&amp;gt;&amp;#039; .. table.concat(monthToggles) .. &amp;#039;&amp;lt;/div&amp;gt;&amp;#039;&lt;br /&gt;
		end&lt;br /&gt;
		divs = &amp;#039;&amp;lt;div&amp;gt;&amp;#039; .. table.concat(yearToggles) .. &amp;#039;&amp;lt;/div&amp;gt;&amp;#039; .. table.concat(monthsDivs)&lt;br /&gt;
	else&lt;br /&gt;
		for i, month in ipairs(months) do&lt;br /&gt;
			monthToggles[#monthToggles+1] = p._monthToggleButton(nil, month)&lt;br /&gt;
		end&lt;br /&gt;
		divs = &amp;#039;&amp;lt;div&amp;gt;&amp;#039; .. table.concat(monthToggles) .. &amp;#039;&amp;lt;/div&amp;gt;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	divs = divs .. &amp;#039;&amp;lt;div&amp;gt;&amp;#039; .. p._lastXToggleButton(years, duration, combinationsL) .. &amp;#039;&amp;lt;/div&amp;gt;&amp;#039;&lt;br /&gt;
	return &amp;#039;&amp;lt;div class=&amp;quot;nomobile&amp;quot; style=&amp;quot;text-align:center&amp;quot;&amp;gt;&amp;#039; .. divs .. &amp;#039;&amp;lt;/div&amp;gt;&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local numwidth = {n=0, t=2.45, m=3.5, d=3.5, w=4.55, x=5.6}&lt;br /&gt;
&lt;br /&gt;
local bkgClasses = {&lt;br /&gt;
	&amp;#039;mcc-d&amp;#039;,	--deaths&lt;br /&gt;
	&amp;#039;mcc-r&amp;#039;,	--recoveries&lt;br /&gt;
	&amp;#039;mcc-c&amp;#039;,	--cases or altlbl1&lt;br /&gt;
	&amp;#039;mcc-a2&amp;#039;,	--altlbl2&lt;br /&gt;
	&amp;#039;mcc-a3&amp;#039;	--altlbl3&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function p._customBarStacked(args)&lt;br /&gt;
	local barargs = {}&lt;br /&gt;
&lt;br /&gt;
	barargs[1] = args[1]&lt;br /&gt;
&lt;br /&gt;
	local function _numwidth(i)&lt;br /&gt;
		return args.numwidth:sub(i,i)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if args[7] or args[8] then -- is it acceptable to have one and not the other?&lt;br /&gt;
		barargs[2] =&lt;br /&gt;
			&amp;#039;&amp;lt;span class=mcc-r&amp;#039; .. _numwidth(1) .. &amp;#039;&amp;gt;&amp;#039; .. (args[7] or &amp;#039;&amp;#039;) .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039; ..&lt;br /&gt;
			&amp;#039;&amp;lt;span class=mcc-l&amp;#039; .. _numwidth(2) .. &amp;#039;&amp;gt;&amp;#039; .. (args[8] or &amp;#039;&amp;#039;) .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	if #args.numwidth == 4 then&lt;br /&gt;
		barargs.note2 = (args[9] or args[10]) and&lt;br /&gt;
			(args.numwidth:sub(3,3) ~= &amp;#039;n&amp;#039; and &amp;#039;&amp;lt;span class=mcc-r&amp;#039; .. _numwidth(3) .. &amp;#039;&amp;gt;&amp;#039; .. (args[9] or &amp;#039;&amp;#039;) .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039; or &amp;#039;&amp;#039;) ..&lt;br /&gt;
			&amp;#039;&amp;lt;span class=mcc-l&amp;#039; .. _numwidth(4) .. &amp;#039;&amp;gt;&amp;#039; .. (args[10] or &amp;#039;&amp;#039;) .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
		or &amp;#039;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	for i = 1, 5 do&lt;br /&gt;
		barargs[i+2] = args[i+1] / args.divisor&lt;br /&gt;
		barargs[&amp;#039;title&amp;#039; .. i] = args[i+1]&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	barargs.align = &amp;#039;cdcc&amp;#039;&lt;br /&gt;
	barargs.bkgclasses = bkgClasses&lt;br /&gt;
	barargs.collapsed = args.collapsed&lt;br /&gt;
	barargs.id = args.id&lt;br /&gt;
&lt;br /&gt;
	return BarBox.stacked(barargs)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._row(args)&lt;br /&gt;
	local barargs = {}&lt;br /&gt;
&lt;br /&gt;
	barargs[1] = (args[1] or &amp;#039;⋮&amp;#039;) .. (args.note0 or &amp;#039;&amp;#039;)&lt;br /&gt;
	barargs[2] = args[2] or 0&lt;br /&gt;
	barargs[3] = args[3] or 0&lt;br /&gt;
&lt;br /&gt;
	if args[&amp;#039;alttot1&amp;#039;] then&lt;br /&gt;
		barargs[4] = args[&amp;#039;alttot1&amp;#039;]&lt;br /&gt;
	elseif args[4] then&lt;br /&gt;
		barargs[4] = (args[4] or 0) - (barargs[2] or 0) - (barargs[3] or 0)&lt;br /&gt;
	else&lt;br /&gt;
		barargs[4] = 0&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	barargs[5] = args[5] or 0&lt;br /&gt;
&lt;br /&gt;
	if args[&amp;#039;alttot2&amp;#039;] then&lt;br /&gt;
		barargs[6] = args[&amp;#039;alttot2&amp;#039;]&lt;br /&gt;
	elseif args[6] then&lt;br /&gt;
		barargs[6] = (args[6] or 0) - (barargs[2] or 0) - (barargs[3] or 0)&lt;br /&gt;
	else&lt;br /&gt;
		barargs[6] = 0&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	barargs[7] = args[7]&lt;br /&gt;
&lt;br /&gt;
	local function changeArg(firstright, valuecol, changecol)&lt;br /&gt;
		local change = &amp;#039;&amp;#039;&lt;br /&gt;
		if args[&amp;#039;firstright&amp;#039; .. firstright] then&lt;br /&gt;
			change = &amp;#039;(&amp;#039; .. i18n.na .. &amp;#039;)&amp;#039;&lt;br /&gt;
		elseif not args[1] and args[valuecol] then&lt;br /&gt;
			change = &amp;#039;(=)&amp;#039;&lt;br /&gt;
		else&lt;br /&gt;
			change = args[changecol] and &amp;#039;(&amp;#039; .. args[changecol] .. &amp;#039;)&amp;#039; or &amp;#039;&amp;#039;&lt;br /&gt;
		end&lt;br /&gt;
		change = change .. (args[&amp;#039;note&amp;#039; .. firstright] or &amp;#039;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
		return change ~= &amp;#039;&amp;#039; and change&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	barargs[8] = changeArg(1, 7, 8)&lt;br /&gt;
	barargs[9] = args[9]&lt;br /&gt;
	barargs[10] = changeArg(2, 9, 10)&lt;br /&gt;
&lt;br /&gt;
	barargs.divisor = args.divisor&lt;br /&gt;
	barargs.numwidth = args.numwidth&lt;br /&gt;
&lt;br /&gt;
	local dates&lt;br /&gt;
	if args.collapsible then&lt;br /&gt;
		local duration = args.duration&lt;br /&gt;
		if args.daysToEnd &amp;gt;= duration then&lt;br /&gt;
			barargs.collapsed = true&lt;br /&gt;
		else&lt;br /&gt;
			barargs.collapsed = false&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		if args.nooverlap and args.daysToEnd &amp;lt; duration then&lt;br /&gt;
			barargs.id = &amp;#039;l&amp;#039; .. duration&lt;br /&gt;
		elseif args.nDate then&lt;br /&gt;
			dates = {year=tonumber(os.date(&amp;#039;%Y&amp;#039;, args.nDate)), mon=lang:formatDate(&amp;#039;M&amp;#039;, os.date(&amp;#039;%Y-%m&amp;#039;, args.nDate)),&lt;br /&gt;
				l=args.daysToEnd &amp;lt; duration and &amp;#039;-l&amp;#039; .. duration, nDate=args.nDate}&lt;br /&gt;
			barargs.id = (args.multiyear and dates.year or &amp;#039;&amp;#039;) .. lang:lc(dates.mon) .. (dates.l or &amp;#039;&amp;#039;)&lt;br /&gt;
		else&lt;br /&gt;
			local id, y, m, ey, em = {},&lt;br /&gt;
				tonumber(os.date(&amp;#039;%Y&amp;#039;, args.nStartDate or args.nAltStartDate)),&lt;br /&gt;
				tonumber(os.date(&amp;#039;%m&amp;#039;, args.nStartDate or args.nAltStartDate)),&lt;br /&gt;
				tonumber(os.date(&amp;#039;%Y&amp;#039;, args.nEndDate   or args.nAltEndDate  )),&lt;br /&gt;
				tonumber(os.date(&amp;#039;%m&amp;#039;, args.nEndDate   or args.nAltEndDate  ))&lt;br /&gt;
			dates = {nStartDate=args.nStartDate, nAltStartDate=args.nAltStartDate, nEndDate=args.nEndDate, nAltEndDate=args.nAltEndDate}&lt;br /&gt;
&lt;br /&gt;
			repeat&lt;br /&gt;
				id[#id+1] = (args.multiyear and y or &amp;#039;&amp;#039;) .. lang:lc(monthAbbrs[m])&lt;br /&gt;
				dates[#dates+1] = {year=y, mon=monthAbbrs[m]}&lt;br /&gt;
				y = y + math.floor(m / 12)&lt;br /&gt;
				m = m % 12 + 1&lt;br /&gt;
			until y == ey and m &amp;gt; em or y &amp;gt; ey&lt;br /&gt;
&lt;br /&gt;
			dates.l = args.daysToEnd &amp;lt; duration and &amp;#039;-l&amp;#039; .. duration&lt;br /&gt;
			id = table.concat(id, &amp;#039;-&amp;#039;) .. (dates.l or &amp;#039;&amp;#039;)&lt;br /&gt;
			barargs.id = id&lt;br /&gt;
			dates.id = id&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		barargs.collapsed = false&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return p._customBarStacked(barargs), dates&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._buildBars(args)&lt;br /&gt;
	local frame = mw.getCurrentFrame()&lt;br /&gt;
	local updatePeriod = 86400 -- temporary implementation only supports daily updates&lt;br /&gt;
&lt;br /&gt;
	local function getUnix(timestamp)&lt;br /&gt;
		return lang:formatDate(&amp;#039;U&amp;#039;, timestamp)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- some info for changetype &amp;#039;w&amp;#039;&lt;br /&gt;
	local sChngTp1 = args.changetype1&lt;br /&gt;
	local sChngTp2 = args.changetype2&lt;br /&gt;
	local xData1Key = args.right1data or 3&lt;br /&gt;
	local xData2Key = args.right2data or 1&lt;br /&gt;
	xData1Key = (type(xData1Key) == &amp;quot;number&amp;quot;) and (xData1Key+1) or xData1Key&lt;br /&gt;
	xData2Key = (type(xData2Key) == &amp;quot;number&amp;quot;) and (xData2Key+1) or xData2Key&lt;br /&gt;
	local nPop = not (args.population == nil) and tonumber(args.population) or nil&lt;br /&gt;
	local bIsW1 = sChngTp1 == &amp;#039;w&amp;#039; and nPop&lt;br /&gt;
	local bIsW2 = sChngTp2 == &amp;#039;w&amp;#039; and nPop&lt;br /&gt;
&lt;br /&gt;
	local rows, prevRow, tStats = {}, {}, {}&lt;br /&gt;
	local nData1Diff1Max, nData1Diff1MaxDate, nData2Diff1Max, nData2Diff1MaxDate&lt;br /&gt;
	local nData1i7Max, nData1i7MaxDate, nData2i7Max, nData2i7MaxDate&lt;br /&gt;
	for line in mw.text.gsplit(args.data, &amp;#039;\n&amp;#039;) do&lt;br /&gt;
		local i, barargs = 1, {}&lt;br /&gt;
		-- line parameter parsing, basic type/missing value handling&lt;br /&gt;
		for parameter in mw.text.gsplit(line, &amp;#039;;&amp;#039;) do&lt;br /&gt;
			if parameter:find(&amp;#039;^%s*%a&amp;#039;) then&lt;br /&gt;
				parameter = mw.text.split(parameter, &amp;#039;=&amp;#039;)&lt;br /&gt;
				parameter[1] = mw.text.trim(parameter[1])&lt;br /&gt;
				if parameter[1]:find(&amp;#039;^alttot&amp;#039;) then&lt;br /&gt;
					parameter[2] = tonumber(frame:callParserFunction(&amp;#039;#expr&amp;#039;, parameter[2]))&lt;br /&gt;
				else&lt;br /&gt;
					parameter[2] = mw.text.trim(parameter[2])&lt;br /&gt;
					if parameter[1]:find(&amp;#039;^firstright&amp;#039;) then&lt;br /&gt;
						parameter[2] = yesno(parameter[2])&lt;br /&gt;
					elseif parameter[2] == &amp;#039;&amp;#039; then&lt;br /&gt;
						parameter[2] = nil&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
				barargs[parameter[1]] = parameter[2]&lt;br /&gt;
			else&lt;br /&gt;
				parameter = mw.text.trim(parameter)&lt;br /&gt;
				if parameter ~= &amp;#039;&amp;#039; then&lt;br /&gt;
					if i &amp;gt;= 2 and i &amp;lt;= 6 then&lt;br /&gt;
						parameter = tonumber(frame:callParserFunction(&amp;#039;#expr&amp;#039;, parameter))&lt;br /&gt;
						if not parameter then&lt;br /&gt;
							error((&amp;#039;Data parameters 2 to 6 must not be formatted. i=%d, line=%s&amp;#039;):format(i, line))&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
					barargs[i] = parameter&lt;br /&gt;
				end&lt;br /&gt;
				i = i + 1&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local bValid, nDateDiff&lt;br /&gt;
		-- get relevant date info based on previous row&lt;br /&gt;
		if barargs[1] then&lt;br /&gt;
			bValid, barargs.nDate = pcall(getUnix, barargs[1])&lt;br /&gt;
			assert(bValid, &amp;#039;invalid date &amp;quot;&amp;#039; .. barargs[1] .. &amp;#039;&amp;quot;&amp;#039;)&lt;br /&gt;
			if prevRow.nDate or prevRow.nEndDate then&lt;br /&gt;
				nDateDiff = barargs.nDate - (prevRow.nDate or prevRow.nEndDate)&lt;br /&gt;
				if nDateDiff &amp;gt; updatePeriod then&lt;br /&gt;
					if nDateDiff == 2 * updatePeriod then&lt;br /&gt;
						prevRow = {nDate=barargs.nDate-updatePeriod}&lt;br /&gt;
						prevRow[1] = os.date(&amp;#039;%Y-%m-%d&amp;#039;, prevRow.nDate)&lt;br /&gt;
					else&lt;br /&gt;
						prevRow = {nStartDate=(prevRow.nDate or prevRow.nEndDate)+updatePeriod, nEndDate=barargs.nDate-updatePeriod}&lt;br /&gt;
					end&lt;br /&gt;
					rows[#rows+1] = prevRow&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				prevRow.nEndDate = barargs.nDate - updatePeriod&lt;br /&gt;
				if prevRow.nStartDate == prevRow.nEndDate then&lt;br /&gt;
					prevRow.nDate = prevRow.nEndDate&lt;br /&gt;
					prevRow[1] = os.date(&amp;#039;%Y-%m-%d&amp;#039;, prevRow.nDate)&lt;br /&gt;
				-- as nAltStartDate assumes a minimal multiday interval, it&amp;#039;s possible for it to be greater if a true previous span is 1 day&lt;br /&gt;
				elseif prevRow.nAltStartDate and prevRow.nAltStartDate &amp;gt;= prevRow.nEndDate then&lt;br /&gt;
					error(&amp;#039;a row in a consecutive intervals group is 1 day long and misses the date parameter&amp;#039;)&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			if barargs.enddate then&lt;br /&gt;
				bValid, barargs.nEndDate = pcall(getUnix, barargs.enddate)&lt;br /&gt;
				assert(bValid, &amp;#039;invalid enddate &amp;quot;&amp;#039; .. barargs.enddate .. &amp;#039;&amp;quot;&amp;#039;)&lt;br /&gt;
			end&lt;br /&gt;
			if prevRow.nDate or prevRow.nEndDate then&lt;br /&gt;
				barargs.nStartDate = (prevRow.nDate or prevRow.nEndDate) + updatePeriod&lt;br /&gt;
				if barargs.nStartDate == barargs.nEndDate then&lt;br /&gt;
					barargs.nDate = barargs.nEndDate&lt;br /&gt;
					barargs[1] = os.date(&amp;#039;%Y-%m-%d&amp;#039;, barargs.nDate)&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				prevRow.nAltEndDate = (prevRow.nStartDate or prevRow.nAltStartDate) + updatePeriod&lt;br /&gt;
				barargs.nAltStartDate = prevRow.nAltEndDate + updatePeriod&lt;br /&gt;
				if barargs.nEndDate and barargs.nAltStartDate &amp;gt;= barargs.nEndDate then&lt;br /&gt;
					error(&amp;#039;a row in a consecutive intervals group is 1 day long and misses the date parameter&amp;#039;)&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		-- update tStats if at least one column changetype is &amp;#039;w&amp;#039;&lt;br /&gt;
		local tBarStats = nil&lt;br /&gt;
		if barargs[1] and (bIsW1 or bIsW2) then&lt;br /&gt;
			bValid, barargs.nDate = pcall(getUnix, barargs[1])&lt;br /&gt;
			assert(bValid, &amp;#039;invalid date &amp;quot;&amp;#039; .. barargs[1] .. &amp;#039;&amp;quot;&amp;#039;)&lt;br /&gt;
			barargs.nDate = tonumber(barargs.nDate)&lt;br /&gt;
			tBarStats = {}&lt;br /&gt;
			local tBarStats1 = tStats[barargs.nDate-86400] -- previous days info&lt;br /&gt;
			local tBarStats7 = tStats[barargs.nDate-604800] -- 7 days before info&lt;br /&gt;
			local tBarStats14 = tStats[barargs.nDate-1209600] -- 14 days before info&lt;br /&gt;
			local nData1 = barargs[xData1Key] or barargs[4]&lt;br /&gt;
			local nData2 = barargs[xData2Key] or barargs[2]&lt;br /&gt;
				&lt;br /&gt;
				&lt;br /&gt;
--	local nData1Diff1Max, nData1Diff1MaxDate, nData12Diff1Max, nData2Diff1MaxDate&lt;br /&gt;
--	local nData1i7Max, nData1i7MaxDate, nData12i7Max, nData2i7MaxDate&lt;br /&gt;
&lt;br /&gt;
			if bIsW1 and nData1 then&lt;br /&gt;
				tBarStats.nData1 = nData1&lt;br /&gt;
				-- if stats exist from day before&lt;br /&gt;
				if not (tBarStats1 == nil) and not (tBarStats1.nData1 == nil) then&lt;br /&gt;
					tBarStats.nData1Diff1 = nData1 - tBarStats1.nData1&lt;br /&gt;
					if nData1Diff1Max == nil or nData1Diff1Max &amp;lt; tBarStats.nData1Diff1 then&lt;br /&gt;
						nData1Diff1Max = tBarStats.nData1Diff1&lt;br /&gt;
						nData1Diff1MaxDate = barargs[1]&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
				-- if stats exist from 7 days before&lt;br /&gt;
				if not (tBarStats7 == nil) then&lt;br /&gt;
					if not (tBarStats7.nData1 == nil) then&lt;br /&gt;
						tBarStats.nData1Diff7 = nData1 - tBarStats7.nData1&lt;br /&gt;
						if nData1i7Max == nil or nData1i7Max &amp;lt; tBarStats.nData1Diff7/nPop*100000 then&lt;br /&gt;
							nData1i7Max = tBarStats.nData1Diff7/nPop*100000&lt;br /&gt;
							nData1i7MaxDate = barargs[1]&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
					if not (tBarStats7.nData1Diff1 == nil) then&lt;br /&gt;
						tBarStats.nData1P7Diff1 = tBarStats7.nData1Diff1&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
				-- if stats exist from 14 days before&lt;br /&gt;
				if not (tBarStats14 == nil) then&lt;br /&gt;
					if not (tBarStats14.nData1 == nil) then&lt;br /&gt;
						tBarStats.nData1Diff14 = nData1 - tBarStats14.nData1&lt;br /&gt;
					end&lt;br /&gt;
					if not (tBarStats14.nData1Diff1 == nil) then&lt;br /&gt;
						tBarStats.nData1P14Diff1 = tBarStats14.nData1Diff1&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			if bIsW2 and nData2 then&lt;br /&gt;
				tBarStats.nData2 = nData2&lt;br /&gt;
				-- if stats exist from day before&lt;br /&gt;
				if not (tBarStats1 == nil) and not (tBarStats1.nData2 == nil) then&lt;br /&gt;
					tBarStats.nData2Diff1 = nData2 - tBarStats1.nData2&lt;br /&gt;
					if nData2Diff1Max == nil or nData2Diff1Max &amp;lt; tBarStats.nData2Diff1 then&lt;br /&gt;
						nData2Diff1Max = tBarStats.nData2Diff1&lt;br /&gt;
						nData2Diff1MaxDate = barargs[1]&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
				-- if stats exist from 7 days before&lt;br /&gt;
				if not (tBarStats7 == nil) then&lt;br /&gt;
					if not (tBarStats7.nData2 == nil) then&lt;br /&gt;
						tBarStats.nData2Diff7 = nData2 - tBarStats7.nData2&lt;br /&gt;
						if nData2i7Max == nil or nData2i7Max &amp;lt; tBarStats.nData2Diff7/nPop*100000 then&lt;br /&gt;
							nData2i7Max = tBarStats.nData2Diff7/nPop*100000&lt;br /&gt;
							nData2i7MaxDate = barargs[1]&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
					if not (tBarStats7.nData2Diff1 == nil) then&lt;br /&gt;
						tBarStats.nData2P7Diff1 = tBarStats7.nData2Diff1&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
				-- if stats exist from 14 days before&lt;br /&gt;
				if not (tBarStats14 == nil) then&lt;br /&gt;
					if not (tBarStats14.nData2 == nil) then&lt;br /&gt;
						tBarStats.nData2Diff14 = nData2 - tBarStats14.nData2&lt;br /&gt;
					end&lt;br /&gt;
					if not (tBarStats14.nData2Diff1 == nil) then&lt;br /&gt;
						tBarStats.nData2P14Diff1 = tBarStats14.nData2Diff1&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			tStats[barargs.nDate] = tBarStats&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local function fillCols(col, change)&lt;br /&gt;
			local data = args[&amp;#039;right&amp;#039; .. col .. &amp;#039;data&amp;#039;]&lt;br /&gt;
			local changetype = args[&amp;#039;changetype&amp;#039; .. col]&lt;br /&gt;
			local value, num, prevnum&lt;br /&gt;
&lt;br /&gt;
			if data == &amp;#039;alttot1&amp;#039; then&lt;br /&gt;
				num = barargs.alttot1 or barargs[4]&lt;br /&gt;
				prevnum = prevRow.alttot1 or prevRow[4]&lt;br /&gt;
			elseif data == &amp;#039;alttot2&amp;#039; then&lt;br /&gt;
				num = barargs.alttot2 or barargs[6]&lt;br /&gt;
				prevnum = prevRow.alttot2 or prevRow[6]&lt;br /&gt;
			elseif data then&lt;br /&gt;
				num = barargs[data+1]&lt;br /&gt;
				prevnum = prevRow[data+1]&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			-- changetype w&lt;br /&gt;
			if not (tBarStats == nil) and not (tBarStats[&amp;quot;nData&amp;quot;..col] == nil) then&lt;br /&gt;
				local nDiff7 = tBarStats[&amp;quot;nData&amp;quot;..col..&amp;quot;Diff7&amp;quot;]&lt;br /&gt;
				local sChngCmt = &amp;quot;&amp;quot;&lt;br /&gt;
				if col == 1 and not (nData1i7Max == nil) then&lt;br /&gt;
					sChngCmt = &amp;quot;all time high: &amp;quot; .. mw.ustring.format(&amp;#039;%.1f&amp;#039;, nData1i7Max) .. &amp;quot; on &amp;quot; .. nData1i7MaxDate&lt;br /&gt;
				elseif col == 2 and not (nData2i7Max == nil) then&lt;br /&gt;
					sChngCmt = &amp;quot;all time high: &amp;quot; .. mw.ustring.format(&amp;#039;%.1f&amp;#039;, nData2i7Max) .. &amp;quot; on &amp;quot; .. nData2i7MaxDate&lt;br /&gt;
				end&lt;br /&gt;
				if nDiff7 == nil then&lt;br /&gt;
					change = i18n.na&lt;br /&gt;
				else&lt;br /&gt;
					change = &amp;#039;&amp;lt;span title=&amp;quot;&amp;#039;.. sChngCmt .. &amp;#039;&amp;quot;&amp;gt;&amp;#039; .. tostring(mw.ustring.format(&amp;#039;%.1f&amp;#039;, nDiff7/args.population*100000)) .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
				end&lt;br /&gt;
				local nValue = tBarStats[&amp;quot;nData&amp;quot;..col]&lt;br /&gt;
				local nDiff1 = tBarStats[&amp;quot;nData&amp;quot;..col..&amp;quot;Diff1&amp;quot;]&lt;br /&gt;
				local nP7Diff1 = tBarStats[&amp;quot;nData&amp;quot;..col..&amp;quot;P7Diff1&amp;quot;]&lt;br /&gt;
				local nP14Diff1 = tBarStats[&amp;quot;nData&amp;quot;..col..&amp;quot;P14Diff1&amp;quot;]&lt;br /&gt;
				local sCmnt&lt;br /&gt;
				if nDiff1 == nil then&lt;br /&gt;
					sCmnt = &amp;quot;&amp;quot;&lt;br /&gt;
				else&lt;br /&gt;
					sCmnt = &amp;quot;daily change: +&amp;quot; .. lang:formatNum(nDiff1)&lt;br /&gt;
				end&lt;br /&gt;
				if not (nP7Diff1 == nil) and not (sCmnt == &amp;quot;&amp;quot;) then&lt;br /&gt;
					sCmnt = sCmnt .. &amp;quot;, 7 days before: +&amp;quot; .. lang:formatNum(nP7Diff1)&lt;br /&gt;
				end&lt;br /&gt;
				if not (nP14Diff1 == nil) and not (sCmnt == &amp;quot;&amp;quot;) then&lt;br /&gt;
					sCmnt = sCmnt .. &amp;quot;, 14 days before: +&amp;quot; .. lang:formatNum(nP14Diff1)&lt;br /&gt;
				end&lt;br /&gt;
				if col == 1 and not (nData1Diff1Max == nil) and not (sCmnt == &amp;quot;&amp;quot;) then&lt;br /&gt;
					sCmnt = sCmnt .. &amp;quot;, all-time high: +&amp;quot; .. lang:formatNum(nData1Diff1Max) .. &amp;quot; on &amp;quot; .. nData1Diff1MaxDate&lt;br /&gt;
				end&lt;br /&gt;
				if col == 2 and not (nData2Diff1Max == nil) and not (sCmnt == &amp;quot;&amp;quot;) then&lt;br /&gt;
					sCmnt = sCmnt .. &amp;quot;, all-time high: +&amp;quot; .. lang:formatNum(nData2Diff1Max) .. &amp;quot; on &amp;quot; .. nData2Diff1MaxDate&lt;br /&gt;
				end&lt;br /&gt;
				value = &amp;#039;&amp;lt;span title=&amp;quot;&amp;#039; .. sCmnt ..&amp;#039;&amp;quot;&amp;gt;&amp;#039; .. lang:formatNum(nValue)  .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
			&lt;br /&gt;
			elseif data and num then -- nothing in column, source found, and data exists&lt;br /&gt;
				value = changetype == &amp;#039;o&amp;#039; and &amp;#039;&amp;#039; or lang:formatNum(num) -- set value to num if changetype isn&amp;#039;t &amp;#039;o&amp;#039;&lt;br /&gt;
				if not change and not barargs[&amp;#039;firstright&amp;#039; .. col] then&lt;br /&gt;
					if prevnum and prevnum ~= 0 then -- data on previous row&lt;br /&gt;
						if num - prevnum ~= 0 then --data has changed since previous row&lt;br /&gt;
							local nChange = num - prevnum&lt;br /&gt;
							if changetype == &amp;#039;a&amp;#039; then -- change type is &amp;quot;absolute&amp;quot;&lt;br /&gt;
								if nChange &amp;gt; 0 then&lt;br /&gt;
									change = &amp;#039;+&amp;#039; .. lang:formatNum(nChange)&lt;br /&gt;
								end&lt;br /&gt;
							elseif changetype == &amp;#039;w&amp;#039; and args.population then -- changetype == &amp;#039;r&amp;#039; or &lt;br /&gt;
								 -- change type is &amp;quot;r&amp;quot;(olling average over 7 days period) or &amp;quot;w&amp;quot;(eekly incidence per 100.000 pop)&lt;br /&gt;
								if barargs.nDate and rows then&lt;br /&gt;
									-- find data row from 7 days before +- 1 hour&lt;br /&gt;
									local tIntervRow = p._findIntervalRow(rows, barargs.nDate-7*24*3600, 3600, false)&lt;br /&gt;
									local tPrevDayRow = p._findIntervalRow(rows, barargs.nDate-24*3600, 3600, false)&lt;br /&gt;
									if tIntervRow then&lt;br /&gt;
										local nDatCol = (col==1) and 4 or 2&lt;br /&gt;
										local nDiff = tIntervRow[nDatCol] and (num - tIntervRow[nDatCol]) or nil&lt;br /&gt;
										if changetype == &amp;#039;r&amp;#039; then&lt;br /&gt;
											change = nDiff and (&amp;#039;&amp;lt;span title=&amp;quot;7 days rolling average of daily change&amp;quot;&amp;gt;r7: &amp;#039; .. tostring(mw.ustring.format(&amp;#039;%.0f&amp;#039;, nDiff/7)) .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;) or i18n.na&lt;br /&gt;
										else&lt;br /&gt;
											change = nDiff and (&amp;#039;&amp;lt;span title=&amp;quot;7 days incidence per 100,000 population.&amp;quot;&amp;gt;&amp;#039; .. tostring(mw.ustring.format(&amp;#039;%.1f&amp;#039;, nDiff/args.population*100000)) .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;) or i18n.na&lt;br /&gt;
											if tPrevDayRow and tPrevDayRow[nDatCol] then&lt;br /&gt;
												value = &amp;#039;&amp;lt;span title=&amp;quot;daily change: +&amp;#039; .. lang:formatNum(num - tPrevDayRow[nDatCol]) .. &amp;#039;&amp;gt;&amp;#039; .. value  .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
											end&lt;br /&gt;
										end&lt;br /&gt;
									else&lt;br /&gt;
										change = i18n.na&lt;br /&gt;
									end&lt;br /&gt;
								else&lt;br /&gt;
									change = i18n.na&lt;br /&gt;
								end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
							else -- change type is &amp;quot;percent&amp;quot;, &amp;quot;only percent&amp;quot; or undefined&lt;br /&gt;
								local percent = 100 * nChange / prevnum -- calculate percent&lt;br /&gt;
								local rounding = math.abs(percent) &amp;gt;= 10 and &amp;#039;%.0f&amp;#039; or math.abs(percent) &amp;gt;= 1 and &amp;#039;%.1f&amp;#039; or &amp;#039;%.2f&amp;#039;&lt;br /&gt;
								percent = tonumber(rounding:format(percent)) -- round to two sigfigs&lt;br /&gt;
&lt;br /&gt;
								if percent &amp;gt; 0 then&lt;br /&gt;
									change = &amp;#039;+&amp;#039; .. lang:formatNum(percent) .. &amp;#039;%&amp;#039;&lt;br /&gt;
								elseif percent &amp;lt; 0 then&lt;br /&gt;
									change = lang:formatNum(percent) .. &amp;#039;%&amp;#039;&lt;br /&gt;
								else&lt;br /&gt;
									change = &amp;#039;=&amp;#039;&lt;br /&gt;
								end&lt;br /&gt;
							end&lt;br /&gt;
						else -- data has not changed since previous row&lt;br /&gt;
							change = &amp;#039;=&amp;#039;&lt;br /&gt;
						end&lt;br /&gt;
					else -- no data on previous row&lt;br /&gt;
						barargs[&amp;#039;firstright&amp;#039; .. col] = true -- set to (n.a.)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			return value, change&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		if not barargs[7] then&lt;br /&gt;
			barargs[7], barargs[8] = fillCols(1, barargs[8])&lt;br /&gt;
		end&lt;br /&gt;
		if not barargs[9] then&lt;br /&gt;
			barargs[9], barargs[10] = fillCols(2, barargs[10])&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		rows[#rows+1] = barargs&lt;br /&gt;
		prevRow = barargs&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	--error(mw.dumpObject(tStats))&lt;br /&gt;
&lt;br /&gt;
	-- calculate and pass repetitive (except daysToEnd) parameters to each row&lt;br /&gt;
	local lastRow = rows[#rows]&lt;br /&gt;
	local total = {lastRow[2] or 0, lastRow[3] or 0, [4]=lastRow[5] or 0}&lt;br /&gt;
	total[3] = lastRow.alttot1 or lastRow[4] and lastRow[4] - total[1] - total[2] or 0&lt;br /&gt;
	total[5] = lastRow.alttot2 or lastRow[6] and lastRow[6] - total[1] - total[2] or 0&lt;br /&gt;
	local divisor = (total[1] + total[2] + total[3] + total[4] + total[5]) / (args.barwidth - 5) --should be -3 if borders didn&amp;#039;t go inward&lt;br /&gt;
	local firstDate, lastDate = rows[1].nDate, lastRow.nDate or lastRow.nEndDate&lt;br /&gt;
	local multiyear = os.date(&amp;#039;%Y&amp;#039;, firstDate) ~= os.date(&amp;#039;%Y&amp;#039;, lastDate - (args.nooverlap and args.duration * 86400 or 0))&lt;br /&gt;
	if args.collapsible ~= false then&lt;br /&gt;
		args.collapsible = (lastDate - firstDate) / 86400 &amp;gt;= args.duration&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local bars, dateList = {}, {}&lt;br /&gt;
	for i, row in ipairs(rows) do -- build rows&lt;br /&gt;
		row.divisor = divisor&lt;br /&gt;
		row.numwidth = args.numwidth&lt;br /&gt;
		row.collapsible = args.collapsible&lt;br /&gt;
		row.duration = args.duration&lt;br /&gt;
		row.nooverlap = args.nooverlap&lt;br /&gt;
		row.daysToEnd = (lastDate - (row.nDate or row.nEndDate or row.nAltEndDate)) / 86400&lt;br /&gt;
		row.multiyear = multiyear&lt;br /&gt;
&lt;br /&gt;
		bars[#bars+1], dateList[#dateList+1] = p._row(row)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return table.concat(bars, &amp;#039;\n&amp;#039;), dateList&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
p._barColors = { -- also in styles.css&lt;br /&gt;
	&amp;#039;#A50026&amp;#039;,	--deaths&lt;br /&gt;
	&amp;#039;SkyBlue&amp;#039;,	--recoveries&lt;br /&gt;
	&amp;#039;Tomato&amp;#039;,	--cases or altlbl1&lt;br /&gt;
	&amp;#039;Gold&amp;#039;,		--altlbl2&lt;br /&gt;
	&amp;#039;OrangeRed&amp;#039;	--altlbl3&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function p._legend0(args)&lt;br /&gt;
	return&lt;br /&gt;
		&amp;#039;&amp;lt;span style=&amp;quot;font-size:90%; margin:0px&amp;quot;&amp;gt;&amp;#039; ..&lt;br /&gt;
			&amp;#039;&amp;lt;span style=&amp;quot;background-color:&amp;#039; .. (args[1] or &amp;#039;none&amp;#039;) ..&lt;br /&gt;
			&amp;#039;; border:&amp;#039; .. (args.border or &amp;#039;none&amp;#039;) ..&lt;br /&gt;
			&amp;#039;; color:&amp;#039; .. (args[1] or &amp;#039;none&amp;#039;) .. &amp;#039;&amp;quot;&amp;gt;&amp;#039; ..&lt;br /&gt;
				&amp;#039;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;#039; .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039; ..&lt;br /&gt;
			&amp;#039;&amp;amp;nbsp;&amp;#039; .. (args[2] or &amp;#039;&amp;#039;) .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._chart(args)&lt;br /&gt;
	for key, value in pairs(args) do&lt;br /&gt;
		if ({float=1, barwidth=1, numwidth=1, changetype=1})[key:gsub(&amp;#039;%d&amp;#039;, &amp;#039;&amp;#039;)] then&lt;br /&gt;
			args[key] = value:lower()&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local barargs = {}&lt;br /&gt;
&lt;br /&gt;
	barargs.css = &amp;#039;Module:Medical cases chart/styles.css&amp;#039;&lt;br /&gt;
	barargs.float = args.float or &amp;#039;right&amp;#039;&lt;br /&gt;
&lt;br /&gt;
	args.barwidth = args.barwidth or &amp;#039;medium&amp;#039;&lt;br /&gt;
	local barwidth&lt;br /&gt;
	if args.barwidth == &amp;#039;thin&amp;#039; then&lt;br /&gt;
		barwidth = 120&lt;br /&gt;
	elseif args.barwidth == &amp;#039;medium&amp;#039; then&lt;br /&gt;
		barwidth = 280&lt;br /&gt;
	elseif args.barwidth == &amp;#039;wide&amp;#039; then&lt;br /&gt;
		barwidth = 400&lt;br /&gt;
	elseif args.barwidth == &amp;#039;auto&amp;#039; then&lt;br /&gt;
		barwidth = &amp;#039;auto&amp;#039;&lt;br /&gt;
	else&lt;br /&gt;
		error(&amp;#039;unrecognized barwidth&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local function _numwidth(i)&lt;br /&gt;
		local nw = args.numwidth:sub(i,i)&lt;br /&gt;
		return assert(numwidth[nw], &amp;#039;unrecognized numwidth[&amp;#039; .. i .. &amp;#039;]&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	args.numwidth = args.numwidth or &amp;#039;mm&amp;#039;&lt;br /&gt;
	if args.numwidth:sub(1,1) == &amp;#039;n&amp;#039; or args.numwidth:sub(2,2) == &amp;#039;n&amp;#039; or args.numwidth:sub(4,4) == &amp;#039;n&amp;#039; then&lt;br /&gt;
		error(&amp;#039;&amp;quot;n&amp;quot; is only allowed in numwidth[3]&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local buffer = 0.3 --until automatic numwidth determination&lt;br /&gt;
	local right1width, right2width = _numwidth(1) + 0.3 + _numwidth(2) + buffer, 0&lt;br /&gt;
	if #args.numwidth == 4 then&lt;br /&gt;
		right2width = _numwidth(3) + _numwidth(4) + buffer&lt;br /&gt;
		if args.numwidth:sub(3,3) ~= &amp;#039;n&amp;#039; then&lt;br /&gt;
			right2width = right2width + 0.3&lt;br /&gt;
		end&lt;br /&gt;
		if args.right2 then&lt;br /&gt;
			right2width = math.ceil(right2width / 0.88 * 100) / 100 -- from td scale to th&lt;br /&gt;
		else&lt;br /&gt;
			right1width = right1width + 0.8 + right2width&lt;br /&gt;
			right2width = 0&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	right1width = math.ceil(right1width / 0.88 * 100) / 100&lt;br /&gt;
&lt;br /&gt;
	if tonumber(barwidth) then&lt;br /&gt;
		-- transform colswidth from th to td scale, add it with border-spacing, and finally transform to table scale&lt;br /&gt;
		local relwidth = math.ceil(((7.08 + right1width + right2width) * 0.88 + 0.8 * (args.right2 and 5 or 4)) * 88) / 100&lt;br /&gt;
		barargs.width = &amp;#039;calc(&amp;#039; .. relwidth .. &amp;#039;em + &amp;#039; .. barwidth .. &amp;#039;px)&amp;#039; --why do the bar borders go inward (no +2)?&lt;br /&gt;
		barargs.barwidth = barwidth .. &amp;#039;px&amp;#039;&lt;br /&gt;
	else&lt;br /&gt;
		barargs.width = &amp;#039;auto&amp;#039;&lt;br /&gt;
		barargs.barwidth = &amp;#039;auto&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	barargs.lineheight = args.rowheight&lt;br /&gt;
&lt;br /&gt;
	local title = {}&lt;br /&gt;
&lt;br /&gt;
	local function spaces(n)&lt;br /&gt;
		local nbsp = &amp;#039;&amp;amp;nbsp;&amp;#039;&lt;br /&gt;
		return &amp;#039;&amp;lt;span class=&amp;quot;nowrap&amp;quot;&amp;gt;&amp;#039; .. nbsp:rep(n) .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local location = lang:ucfirst(mw.ustring.gsub(args.location, i18n.the_, &amp;#039;&amp;#039;))&lt;br /&gt;
	local navbartitle = args.outbreak .. i18n._data .. &amp;#039;/&amp;#039; ..&lt;br /&gt;
		(args.location3 and args.location3 .. &amp;#039;/&amp;#039; or &amp;#039;&amp;#039;) ..&lt;br /&gt;
		(args.location2 and args.location2 .. &amp;#039;/&amp;#039; or &amp;#039;&amp;#039;) ..&lt;br /&gt;
		location .. i18n._medicalCasesChart&lt;br /&gt;
&lt;br /&gt;
	local navbar = require(&amp;#039;Module:Navbar&amp;#039;)._navbar&lt;br /&gt;
	title[1] = (args.pretitle and args.pretitle .. &amp;#039; &amp;#039; or &amp;#039;&amp;#039;) ..&lt;br /&gt;
		args.disease .. &amp;#039; &amp;#039; .. i18n.casesIn .. &amp;#039; &amp;#039; .. args.location ..&lt;br /&gt;
		(args.location2 and &amp;#039;, &amp;#039; .. args.location2 or &amp;#039;&amp;#039;) ..&lt;br /&gt;
		(args.location3 and &amp;#039;, &amp;#039; .. args.location3 or &amp;#039;&amp;#039;) ..&lt;br /&gt;
		(args.posttitle and &amp;#039; &amp;#039; .. args.posttitle or &amp;#039;&amp;#039;) .. spaces(2) ..&amp;#039;(&amp;#039; ..&lt;br /&gt;
		navbar({navbartitle, titleArg=&amp;#039;:&amp;#039; .. mw.getCurrentFrame():getParent():getTitle(), mini=1, nodiv=1}) ..&lt;br /&gt;
		&amp;#039;)&amp;lt;br /&amp;gt;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
	title[2] = p._legend0({p._barColors[1], i18n.deaths})&lt;br /&gt;
	args.recoveries = args.recoveries == nil and true or args.recoveries&lt;br /&gt;
	title[3] = args.recoveries and spaces(3) .. p._legend0({p._barColors[2], args.reclbl or i18n.recoveries}) or &amp;#039;&amp;#039;&lt;br /&gt;
	title[4] = args.altlbl1 ~= &amp;#039;hide&amp;#039; and spaces(3) .. p._legend0({p._barColors[3], args.altlbl1 or i18n.activeCases}) or &amp;#039;&amp;#039;&lt;br /&gt;
	title[5] = args.altlbl2 and spaces(3) .. p._legend0({p._barColors[4], args.altlbl2}) or &amp;#039;&amp;#039;&lt;br /&gt;
	title[6] = args.altlbl3 and spaces(3) .. p._legend0({p._barColors[5], args.altlbl3}) or &amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
	local togglesbar, buildargs = nil, {}&lt;br /&gt;
&lt;br /&gt;
	args.right1 = args.right1 or i18n.noOfCases&lt;br /&gt;
	args.duration = args.duration or 15&lt;br /&gt;
	args.nooverlap = args.nooverlap or false&lt;br /&gt;
&lt;br /&gt;
	buildargs.barwidth = tonumber(barwidth) or 280&lt;br /&gt;
	buildargs.numwidth = args.numwidth:gsub(&amp;#039;d&amp;#039;, &amp;#039;m&amp;#039;)&lt;br /&gt;
	if args.datapage then&lt;br /&gt;
		local externalData = require(&amp;#039;Module:Medical cases chart/data&amp;#039;)._externalData&lt;br /&gt;
		buildargs.data = externalData(args)&lt;br /&gt;
	else&lt;br /&gt;
		buildargs.data = args.data&lt;br /&gt;
	end&lt;br /&gt;
	-- if no right1data and right1 title is cases, use 3rd classification&lt;br /&gt;
	buildargs.right1data = args.right1data or args.right1 == i18n.noOfCases and 3&lt;br /&gt;
	-- if no right2data and right2 title is deaths, use 1st classification&lt;br /&gt;
	buildargs.right2data = args.right2data or (args.right2 == i18n.noOfDeaths or args.right2 == i18n.noOfDeaths2) and 1&lt;br /&gt;
	buildargs.changetype1 = (args.changetype1 or args.changetype or &amp;#039;&amp;#039;):sub(1,1) -- 1st letter&lt;br /&gt;
	buildargs.changetype2 = (args.changetype2 or args.changetype or &amp;#039;&amp;#039;):sub(1,1) -- 1st letter&lt;br /&gt;
	buildargs.collapsible = args.collapsible&lt;br /&gt;
	buildargs.duration = args.duration&lt;br /&gt;
	buildargs.nooverlap = args.nooverlap&lt;br /&gt;
	buildargs.population = args.population&lt;br /&gt;
&lt;br /&gt;
	local dateList&lt;br /&gt;
	barargs.bars, dateList = p._buildBars(buildargs)&lt;br /&gt;
&lt;br /&gt;
	if buildargs.collapsible then&lt;br /&gt;
		togglesbar = p._buildTogglesBar(dateList, args.duration, args.nooverlap)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	title[7] = togglesbar and &amp;#039;&amp;lt;br /&amp;gt;&amp;#039; .. togglesbar or &amp;#039;&amp;#039;&lt;br /&gt;
	barargs.title = table.concat(title)&lt;br /&gt;
&lt;br /&gt;
	barargs.left1 = &amp;#039;&amp;lt;div style=&amp;quot;width:7.08em&amp;quot;&amp;gt;&amp;#039; .. i18n.date .. &amp;#039;&amp;lt;/div&amp;gt;&amp;#039;&lt;br /&gt;
	barargs.right1 = &amp;#039;&amp;lt;div class=center style=&amp;quot;width:&amp;#039; .. right1width .. &amp;#039;em&amp;quot;&amp;gt;&amp;#039; .. args.right1 .. &amp;#039;&amp;lt;/div&amp;gt;&amp;#039; --center isn&amp;#039;t necessary with proper&lt;br /&gt;
	if args.right2 then																					   --numwidth, but better safe than sorry&lt;br /&gt;
		barargs.right2 = &amp;#039;&amp;lt;div class=center style=&amp;quot;width:&amp;#039; .. right2width ..&amp;#039;em&amp;quot;&amp;gt;&amp;#039; .. args.right2 .. &amp;#039;&amp;lt;/div&amp;gt;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	barargs.footer = args.footer&lt;br /&gt;
	local box = BarBox.create(barargs)&lt;br /&gt;
	return tostring(box)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local getArgs = require(&amp;#039;Module:Arguments&amp;#039;).getArgs&lt;br /&gt;
&lt;br /&gt;
function p.barColors(frame)&lt;br /&gt;
	local args = getArgs(frame)&lt;br /&gt;
	return p._barColors[tonumber(args[1])]&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.chart(frame)&lt;br /&gt;
	local args = getArgs(frame, {&lt;br /&gt;
		valueFunc = function (key, value)&lt;br /&gt;
			if value and value ~= &amp;#039;&amp;#039; then&lt;br /&gt;
				key = key:gsub(&amp;#039;%d&amp;#039;, &amp;#039;&amp;#039;)&lt;br /&gt;
				if ({rowheight=1, duration=1, rightdata=1})[key] then -- if key in {...}&lt;br /&gt;
					return tonumber(value) or value&lt;br /&gt;
				end&lt;br /&gt;
				if ({recoveries=1, collapsible=1, nooverlap=1})[key] then&lt;br /&gt;
					return yesno(value)&lt;br /&gt;
				end&lt;br /&gt;
				return value&lt;br /&gt;
			end&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
	})&lt;br /&gt;
	return p._chart(args)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>imported&gt;GKFX</name></author>
	</entry>
</feed>