Module:COVID-19 data
local p = {}
 
 local data_title = mw.title.new(
 	'Template:COVID-19 data/data'
 )
 local data_content = data_title:getContent()
 local data = mw.text.jsonDecode(data_content)
 
 local function format_num(number)
 	if not number then
 		return ''
 	end
 	local _, _, minus, int, _ = tostring(number):find('([-]?)(%d+)([.]?%d*)')
 	int = int:reverse():gsub(&quot;(%d%d%d)&quot;, &quot;%1,&quot;)
 	int = int:reverse():gsub(&quot;^,&quot;, &quot;&quot;)
 	int = minus .. int
 	return int
 end
 
 function p.main()
 	local out = ''
 	local data_s = {}
 	local has_notelist = false
 	local count_row = 0
 	local count_col = 0
 	-- Build new table
 	local locations = {}
 	if mw.getCurrentFrame().args['locations'] then
 		for location in string.gmatch(
 			mw.getCurrentFrame().args['locations'],
 			'([^,]+)'
 		) do
 			locations[location] = true
 		end
 	else
 		locations = nil
 	end
 	for key, value in pairs(data) do
 		local index
 		if mw.getCurrentFrame().args['sort'] then
 			if value[mw.getCurrentFrame().args['sort']] then
 				index = value[mw.getCurrentFrame().args['sort']]
 			else
 				index = 0
 			end
 		else
 			if value.cases then
 				index = value.cases
 			elseif value.deaths then
 				index = value.deaths
 			elseif value.vaccine_doses then
 				index = value.vaccine_doses
 			elseif value.total_vaccinated then
 				index = value.total_vaccinated
 			elseif value.fully_vaccinated then
 				index = value.fully_vaccinated
 			else index = 0
 			end
 		end
 		if (not locations) or locations[key] then
 			data_s[#data_s+1] = value
 			data_s[#data_s]['_index'] = index
 			data_s[#data_s]['_code'] = key
 		end
 	end
 	-- Sort the new table
 	table.sort(
 		data_s,
 		function(x, y)
 			if x._code == 'XW' then
 				return true
 			elseif y._code == 'XW' then
 				return false
 			else
 				return (x._index &gt; y._index)
 			end
 		end
 	)
 	-- Get columns
 	local columns = {
 		cases = false,
 		deaths = false,
 		total_vaccinated = false,
 		vaccine_doses = false,
 		fully_vaccinated = false,
 		percent_vaccinated = false,
 		percent_fully_vaccinated = false,
 		deaths_per_million = false,
 		population = false
 	}
 	local columns_index = {}
 	if mw.getCurrentFrame().args['columns'] then
 		for column in string.gmatch(
 			mw.getCurrentFrame().args['columns'],
 			'([^,]+)'
 		) do
 			columns[column] = true
 			columns_index[#columns_index+1] = column
 		end
 	else
 		columns = {
 			cases = true,
 			deaths = true,
 			total_vaccinated = true,
 			vaccine_doses = true,
 			fully_vaccinated = true,
 			percent_vaccinated = false,
 			percent_fully_vaccinated = false,
 			deaths_per_million = false,
 			population = false
 		}
 		columns_index = {
 			'cases',
 			'deaths',
 			'total_vaccinated',
 			'vaccine_doses',
 			'fully_vaccinated',
 			'percent_vaccinated',
 			'percent_fully_vaccinated',
 			'deaths_per_million',
 			'population'
 		}
 	end
 	-- Check if should show note_vaccination
 	local show_note_vaccination = false
 	if columns['total_vaccinated'] or columns['vaccine_doses'] or columns['fully_vaccinated'] or columns['percent_vaccinated'] or columns['percent_fully_vaccinated'] then
 		show_note_vaccination = true
 	end
 	-- Generate wikitext content
 	for _, row in ipairs(data_s) do
 		-- Test for empty rows
 		local has_data = false
 		for _, column in pairs(columns_index) do
 			if columns[column] and row[column] then
 				has_data = true
 			end
 		end
 		if has_data then -- Only add row if it has data
 			count_row = count_row + 1
 			out = out .. '\n|-'
 			if row._code == 'XW' then
 				out = out .. 'class=&quot;sorttop static-row-header&quot;'
 			end
 			-- Add the flag
 			if not mw.getCurrentFrame().args['noflag'] then
 				if count_row == 1 then
 					count_col = count_col + 1
 				end
 				out = out .. '\n| style=&quot;text-align: center;&quot; data-sort-value=&quot;' .. row.name .. '&quot; | '
 				if row._code == 'XW' then
 					out = out ..
 						'[[File:OOjs UI icon globe.svg|16px|alt=|link=]]'
 				else
 					flag_params = {row.name}
 					-- So that it's not too large
 					if row.name == 'New Caledonia' then
 						flag_params[2] = 'merged'
 					end
 					out = out ..
 						mw.getCurrentFrame():expandTemplate{
 							title = 'Flagicon',
 							args = flag_params
 						}
 				end
 			end
 			-- Add country name
 			if count_row == 1 then
 				count_col = count_col + 1
 			end
 			if mw.getCurrentFrame().args['noflag'] then
 				out = out .. '\n! scope=&quot;row&quot; data-sort-value=&quot;' .. row.name .. '&quot; | '
 			else
 				out = out .. '\n! scope=&quot;row&quot; |'
 			end
 			if row._code == 'XW' then
 				out = out .. '[[COVID-19 pandemic|' .. row.name .. ']]'
 			elseif row._code == 'GE' then
 				out = out ..
 					'[[COVID-19 pandemic in Georgia (country)' ..
 					'|' .. row.name .. ']]'
 			elseif row._code == 'IM' then
 				out = out ..
 					'[[COVID-19 pandemic in the ' .. row.name ..
 					'|' .. row.name .. ']]'
 			else
 				out = out ..
 					'[[COVID-19 pandemic in ' .. row.name ..
 					'|' .. row.name .. ']]'
 			end
 			-- Add notes
 			if row.note then
 				has_notelist = true
 				out = out ..
 					mw.getCurrentFrame():expandTemplate{
 						title = 'Efn',
 						args = {row.note}
 					}
 			end
 			if row.note_vaccination and show_note_vaccination then
 				has_notelist = true
 				out = out ..
 					mw.getCurrentFrame():expandTemplate{
 						title = 'Efn',
 						args = {'Vaccination note: ' .. row.note_vaccination}
 					}
 			end
 			-- Fill out columns
 			for _, column in ipairs(columns_index) do
 				if columns[column] then
 					if count_row == 1 then
 						count_col = count_col + 1
 					end
 					if row[column] then
 						out = out .. '\n| data-sort-value=' ..
 							tostring(row[column]) ..
 							'|'
 						if column:find('^percent') then
 							out = out .. string.format('%.2f', row[column]) .. '%'
 						else
 							out = out .. format_num(row[column])
 						end
 					else
 						out = out .. '\n| data-sort-value=0 | —'
 					end
 				end
 			end
 		end
 	end
 	if has_notelist then
 		out = out .. '\n|- class=&quot;sortbottom static-row-header&quot; style=&quot;text-align: left;&quot;' ..
 			'\n| colspan=&quot;' .. count_col .. '&quot; style=&quot;width: 0;&quot; |' ..
 			mw.getCurrentFrame():expandTemplate{
 				title = 'Notelist'
 			}
 	end
 	return out
 end
 
 function p.vac()
 	local out = ''
 	local data_s = {}
 	local has_country_num_doses = false
 	local has_country_num_fully = false
 	local count_row = 0
 	local count_col = 0
 	-- Build new table
 	for key, value in pairs(data) do
 		if value.total_vaccinated then
 			data_s[#data_s+1] = value
 			data_s[#data_s]['index'] = value.total_vaccinated
 		elseif value.vaccine_doses then
 			data_s[#data_s+1] = value
 			data_s[#data_s]['index'] = value.vaccine_doses
 		elseif value.fully_vaccinated then
 			data_s[#data_s+1] = value
 			data_s[#data_s]['index'] = value.fully_vaccinated
 		end
 	end
 	-- Sort the new table
 	table.sort(
 		data_s,
 		function(x, y)
 			return (x.index &gt; y.index)
 		end
 	)
 	-- Generate wikitext content
 	for _, row in pairs(data_s) do
 		count_row = count_row + 1
 		out = out .. '\n|-'
 		-- Add the flag
 		if count_row == 1 then
 			count_col = count_col + 2
 		end
 		if row.name == 'World' then
 			out = out ..
 				'class=&quot;sorttop static-row-header&quot;' ..
 				'\n| style=&quot;text-align: center;&quot; data-sort-value=&quot;' .. row.name .. '&quot; | ' ..
 				'[[File:OOjs UI icon globe.svg|16px|alt=|link=]]' ..
 				'\n! scope=&quot;row&quot; data-sort-value=&quot;' .. row.name .. '&quot; | ' ..
 				'[[Deployment of COVID-19 vaccines|World]]'
 		else
 			flag_params = {row.name}
 			-- So that it's not too large
 			if row.name == 'New Caledonia' then
 				flag_params[2] = 'merged'
 			end
 			out = out ..
 				'\n| style=&quot;text-align: center;&quot; data-sort-value=&quot;' .. row.name .. '&quot; | ' ..
 				mw.getCurrentFrame():expandTemplate{
 					title = 'Flagicon',
 					args = flag_params
 				} ..
 				'\n! scope=&quot;row&quot; data-sort-value=&quot;' .. row.name .. '&quot; | ' ..
 				'[[COVID-19 vaccination in ' .. row.name .. '|' .. row.name .. ']]'
 		end
 		-- Add note
 		if row.note_vaccination then
 			out = out ..
 				mw.getCurrentFrame():expandTemplate{
 					title = 'Efn',
 					args = {row.note_vaccination}
 				}
 		end
 		-- Add the number
 		if count_row == 1 then
 			count_col = count_col + 1
 		end
 		if row.total_vaccinated then
 			out = out .. '\n| data-sort-value=' ..
 				tostring(row.total_vaccinated) ..
 				'|' .. format_num(row.total_vaccinated)
 		elseif row.vaccine_doses then
 			has_country_num_doses = true
 			out = out .. '\n| data-sort-value=' ..
 				tostring(row.vaccine_doses) ..
 				'|' ..
 				mw.getCurrentFrame():expandTemplate{
 					title = 'Font color',
 					args = {'darkred', format_num(row.vaccine_doses)}
 				} ..
 				mw.getCurrentFrame():expandTemplate{
 					title = 'Efn',
 					args = {name = 'country_num_doses'}
 				}
 		elseif row.fully_vaccinated then
 			has_country_num_fully = true
 			out = out .. '\n| data-sort-value=' ..
 				tostring(row.fully_vaccinated) ..
 				'|' ..
 				mw.getCurrentFrame():expandTemplate{
 					title = 'Font color',
 					args = {'darkorange', format_num(row.fully_vaccinated)}
 				} ..
 				mw.getCurrentFrame():expandTemplate{
 					title = 'Efn',
 					args = {name = 'country_num_fully'}
 				}
 		end
 		-- Add the percentage
 		if count_row == 1 then
 			count_col = count_col + 1
 		end
 		if row.percent_vaccinated then
 			out = out .. '\n| data-sort-value=' ..
 				tostring(row.percent_vaccinated) ..
 				'|' .. string.format(&quot;%.1f&quot;, row.percent_vaccinated) .. '%'
 		else
 			out = out .. '\n| data-sort-value=0 | —'
 		end
 	end
 	if has_country_num_doses or has_country_num_fully then
 		notelist_refs = ''
 		if has_country_num_doses then
 			notelist_refs = notelist_refs ..
 				mw.getCurrentFrame():expandTemplate{
 					title = 'Efn',
 					args = {
 						name = 'country_num_doses',
 						'This country\'s data are the ' ..
 							mw.getCurrentFrame():expandTemplate{
 								title = 'Font color',
 								args = {
 									'darkred',
 									'number of vaccine doses administered'
 								}
 							} ..
 							', not the first dose only.'
 					}
 				}
 		end
 		if has_country_num_fully then
 			notelist_refs = notelist_refs ..
 				mw.getCurrentFrame():expandTemplate{
 					title = 'Efn',
 					args = {
 						name = 'country_num_fully',
 						'This country\'s data are the ' ..
 							mw.getCurrentFrame():expandTemplate{
 								title = 'Font color',
 								args = {
 									'darkorange',
 									'number of people fully vaccinated'
 								}
 							} ..
 							', not the number of people ' ..
 							'who have received at least one dose.'
 					}
 				}
 		end
 		out = out .. '\n|- class=&quot;sortbottom  static-row-header&quot; style=&quot;text-align: left;&quot;' ..
 			'\n| colspan=&quot;' .. count_col .. '&quot; style=&quot;width: 0;&quot; |' ..
 			mw.getCurrentFrame():expandTemplate{
 				title = 'Notelist',
 				args = {refs = notelist_refs}
 			}
 	end
 	return out
 end
 
 function p.text()
 	local location = mw.getCurrentFrame().args['location']
 	local column = mw.getCurrentFrame().args['column']
 	return data[location][column]
 end