Module:Infobox country
Module documentation
[create]
local infobox = require( 'Module:Infobox' )
local graph = require( 'Module:Graph' )
local baseColors = {
'1f77b4', 'ff7f0e', '2ca02c', 'd62728', '9467bd', '8c564b', 'e377c2', '7f7f7f', 'bcbd22', '17becf'
}
local countryBlacklist = {
'AZ','BH','BY','CN','CU','DJ','EG','GQ','ER','ET','IR','KZ','LA','LY','MM','KP','PK','RU','SA','SO','SD','SY','TH','TR','TM','AE','UZ','VE','VN','YE'
}
function filter( arr, fn )
local r = {}
for i, v in pairs( arr ) do
if fn( v ) then
table.insert( r, v )
end
end
return r
end
function incrementer( start )
local i = start
return function ()
i = i + 1
return i
end
end
function round( num )
if num < 0.95 then
return math.floor( num * 10 + 0.5 ) / 10
else
return math.floor( num + 0.5 )
end
end
-- Note: This breaks once numbers start going up to the 1e+14.. range.
function formatNumber( num )
local nString = tostring( num )
local tDigits = #nString % 3
if tDigits == 0 then
tDigits = 3
end
return string.sub( nString, 0, tDigits ) ..
string.gsub( string.sub( nString, tDigits + 1 ), "...", ",%1" )
end
function formatDate( y, m )
return y .. '-' .. ( m > 9 and m or '0' .. m )
end
function getTimestamp( dateString )
local dateParts = mw.text.split( dateString, '-' )
return 1000 * os.time( {
year = dateParts[ 1 ],
month = tonumber( dateParts[ 2 ] ),
day = 1,
hour = 0
} )
end
function runI18n( msg, ... )
local r = msg
for i, v in pairs( arg ) do
r = string.gsub( r, '%$' .. i, v )
end
return r
end
function unfuzzyI18n( ... )
-- Fuzzy translations are surrounded by span tags that need to be removed
-- before using the msg as a title.
local text = string.gsub( runI18n( ... ), '<span class="mw%-translate%-fuzzy">', '' )
text = string.gsub( text, '</span>', '' )
return text
end
function tryWikidataLink( item )
local label = mw.wikibase.getLabel( item )
if label then
return "[[d:" .. item .. '|' .. label .. ']]'
else
return item
end
end
function notEmpty( arg )
return arg and arg ~= ''
end
-- TODO: Clean this up a bit.
function collateRows( data, group_by, initRow, addFn )
table.sort( data, function ( a, b ) return a[ group_by ] > b[ group_by ] end )
local result = {}
local currentRow
local currentKey
for _, row in pairs( data ) do
if row[ group_by ] ~= currentKey then
currentRow = initRow( row )
table.insert( result, currentRow )
currentKey = row[ group_by ]
end
addFn( currentRow, row )
end
return result
end
function getForCountry( data, country, type )
local cd = filter( data, function ( row ) return row[ 2 ] == country and row[ 3 ] == type end )
return cd
end
function getForCountries( data, countries, type )
local cd = filter( data, function ( row ) return row[ 3 ] == type and tableIncludes( countries, row[ 2 ] ) end )
return cd
end
function tableIncludes( arr, toFind )
if arr[ 2 ] then
for _, value in pairs( arr ) do
if value == toFind then
return true
end
end
return false
else
return arr[ 1 ] == toFind
end
end
function getAssumedEditorCount( num )
-- num is rounded up to the nearest ten in the dataset.
-- I have no idea how to estimate its actual value, so these are randomish
-- estimates
if num == 10 then
return 3
elseif num < 50 then
return num - 5
else
return num - 4.5
end
end
function getMinEditorCount( num )
-- num is rounded up to the nearest ten in the dataset.
return num - 9
end
function getAssumedPageViewsCount( num )
-- dunno
return num
end
function sumObject( data, fn )
local sum = 0
for i, v in pairs( data ) do
sum = sum + fn( v )
end
return sum
end
-- Unused?
function getTotalEditorCount( data )
return sumObject( data, function ( v ) return getAssumedEditorCount( v[ 4 ] ) end )
end
function parse_dbname( dbname, useLang )
local l = #dbname
local sourceOfTranslations = 'Translations:Template:OurProjects/'
-- These two are unused, but might be necessary is someone deletes the
-- pile of translations at Template:OurProjects.
--local specialProjectsNames = {
-- -- Hm...
-- wikidata = 'Wikidata',
-- metawiki = 'Meta-Wiki',
-- mediawikiwiki = 'Mediawiki',
-- commons = 'Commons'
--}
--local baseProjectsNames = {
-- wikibooks = 'Wikibooks',
-- wiktionary = 'Wiktionary',
-- wikivoyage = 'Wikivoyage',
-- wikinews = 'Wikinews',
-- wikiquote = 'Wikiquote',
-- wikisource = 'Wikisource',
-- wikiversity = 'Wikiversity',
-- wiki = 'Wikipedia'
--}
local specialProjects = {
wikidatawiki = '38',
commonswiki = '36',
specieswiki = '34'
}
local annoyingToTranslateProjects = {
metawiki = 'Meta-Wiki',
mediawikiwiki = 'Mediawiki',
}
local baseProjects = {
wikibooks = '16',
wiktionary = '8',
wikivoyage = '32',
wikinews = '12',
wikiquote = '20',
wikisource = '24',
wikiversity = '28',
wiki = '4'
}
local langCode, langName, projectNum, projectName
if annoyingToTranslateProjects[ dbname ] then
-- Just use the English name until a solution is found. These probably
-- won't ever show up anyway.
return nil, annoyingToTranslateProjects[ dbname ]
elseif specialProjects[ dbname ] then
-- These don't have set languages
projectNum = specialProjects[ dbname ]
else
for i, v in pairs( baseProjects ) do
local projectCode = string.match( dbname, i .. '$' )
if projectCode then
langCode = string.sub( dbname, 0, #dbname - #projectCode )
projectNum = baseProjects[ projectCode ]
break
end
end
end
if langCode then
langName = mw.language.fetchLanguageName( string.gsub( langCode, '_', '-' ), useLang )
end
if projectNum then
-- Translate project names.
local tBase = sourceOfTranslations -- number / lang
pcall( function ()
projectName = mw.getCurrentFrame():expandTemplate{ title =
tBase .. projectNum .. '/' .. useLang
}
end )
if not projectName then
-- Fallback to English
projectName = mw.getCurrentFrame():expandTemplate{ title =
tBase .. projectNum .. '/en'
}
end
return langName, projectName
else
-- not found
end
end
function lang_sum( data, project, type )
-- Not sure this will be necessary. There are stats available on 100+ and total. Unsure if it's the same thing.
local sum = 0
for i, v in pairs( data ) do
if v[ 1 ] == project and v[ 3 ] == type then
sum = sum + getAssumedEditorCount( v[ 4 ] )
end
end
return sum
end
function pageviews_project_sum( data, project )
local sum = 0
for i, v in pairs( data ) do
if v[ 1 ] == project then
sum = sum + getAssumedPageViewsCount( v[ 3 ] )
end
end
return sum
end
function process_editor_data( data, cd, countrySum, countryName, editorType )
local r = {}
for i = 1, 10 do -- We only want the top-10 projects.
local row = cd[ i ]
if not row then
break
end
local project = row[ 1 ]
local count = row[ 2 ]
local assumedCount = row[ 3 ]
local minCount = row[ 4 ] -- For editors
if count > 10 then
table.insert( r, {
project,
count,
assumedCount / lang_sum( data, project, editorType ),
assumedCount / countrySum,
assumedCount,
minCount
} )
end
end
return r
end
-- 'enwiki' -> 'English Wikipedia'
function getNameFromDb( project, isPageViews, useLang, i18n )
local r = ''
local langName, projectName = parse_dbname( project, useLang )
if langName and isPageViews then
--r = langName .. ' ' .. projectName
r = runI18n( i18n.language_project, langName, projectName )
elseif isPageViews then
r = projectName
else
-- Editor counts are limited to Wikipedias. Don't list project name.
r = langName
end
return r
end
-- TODO: Merge with getStatsTable. Need to share vars.
function getTextFromCount( count, ofProject, ofCountry, isPageViews, i18n, si18n, project_name, assumedCount, minCount )
local text = ''
if isPageViews then
-- Count is in thousands at the start
local m = { { 'B', 1000000 }, { 'M', 1000 }, { 'K', 1 } }
for i, v in pairs( m ) do
local letter, mag = v[ 1 ], v[ 2 ]
if count > mag * 1 then
text = '<span title="' ..
unfuzzyI18n( i18n.viewsHovertext, formatNumber( count * 1000 ) ) ..
'">~' .. ( round( count / mag * 100 ) / 100 ) .. letter .. '</span>'
-- round
break
end
end
--text = '~' .. count * 1000
else
local displayCount = math.floor( assumedCount / 10 + 0.5 ) * 10 -- round to nearest ten
text = '<span title="' .. unfuzzyI18n( i18n.editorsHovertext, minCount, count ) .. '">~' .. displayCount .. '</span>'
end
-- Figure out some way to describe the stats more fully.
local ofCountryText = round( ofCountry * 100 ) .. '%%'
local ofProjectText = round( ofProject * 100 ) .. '%%'
text = text ..
' (' ..
'<span title="' ..
unfuzzyI18n( si18n.ofCountryH, ofCountryText, project_name ) ..
'">' ..
runI18n( si18n.ofCountry, ofCountryText ) .. '</span>, ' ..
'<span title="' ..
unfuzzyI18n( si18n.ofProjectH, ofProjectText, project_name ) ..
'">' ..
runI18n( i18n.ofProject, ofProjectText ) .. '</span>' ..
')'
return text
end
function colorDot( i )
return '<span style="display:inline-block; height: 6px; width:6px; border-radius:5px; background: ' ..
'#' .. baseColors[ i ] ..
';"></span>'
end
function getStatsTable( data, isPageViews, useLang, i18n, si18n )
local r = {}
for i = 1, 10 do
local dataRow = data[ i ]
if not dataRow then
break
end
local project, count, ofProject, ofCountry = unpack( dataRow )
local row = {}
local project_name = getNameFromDb( project, isPageViews, useLang, i18n )
row[ 1 ] = (
-- Don't show dots for pageviews, for now.
-- No history, so no graph, so no need to color-code.
isPageViews and '' or
colorDot( i ) .. ' '
) ..
project_name
row[ 2 ] = getTextFromCount( count, ofProject, ofCountry, isPageViews, i18n, si18n, project_name, dataRow[ 5 ], dataRow[ 6 ] )
table.insert( r, row )
end
return r
end
function getEditorData( data, countryCode, editorType )
-- Fields: dbname, country, type, count
local DB_NAME, COUNTRY, EDITORTYPE, COUNT = 1, 2, 3, 4 -- columns in the dataset
local cd = getForCountries( data, countryCode, editorType )
-- Sum of all editors in region
local countrySum = sumObject( cd, function ( v ) return getAssumedEditorCount( v[ COUNT ] ) end )
-- Create a new table, summing up the countries' totals.
-- New table format: [ DB_NAME, count, assumedCount ]
local cd2 = collateRows( cd, DB_NAME, function ( row )
return { row[ DB_NAME ], 0, 0, 0 }
end, function ( row, toAdd )
row[ 2 ] = row[ 2 ] + toAdd[ COUNT ]
row[ 3 ] = row[ 3 ] + getAssumedEditorCount( toAdd[ COUNT ] )
row[ 4 ] = row[ 4 ] + getMinEditorCount( toAdd[ COUNT ] )
end )
-- Sort by count
table.sort( cd2, function ( a, b ) return a[ 2 ] > b[ 2 ] end )
return process_editor_data( data, cd2, countrySum, countryCode, editorType )
end
function getPageViewData( countryCode )
local DB_NAME, COUNTRY, COUNT = 1, 2, 3 -- columns in the dataset
local data = findMostRecentMonthWithData( 'Pageviews-by-country-monthly-$1.tab' ).data
local dataForCountry = filter( data, function ( row ) return tableIncludes( countryCode, row[ COUNTRY ] ) end )
local dataForCountry2 = collateRows( dataForCountry, DB_NAME, function ( row )
return { row[ DB_NAME ], 0, 0 }
end, function ( row, toAdd )
row[ 2 ] = row[ 2 ] + toAdd[ COUNT ]
row[ 3 ] = row[ 3 ] + getAssumedPageViewsCount( toAdd[ COUNT ] )
end )
table.sort( dataForCountry2, function ( a, b ) return a[ COUNT ] > b[ COUNT ] end )
local r = {}
for i = 1, 10 do
local row = dataForCountry2[ i ]
if row then
local project = row[ DB_NAME ]
local count = row[ 2 ]
if count > 1 then
local assumedCount = row[ 3 ]
local countrySum = sumObject( dataForCountry, function ( cRow )
return cRow[ 3 ]
end )
table.insert( r, {
project,
count,
assumedCount / pageviews_project_sum( data, project ),
assumedCount / countrySum
} )
end
end
end
return r
end
-- For a set of monthly data files on Commons with a standard naming including a
-- year-month string, find the most recent one that's been uploaded.
-- Returns data, date string, year, month
function findMostRecentMonthWithData( fileNameFormat )
local currentDate = os.date( '*t' )
local year, month = currentDate.year, currentDate.month
local fixIndex = function()
if month == 0 then
-- months are 1-indexed, roll over
year = year - 1
month = 12
end
end
local dateString
local currentData
repeat
month = month - 1
fixIndex()
dateString = formatDate( year, month )
local fileName = string.gsub( fileNameFormat, '%$1', dateString )
currentData = mw.ext.data.get( fileName )
until currentData
return currentData, dateString, year, month
end
function getRawEditorData()
local gapSizeInMonths = 1 -- 1 means show every month, 2 is every other month, etc.
local numberOfYearsToDisplay = 2 -- Note that geoeditors data starts in 2018.
-- Get all the files
local dates = {}
local files = {}
local currentData, currentDateString, currentYear, currentMonth =
findMostRecentMonthWithData( 'Geoeditors-monthly-$1.tab' )
-- Find the last two years of data
local year, month = currentYear - numberOfYearsToDisplay, currentMonth
while formatDate( year, month ) ~= currentDateString do
local dateString = formatDate( year, month )
table.insert( dates, dateString )
local file = mw.ext.data.get( 'Geoeditors-monthly-' .. dateString .. '.tab' )
table.insert( files, file and file.data )
month = month + gapSizeInMonths
if month > 12 then
month = month - 12
year = year + 1
end
end
table.insert( files, currentData.data )
table.insert( dates, currentDateString )
return files, dates
end
function findEditorCountPoint( data, project, countries, editorType )
local length = #data
local sum = 0
for i = 1, length do
local row = data[ i ]
if row[ 1 ] == project and row[ 3 ] == editorType and tableIncludes( countries, row[ 2 ] ) then
sum = sum + row[ 4 ]
end
end
return sum
end
-- For populating the graphs
-- For each of the projects given, generate a list of editor counts in past dates
function getEditorHistory( listOfLanguages, pastData, country, editorType )
local r = {}
local numberOfSnapshots = #pastData
for ii = 1, #listOfLanguages do
local project = listOfLanguages[ ii ][ 1 ]
local h = {}
table.insert( r, h )
for i = 1, numberOfSnapshots do
local snapshot = pastData[ i ]
if snapshot then
local count = findEditorCountPoint( snapshot, project, country, editorType )
table.insert( h, count )
else
-- Not available
table.insert( h, '' )
end
end
end
return r
end
function build_graph( editorHistory, dates )
local chartParams = {
width = 230,
height = 80,
type = 'line',
xType = 'date', yType = 'number',
yGrid = true,
xAxisMin = getTimestamp( dates[ 1 ] ),
yAxisMin = 0,
xAxisAngle = 45,
-- No legend in-graph. Place the colors next to their listings.
colors = '#' .. table.concat( baseColors, ',#' )
}
for i = 1, #editorHistory do
chartParams[ 'y' .. i ] = table.concat( editorHistory[ i ], ',' )
end
chartParams.x = table.concat( dates, ',' )
local chartJson = graph.chart( { args = chartParams } )
-- Turn it into a Lua object, and then back to JSON, so that ticks
-- can be overridden.
local chartObject = mw.text.jsonDecode( chartJson )
chartObject.axes[ 2 ].ticks = 3
-- chartObject.axes[ 3 ].ticks = 3 -- If the dates also need to be limited...
return mw.text.jsonEncode( chartObject )
end
return {
infobox = function( frame )
local TESTING = false
local useLang = mw.getCurrentFrame():expandTemplate{ title = 'Template:uselang' }
-- Note that we'll need to accept arguments as well...
-- Also i18n
local args = frame.args
-- temp. replace with local i18n = {} later.
local i18n = {
showmore = '(Show more)',
ofCountry = '~$1 of country',
ofRegion = '~$1 of region',
ofProject = '~$1 of project',
viewsHovertext = '$1 views, rounded up to the nearest thousand',
editorsHovertext = '$1 - $2 editors',
editorsOfCountry = 'Roughly $1 of Wikipedia editors located in the country are $2 Wikipedia editors',
editorsOfCountryR = 'Roughly $1 of Wikipedia editors located in the region are $2 Wikipedia editors',
editorsOfProject = 'Roughly $1 of $2 Wikipedia editors are located in the country. (Project totals exclude editors from countries in the Country Protection List.)',
editorsOfProjectR = 'Roughly $1 of $2 Wikipedia editors are located in the region. (Project totals exclude editors from countries in the Country Protection List.)',
pageviewsOfCountry = 'Roughly $1 of pageviews from the country are of $2',
pageviewsOfCountryR = 'Roughly $1 of pageviews from the region are of $2',
pageviewsOfProject = 'Roughly $1 of $2 pageviews come from readers located in the country',
pageviewsOfProjectR = 'Roughly $1 of $2 pageviews come from readers located in the region',
organizations = "Wikimedia organizations",
wikiproject = "Wikiproject",
censored = "Projects censored",
editors = 'Editors',
readers = 'Readers',
category = 'Category',
byactiveeditors = 'Major Wikipedias by active editors',
byveryactiveeditors = 'Major Wikipedias by very active editors',
activeeditorssub = '5-99 edits per month',
veryactiveeditorssub = '100+ edits per month',
bymonthlypageviews = 'Major projects by monthly pageviews',
excluding = 'Excluding editors from $1',
language_project = '$1 $2'
}
-- Populate i18n
for argName, argValue in pairs( args ) do
local is18n = string.sub( argName, 1, 5 ) == 'i18n-'
if is18n then
i18n[ string.sub( argName, 6 ) ] = argValue
end
end
local rawEditorData, dates = getRawEditorData()
-- Args fed to the infobox.
local iBArgs = {
--above = args.commonTitle or frame:getTitle(),
above = notEmpty( args.commonTitle ) and args.commonTitle or mw.getCurrentFrame():getTitle()
}
local countryCode = args.code
if not countryCode then
--error( 'Argument code= is unspecified' )
end
local countryCodes = mw.text.split( countryCode, ',' )
local isSingleCountry = #countryCodes == 1
if notEmpty( args.organizations ) then
iBArgs.label1 = i18n.organizations
iBArgs.data1 = args.organizations
end
if notEmpty( args.censorship ) then
iBArgs.label2 = i18n.censored
iBArgs.data2 = args.censorship
end
if notEmpty( args.wikiproject ) then
iBArgs.label3 = i18n.wikiproject
iBArgs.data3 = tryWikidataLink( args.wikiproject )
end
local editorSubbox = { child = 'yes', decat = 'yes' }
local pageviewsSubbox = { child = 'yes', decat = 'yes' }
local fillTable = function ( targetInfobox, tIncrementer, dataTable, key )
-- Add the data from dataTable to targetInfobox
for i = 1, #dataTable do
local rowNumber = tIncrementer()
targetInfobox[ 'label' .. rowNumber ] = dataTable[ i ][ 1 ]
--targetInfobox[ 'data' .. rowNumber ] = dataTable[ i ][ 2 ] ..
-- ( i == 3 and #dataTable > 3 and
-- '<br /><span class="mw-customtoggle-' .. key .. '">' .. i18n.showmore .. '</span>' or
-- '' )
targetInfobox[ 'data' .. rowNumber ] = dataTable[ i ][ 2 ]
-- Collapsible rows
if i > 3 then
targetInfobox[ 'rowclass' .. rowNumber ] = 'mw-collapsible mw-collapsed'
targetInfobox[ 'rowid' .. rowNumber ] = 'mw-customcollapsible-' .. key
end
end
if #dataTable > 3 then
targetInfobox[ 'data' .. tIncrementer() ] =
'<span class="mw-customtoggle-' .. key .. '" data-collapsetext="t2" data-expandtext="t3">' ..
i18n.showmore .. '</span>'
end
end
-- EDITOR STATS
do
-- Should there be one of those green/red arrows?
-- Ideally this should eventually link to a wikistats page with more data, with this just being a summary
-- Need to get the overall editor counts somehow. Otherwise things look ridiculous
-- in projects dominated by countries on the hidden list.
editorSubbox.title = i18n.editors
if notEmpty( args.editorcat ) then
editorSubbox.label1 = i18n.category
editorSubbox.data1 = tryWikidataLink( args.editorcat )
end
local rowsCompleted = incrementer( 2 )
local blacklisted = filter( countryCodes, function ( code )
return tableIncludes( countryBlacklist, code )
end )
local excludingText = ''
if #blacklisted > 0 and #blacklisted < #countryCodes then
excludingText = '<br />' .. runI18n( i18n.excluding, mw.text.listToText( blacklisted ) )
end
for editorType = 1, 2 do
local editorTypeCode = ( { '5..99', '100..' } )[ editorType ]
local editorData = getEditorData( rawEditorData[ #rawEditorData ], countryCodes, editorTypeCode )
local editorTable = getStatsTable( editorData, false, useLang, i18n, {
ofCountryH = isSingleCountry and i18n.editorsOfCountry or i18n.editorsOfCountryR,
ofProjectH = isSingleCountry and i18n.editorsOfProject or i18n.editorsOfProjectR,
ofCountry = isSingleCountry and i18n.ofCountry or i18n.ofRegion
} )
if #editorTable ~= 0 then
editorSubbox[ 'data' .. rowsCompleted() ] = ( {
i18n.byactiveeditors .. '<br />(' .. i18n.activeeditorssub .. ')',
i18n.byveryactiveeditors .. '<br />(' .. i18n.veryactiveeditorssub .. ')'
} )[ editorType ] .. excludingText
fillTable( editorSubbox, rowsCompleted, editorTable, 'editorlist-' .. editorType )
local editorHistory = getEditorHistory( editorData, rawEditorData, countryCodes, editorTypeCode )
if not TESTING then
editorSubbox[ 'data' .. rowsCompleted() ] = mw.getCurrentFrame():extensionTag( { name = 'graph', content = build_graph( editorHistory, dates ) } )
else
-- For testing
editorSubbox[ 'data' .. rowsCompleted() ] = '<graph>' .. build_graph( editorHistory, dates ) .. '</graph>'
end
end
end
end
-- PAGEVIEWS
do
pageviewsSubbox.title = i18n.readers
local pageviewData = getPageViewData( countryCodes )
local pageviewTable = getStatsTable( pageviewData, true, useLang, i18n, {
ofCountryH = isSingleCountry and i18n.pageviewsOfCountry or i18n.pageviewsOfCountryR,
ofProjectH = isSingleCountry and i18n.pageviewsOfProject or i18n.pageviewsOfProjectR,
ofCountry = isSingleCountry and i18n.ofCountry or i18n.ofRegion
} )
if pageviewTable[ 1 ] then
pageviewsSubbox.data1 = i18n.bymonthlypageviews
local rowsCompleted = incrementer( 2 )
fillTable( pageviewsSubbox, rowsCompleted, pageviewTable, 'pageviewlist' )
else
-- Something to indicate that the table isn't available?
end
end
-- TODO in the future when stats are available: Donor statistics.
-- The infobox module stuffs everything into globals. The only way to
-- avoid breaking everything is to reload the entire module via invoke.
iBArgs.header4 = mw.getCurrentFrame():expandTemplate( { title = 'Infobox', args = editorSubbox } )
iBArgs.header5 = mw.getCurrentFrame():expandTemplate( { title = 'Infobox', args = pageviewsSubbox } )
--mw.log( os.clock() )
return infobox.infobox( iBArgs )
-- to test:
--p.infobox({args={
-- code='US',
-- organizations = '[[Wikimedia Foundation]]<br />[[Wikimedia New York City]]<br />[[Wikimedia District of Columbia]]',
-- censorship='None', wikiproject = 'Q10816993', editorcat = 'Q8244096'
--}})
end,
test = function () -- Just for testing
--local a = mw.ext.data.get( 'Geoeditors-monthly-2018-10.tab' ).data
local a = mw.ext.data.get( 'Geoeditors-monthly-2020-02.tab' ).data
local total = 0
local us = 0
for i = 1, #a do
local r = a[ i ]
if r[ 3 ] == '5..99' then
local v = r[ 4 ] - 9
if r[ 2 ] == 'US' then
us = us + v
end
total = total + v
end
end
--return total
return us / total
end
}