Kontent qismiga oʻtish

Modul:Goalscorers

Vikipediya, ochiq ensiklopediya

This template shows football(soccer) goalscorers, and is used on many soccer pages.

Data subpages


    Usage[manbasini tahrirlash]

    {{#invoke:Goalscorers|main}}


    Used by template {{goalscorers}}.



    require('Module:No globals');
    local yesno = require('Module:Yesno')
    
    local p = {} 
    local g = {}         -- for parameters with global scope in this module
    g.goalscorers = {}   -- table where selected and sorted players will be place
    g.args = {}
    g.totalGoals = 0
    local data = {}      -- module subpage data -- require('Module:Goalscorers/data/UEFA Euro 2016 qualifying'); 
    
    p.errorString = ""
    function p.error_msg()
    	if p.errorString ~= "" then
    		return '<span style="font-size:100%" class="error">'
    	         -- '<code style="color:inherit;border:inherit;padding:inherit;">&#124;_template=</code>'
    	         .. p.errorString .. '</span>';
    	end
    end
    -- data for goals scored held in module subpages, e.g. "Module:Goalscorers/data/UEFA Euro 2016 qualifying"
          --[[ parameters containing data help in three tables
    						data.rounds = {}   -- group, play-off
    						data.goalscorers = {}    -- player, country, goals in each round)
    						data.owngoalscorers = {} -- player, country, goals in each round)
    						data.updated = {}        -- date of latest update (month, day, year)
    					--]]
    
    --[[ ############################ Parameter handing  ###############################
         p.getArgs() - gets arguments from frame (invoke) or parent frame (template)     
    ]]
    
    local function getArgs(frame)
    	local parents = mw.getCurrentFrame():getParent()
    		
    	for k,v in pairs(parents.args) do
    		--check content
    		if v and v ~= "" then
    			g.args[k]=mw.text.trim(v) --parents.args[k]
    		end
    	end
    	for k,v in pairs(frame.args) do
    		--check content
    		if v and v ~= "" then
    			g.args[k]= mw.text.trim(v)  --parents.args[k]
    		end
    	end
    	-- allow empty caption to blank default
    	--if parents.args['caption'] then templateArgs['caption'] = parents.args['caption'] end
    end
    
    --[[ ############################## Main function and other functions ######################
         p.main()                      - simple output of the data in the module in list form
         p.addIntroductorySentence()   - add sentence on number of goals and matches, with goals per match
         p.addFooterSentence()         - add footnote
         p.getNumberMatches()
         p.owngoals()                  - get own goals (no longer used?)
    	 p._owngoals()                 - core functionality for p.owngoals()
    ]]
    function p.main(frame)
        getArgs(frame)
        local dataTarget =  g.args[1] or  g.args['data']
        if dataTarget then
            data = require('Module:Goalscorers/data/'.. dataTarget) --or 'UEFA Euro 2016 qualifying' 
        	return p.useModuleData(frame)  -- data on goals taken from module subpage
        else
        	return p.useTemplateData(frame)  -- data on goals/assists taken from template
        end
        
    end
    function p.useModuleData(frame)
    
        --p.goalscorers = {} -- table where selected and sorted players will be place
        g.totalGoals = 0
        local ok = p.selectGoalscorers() -- selected goalscorers meeting round and group criteris
        if not ok then return p.error_msg() end
        
        -- CHANGE: append own goals to list  (data will now include goals and own goals (negative))  
        p.selectGoalscorers("OG")    
        
        p.sortGoalscorers() -- sort selected goalscorers by number of goal, then country
    
        local outputString = p.addIntroductorySentence() .. p.outputGoalscorers(frame) .. p.addFooterSentence()
    --                      .. ""              --TODO add intermediate heading?
    --                      .. p._owngoals(frame)  -- output list of goalscorers
        
        return p.error_msg() or outputString
    end
    
    function p.addIntroductorySentence()          -- add introductory text
    	
    	local totalGoalString = "A total of " .. g.totalGoals .. " goals were scored."
    	--There were [has been|have been|was|were] #GOALS goal(s) scored in #MATCHES match(s), for an average of #GOALS/#MATCHES per match.
    	
    	local matches, dateUpdated = p.getNumberMatches()
    	local mdyFormat = yesno(g.args['mdy'])
    	
    	local Date = require('Module:Date')._Date
    	
    	local pluralGoals = "s"
    	local text1 = ""
    	if g.totalGoals == 1 then
    		pluralGoals = ""
    		if dateUpdated == 'complete' then text1 = "was" else text1 = "has been" end
    	else
    		if dateUpdated == 'complete' then text1 = "were" else text1 = "have been" end
    	end
    	local text = string.format("There %s %s goal%s scored", text1, mw.getLanguage('en'):formatNum(g.totalGoals), pluralGoals)
    	
    	local pluralMatches = "es"
    	if matches==1 then pluralMatches = "" end
    	if matches then
    		local average = g.totalGoals/tonumber(matches)
    		local precision = 3                        -- display d.dd (three significant disgits)
    		if average < 1 then precision = 2 end      -- display 0.dd (thwo significant disgits)
    		average = tostring (average)
    
    		local pluralAverage = "s"
    		if  tonumber(string.format("%.2f",average))==1 then pluralAverage = "" end
    	    text = text .. string.format(" in %d match%s, for an average of %."..precision.."g goal%s per match", matches, pluralMatches, average, pluralAverage)
    	end
        
    	if dateUpdated == 'complete' or dateUpdated == "" then
    	    text = text .. "."
    	else
    		local dateFormat =  'dmy'                                                       -- default
    		if data.params and data.params['date_format'] then dateFormat = data.params['date_format'] end  -- from data module
    		if mdyFormat == true then dateFormat = "mdy" else
    			if mdyFormat == false then dateFormat = "dmy" end   -- template param overrides
    		end
    	    text = text .. " (as of " .. Date(dateUpdated):text(dateFormat) .. ")."
    	end
    	text = p.addAdditionHeaderText(text, dateUpdated)  -- handles template parameters bold, further, extra
    
    	return text --totalGoalString 
    end
    function p.addFooterSentence()                 -- add notes at bottom
        
        local footerSentence = g.args['footer'] or ""
        --footerSentence = "This is a footer sentence."               -- test footer
        if data.params then
        	local footer = data.params['footer'] or nil
    	    if footer then
    	    	local frame = mw.getCurrentFrame()
    	    	local processed = frame:preprocess(footer)
    	    	if g.notes then
    	    		footerSentence  = footerSentence  .. processed
    	    	end
    	    end
        end
        
        if footerSentence ~= "" then
        	footerSentence = '<div style = "" >' .. footerSentence .. '</div>'
        end
        return footerSentence
    end
    function p.getNumberMatches()
       	local matches = g.args['matches']
       	local dateUpdated = data.updated['date'] or "1700-01-01" --'complete' -- assume completed if missing
      
        --local round = g.args['round'] or "all"    -- round =  all(empty)|group|playoffs
        --local group = g.args['group'] or "all"     -- group =  all(empty), A,B,C etc 
        local round, group =  p.getRoundAndGroup()
        
        local allGroupGames = 0
        local latestGroupDate = "1800-01-01" 
        if group and (round == "all" or group == "all") then           -- count all the group games
        	for k,v in pairs(data.updated.group) do
        		allGroupGames = allGroupGames + v[1]
        		if v[2] ~= "complete" and v[2] > latestGroupDate then latestGroupDate = v[2] end -- update if later date
        	end
        	if latestGroupDate == "1800-01-01" then latestGroupDate = "complete"  end -- no dates so must be complete
        end
        if group and (round == "all" and group ~= "all") then                   -- for totals of all rounds with only one group
               allGroupGames     = data.updated.group[group][1]     -- number matches
               latestGroupDate = data.updated.group[group][2]       -- update date or completed
    	end
    	if round == "all" then                                       -- all rounds and goals
            matches=0
            for k,v in pairs(data.updated) do 
                if k == "group" then
            		matches = matches + allGroupGames
        	     	if latestGroupDate ~= "complete" and latestGroupDate > dateUpdated then 
        	     		dateUpdated = latestGroupDate                -- update if later date
        	        end 
            	elseif p.validateRound(k) then
            		matches = matches + v[1]
        		    if v[2] ~= "complete" and v[2] > dateUpdated then dateUpdated = v[2] end -- update if later date
            	end
            	
            end 
    	elseif round == "group" then                                  -- group round only
    	    if group == "all" then                            
    		   matches = allGroupGames
    		   dateUpdated = latestGroupDate  
    		else                                                      -- single group only
               matches     = data.updated.group[group][1]                 -- number matches
               dateUpdated = data.updated.group[group][2]                 -- update date or completed
    		end
    	else                                                          -- any other round
           matches     = data.updated[round][1]                           -- number matches
           dateUpdated = data.updated[round][2]                           -- update date or completed
        end 
        
        if dateUpdated == "1700-01-01" then dateUpdated = "complete"  end -- no dates so must be complete
    
       	return matches, dateUpdated
    end
    
    function p.owngoals(frame) -- need to check parameters if external call
        getArgs(frame)
        data = require('Module:Goalscorers/data/'.. g.args[1]) --or 'UEFA Euro 2016 qualifying' 
    
        local outputString = p._owngoals(frame)
        return  p.error_msg() or outputString
    end
    function p._owngoals(frame) -- internal call for own goals
    
        --p.goalscorers = {} -- table where selected and sorted players will be place
        
        p.selectGoalscorers("OG") -- selected goalscorers meeting round and group criteris
        
        p.sortGoalscorers() -- sort selected goalscorers by number of goal, then country
    
        return p.outputGoalscorers(frame, "OG") -- output list of goalscorers
        
    end
    function p.validateRound(round)
       local validateRound = false
        for k,v in pairs(data.rounds) do
           if k == round then validateRound = true end             -- data for this round exists
    	end
    	return validateRound
    end
    
    --[[ ############################## functions to select goalscorers ######################
          p.selectGoalscorers()     - select goals scoreers required for list (rounds, groups)
          p.getRoundAndGroup()
          p.getGoalsCol(round)      - get column containing round data or first data column if round = all
          (country, possibleGroup)
          p.getGoals (u, player)
          p.parseComment(comment)
          p.getPlayer(u)
    ]]
    --[[ p.selectGoalscorers()     
             - select players meeting round and group criteria from goalscoreres list
             - gets goals and comments
    ]]
    function p.selectGoalscorers(og)
        
        local round, group =  p.getRoundAndGroup()        
        if not round then return false end                    -- exit if no valid round
        
        local goalMinimum = tonumber(g.args['minimum']) or -5  -- assume 5 own goals is maximum
        local goalsCol = p.getGoalsCol(round)                  -- first column for goals
        
        -- select players who have scored in rounds/groups requested
        local goalscorerData = data.goalscorers
        if og == "OG" then goalscorerData = data.owngoalscorers end
        
        for k,v in pairs(goalscorerData) do
            local goals, comment = 0, ""                         -- goals > 0 is the flag to include the player
            local playerName, playerAlias = p.getPlayer(v[1])                -- player name
            local goalsByRound, commentByRound = 0, ""
    		
    		if round == "all"  then                         -- goals in all rounds and all groups
    		    
    		    for i = goalsCol, #v, 1 do        
    		    	if group and group ~= "all" and i == p.getGoalsCol("group") and group ~= p.getGroup(v[2], v[3])  then 
    		    	   goalsByRound = 0
    		    	   commentByRound = ""
    		    	else
    		    		goalsByRound, commentByRound = p.getGoals( v[i] , playerName)
    		    	end
    
    		    	goals = goals +   goalsByRound              --TODO use getGoals on round options
    		    	if commentByRound ~= "" then
    			    	if comment == "" then
    			    		comment = commentByRound 
    			    	else
    			    		comment = comment .. "," .. commentByRound  --TODO decide on comma or semi-colon
    		    		end
    	       		end
    		    	i = i+1
    		    end
    		elseif round == "all2" and group ~= "all" then         -- goals in all rounds but only from one group
    
    			--TODO code to go through all rounds but only include goals in specified group [TODO merge with above option]
    			--mw.addWarning( g.args[1] .. ":Mix:round=all and group=" .. group .. "/" .. p.getGroup(v[2], v[3] ) )
    		    for i = goalsCol, #v, 1 do        
    		    	if i == p.getGoalsCol("group") and group ~= p.getGroup(v[2], v[3])  then 
    		    	   goalsByRound = 0
    		    	   commentByRound = ""
    		    	else
    		    		goalsByRound, commentByRound = p.getGoals( v[i] , playerName)
    		    	end
    		    	goals = goals +   goalsByRound              
    		    	if commentByRound ~= "" then
    			    	if comment == "" then
    			    		comment = commentByRound 
    			    	else
    			    		comment = comment .. "," .. commentByRound  --TODO decide on comma or semi-colon
    		    		end
    	       		end
    		    	i = i+1
    		    end
    		elseif round == "group" then                                  -- group round only
    		    if group == p.getGroup(v[2], v[3]) then                         -- single group only 
    				goals, comment = p.getGoals( v[goalsCol] , playerName)
    			elseif group == "all" then                                 -- any group
    				goals, comment = p.getGoals( v[goalsCol] , playerName)
    			else   
    				-- do nothing for other groups
    			end
    		--elseif round == "playoffs" then                                   -- playoff round (redunant?)
    		--	   goals = v[goalsCol]
    		else                                                              -- any other round
    			goals, comment = p.getGoals( v[goalsCol] , playerName)        -- should also handle playoffs
    	    end 
    	    if goals >= goalMinimum and goals ~= 0 then
    	    	   if comment ~= "" then 
    	    	   	  if og == "OG" then 
    	    	   	  	comment = '<span> (' .. p.sortComment(comment) .. ')</span>' 
    	    	   	  else
    	    	   	  	comment = '<span>' .. comment .. '</span>'   -- no parenthesis when using notes
    	    	      end
    	    	   end
    	    	   
    	    	   if og == "OG" then goals = -goals end  -- make owngoals negative numbers
    	    	   
    			   g.goalscorers[#g.goalscorers+1] = { player=playerName, alias=playerAlias,
    			   	                                   country=v[2], 
    			   	                                   goals=goals, 
    			   	                                   comment=p.parseComment(comment)}
    			   --g.totalGoals = g.totalGoals + math.abs(goals)    -- increment total goal counter	                                  
    	    end
    	    g.totalGoals = g.totalGoals + math.abs(goals)    -- increment total goal counter
        end
        return true -- data collected for selected goalscorers 
    end
    --[[ p.getRoundAndGroup()
    
    
    ]]
    function  p.getRoundAndGroup()
        local round = g.args['round'] or "all"    -- round =  all(empty)|group|playoffs
        local group = g.args['group'] or "all"     -- group =  all(empty), A,B,C etc  
        
        local validateRound = false
        local validateGroupRound = false
        for k,v in pairs(data.rounds) do
           if k == round then validateRound = true end             -- data for this round exists
           if k == "group" then validateGroupRound = true end      -- there is a group round
        end
        if validateRound == false and round ~= "all" then 
        	local message = 'Invalid round "' .. round .. '" specified. No data found for that round. '
        	mw.addWarning( message )
        	p.errorString = p.errorString .. message
        	round = nil
        end
        if validateGroupRound == false  then group = false end  -- there is no group round
        
        -- TODO add group error checking
        -- Could merge with getGoalsCol() and also return goalsCol
        return round, group
    end
    
    --[[  p.getGoalsCol(round)
          - get column containing round data or first data column if round = "all" 
          - allows group column to be omitted from player table when group table provided 
    ]]
    function p.getGoalsCol(round)
       
        local minimum = 1000
        if round == "all" then  -- if all need column of first round
           for k,v in pairs(data.rounds) do
           	  if v < minimum then minimum = v end
           	  --return v -- return the first one  [this seemed to work reliably, but sometimes table order is not as listed]
           end
           return minimum
        end
        if data.rounds and data.rounds[round] then
        	return  data.rounds[round] -- get column containing goals for that round
        else
        	return 4  -- an old default when no data.round (may not be necessary)
        end
    end
    
    --[[ p.getGroup(country, possibleGroup)
             - get group from group table or from player table    
             - possibleGroup is the column containing the Group (when no group table) or the first data column
    ]]
    function p.getGroup(country, possibleGroup)             -- row contain player name, country code, group if given, goals
    	if data.groups then
           for k,v in pairs(data.groups)  do  -- iterate through the groups
                --local = gotGroup = false
        		for j,u in pairs(v) do       -- for each group
        		   if u == country then
        		   	  return k
        		   end
        		end
        	end
            return "no group found"
        else 
        	return possibleGroup -- no group table, so assume column three contains the group
    	end
    	
    end
    --[[ get number of goals and any associated comment
          the goals can be a single number (the usual case)
            or as an option table (e.g. for own goals): { number of own goals, comma-delimited list of opponents }
        - if the entry is a table, we want the first entry (a number) and the second (comment string)
        - otherwise, if a number, we just want the number and an empty string
    ]]
    function p.getGoals (u, player)
    	if type(u) == 'table' and type(u[1]) == 'number' then
    		return u[1], u[2]            -- return number of goals, comment
    	elseif type(u) == 'number' then
    		return u, ""                 -- return number of goals, empty string
    	else
    		p.errorString = p.errorString .. " Invalid goals entry for player " .. player
    		return 0, ""
    	end
    end
    function p.parseComment(comment)
    	
    	local frame = mw.getCurrentFrame()
    
    	-- we have something like "{{efn-ua|name=goals}}"
    	if string.find(comment, "efn" , 1 , true ) then       -- if we have a comment with a note
    		g.notes = true                                    -- set flag
    	end
    	
    	
    	return frame:preprocess(comment)
    end
    
    function p.getPlayer(u)
    	if type(u) == 'table'  then
    		if type(u[1]) == 'string' and type(u[2]) == 'string' then
    			--[[if #u[2] >1 then 
    				p.errorString = p.errorString  .. "\n\nWe have u[1]=" .. u[1] .. " and u[2]=" .. u[2]
    			end]]
    			return u[1], u[2]            -- return player name, player sorting alias
    		else
    			p.errorString = p.errorString .. " Invalid name entry for player " .. u[1] .. ", " .. u[2] 
    			return "", ""     --TODO errroer
    		end
    	elseif type(u) == 'string' then
    		return u, ""                 -- return player name
    	else
    		p.errorString = p.errorString .. " Invalid name entry for player " .. u or u[1] or "unknown"
    		return "", ""
    	end
    end
    
    --[[ ############################## functions to sort goalscorers ######################
            p.preprocessSortName (name)
            p.getPlayerSortName (playerName, sortName, countryName)
            p.sortComment(comment)
            p.getCountryName(country)
            p.sortGoalscorers()             -- the main sort funtion
            
    ]]
    
    --[=[ function p.preprocessSortName()
          stripp off wikitext [[ and ]]
          force to lowercase
          change special characters to standard letters
    ]=]
    function p.preprocessSortName (name)
    	name = string.gsub(name, "%[%[", "")              -- strip off [[ and ]]
    	name = string.gsub(name, "%]%]", "")
        --name =string.lower(name)                          -- force lower case and return
        name = mw.ustring.lower(name)                       -- use unicode function
    
    	local specialChars = {                            -- list of special characters and replacement pairs
    		                   { "ı", "i" } , { "İ", "i" } , { "ß", "ss" },
    		                   { "ý", "y" } , { "ř", "r" } , { "ő", "o" },
    		                   { "é", "e" } , { "è", "e" } , { "þ", "th" },
    		                   { "ē", "e" } , { "ņ", "n" } , { "č", "c" },
    		                   { "ū", "u" } , { "ž", "z" } , { "æ", "ae" },
    		                   { "å", "a" } , { "ø", "o" } , { "ą", "a" },
    		                   { "ń", "n" } , { "ł", "l" } , { "ã", "a" },
    		                   { "ș", "s" } , { "š", "s" } , { "í", "i" },
    		                   { "á", "a" } , { "ä", "a" } , { "ć", "c" },
    		                   { "ç", "c" } , { "ğ", "g" } , { "ö", "o" },
    		                   { "ë", "e" } , { "ú", "u" } , { "ó", "o" },
    		                   { "ð", "d" } , { "ü", "u" } , { "ű", "u" },
    		                   { "ā", "a" } , { "ī", "i" } , { "đ", "d" },
    		                   { "ă", "a" } , { "â", "a" } , { "ż", "z" },
    		                   { "ț", "t" } , { "ş", "s" } , { "ś", "s" },
    		                   { "ǎ", "a" } , { "ě", "e" } , { "ů", "u" },
    		                   { "ĕ", "e" } , { "ñ", "n" } , { "ď", "d" },
    		                   { "ï", "i" } , { "ź", "z" } , { "ô", "o" },
    		                   { "ė", "e" } , { "ľ", "l" } , { "ģ", "g" },
    		                   { "ļ", "l" } , { "ę", "e" } , { "ň", "n" },
    		                   { "ò", "o" }
                             }
        for k,v in pairs(specialChars) do                 -- replace special characters from supplied list
        	name = string.gsub(name, v[1], v[2])
        end
    
    	return name                     
    end
    --[[ return the name for sorting 
           return supplied alias name for sorting
           otherwise
              checks for pipe (redirect) and uses name after pipe
              splits name into words
                 returns first name if only name (e.g. Nani)
                 otherwise returns name in format second_name [.. last name], firstname
    ]]
    function p.getPlayerSortName (playerName, sortName, countryName)
    	
    			--dewikify all names before sorting, also forces lowercase
    	playerName = p.preprocessSortName(playerName)
    	sortName = p.preprocessSortName(sortName)
    	
    	if sortName ~= "" then                           -- if we have a sort name supplied
    		return sortName                              --            then return it
    	end
    	
    	-- players from certain countries will use name in order supplied
    	local noSort = { "CAM", "CHN", "TPE", "MYA", "PRK", "KOR", "VIE" }
    	for k,v in pairs(noSort) do 
    		if v == countryName then
    			return playerName
    		end
    	end
    	
    	
    	-- else work it out from the supplied player name
    		
        -- we don't want to test the name in a redirect, so get name after pipe if there is one
        if string.find (playerName, "|") then                 -- test for redirect
          	local names = mw.text.split( playerName, "|")    
           	playerName = names[2]                               -- get name after pipe
        end
    
        local names = mw.text.split( playerName, " ") -- we don't want to sort on first name
    	
    	if #names == 1 then
    		return names[1]                             -- return name of single name player
    	else
    		-- we will assume the second name is the sort name e.g, Joe Bloggs, Jan van Bloggen
    		local name = names[2]                   -- set name to second name e.g. Bloggs or van
    		local i=3
    		while i <= #names do                       -- any addition names e.g. Bloggen
    			name= name .. names[i]
    			i=i+1
    		end
    		name = name .. ", " .. names[1]           -- add first name e.g. Joe or Jan
    		        
    		return name                                -- sort on second name third name etc, first name	
    	end
    	
    end
    
    -- sort the list of countries alphabetically
    function p.sortComment(comment)
    
    	local items = mw.text.split( comment, ",")         -- split comma-delimited list
    
        for k,v in pairs(items) do 
        	items[k] = mw.text.trim(v)                          -- trim spaces and coe
        end
        
    	table.sort(items, function(a,b) return a<b end)         -- sort the table alphbetically
    
    	local list = "against "                    -- construct the alphabetical list string
    	for i=1, #items do
    		local sep =  ", "                              -- separator for comma-delimited list
    		if i==1 then sep = ""                          -- first word doesn't need comma
    		elseif i==#items then sep = " & "            -- use "and" before last word
    		end
    		list = list .. sep .. items[i]
    	end	
    	return list
    	
    end
    function p.getCountryName(country)
    	
    	if string.len(country) == 3 then      -- if the country given as a three-letter code
    		local codes = require('Module:Goalscorers/data/Country codes')
    	    
    	    for k,v in pairs(codes.alias) do 
        	   if v[1] == country then
        	   	   return v[2]
        	   end
            end
    	else
    	    return country                    -- return the country name as is
    	end
    end
    --[[ sort goalscorers by goals, country and name
            the sort first sorts by number of goals
            when these are equal, it sorts by country
            when these are equal, it sorts by name
            Note: the name sort is on the first name
                   - a split of the name and sort on the last name is possible
                   - however, this would be complicated by Dutch (e.g. Stefan de Vrij) and Spanish names
                   - would sort on second name be better
    ]]
    function p.sortGoalscorers()
        
        local sort_function = function( a,b )
    		    if (a.goals > b.goals) then                -- primary sort on 'goals' -> a before b
    		        return true
    		    elseif (a.goals < b.goals) then            -- primary sort on 'goals' -> b before a
    		        return false
    		    else -- a.goals == b.goals 		           -- primary sort tied, 
    		        
    		        --return a.country < b.country         -- resolve with secondary sort on 'country'
    			    local country_a = p.getCountryName(a.country)  -- sort on name of country, not the code
    			    local country_b = p.getCountryName(b.country)
    			    
    			    if (country_a < country_b) then        -- secondary sort on 'country'
    			        return true
    			    elseif (country_a > country_b) then    -- secondary sort on 'country'
    			        return false
    			    else -- a.country == b.country 		   -- secondary sort tied, 
    
    			        --return a.player < b.player         --resolve with tertiary sort on 'player' name
                        
                        local player_a = p.getPlayerSortName(a.player, a.alias, a.country) -- get player name for sorting
                        local player_b = p.getPlayerSortName(b.player, b.alias, b.country)
                        
                        return player_a < player_b      -- 
    --[[]
                         --local test_a, test_b = a.player, b.player
    
                       -- we don't want to test the name in a redirect, so get name after pipe if there is one
                        if string.find (a.player, "|") then                 -- test for redirect
                        	local names = mw.text.split( a.player, "|")    
                        	test_a = names[2]                               -- get name after pipe
                        end
                        if string.find (b.player, "|") then
                        	local names = mw.text.split( b.player, "|")
                        	test_b = names[2]
                        end
                        
    			        local names_a = mw.text.split( test_a, " ") -- we don't want to sort on first name
    			        local names_b = mw.text.split( test_b, " ") --     so split names 
    			        
    			        if not names_a[2] then names_a[2] = test_a end -- for players with one name
    			        if not names_b[2] then names_b[2] = test_b end
    			        
    			        return names_a[2] < names_b[2]      -- sort on second name
    ]]			        
    			    end		        
    		    end
    		end
    		
        table.sort(g.goalscorers, sort_function)
    
    
    end
    function   p.tabulateGoalscorers(frame, og) 
    	
        -- ==============output the lists of goalscorers by goal======================
        local goalNumber = 1000
        local maxRank = tonumber(g.args['maxrank'] or 10)  -- limit list top ten or value in parameter maxrank
        local rank = 1
        local playerCount = 0
        local rankCount = 0
        local playerCells = ""
        local firstplayerCell = ""
    
        local tableString = '\n{| class="wikitable"'                                           -- start table 
                             ..'\n|-' .. '\n!Rank !! Player !! Goals'                          -- add table headers
        if g.args['header'] then tableString = tableString .. '\n|+ ' .. g.args['header']  end -- add header       
        for j,u in pairs(g.goalscorers) do    -- run through sorted list of selected goalscorers
     
        	-- is the player active still?
        	local playerActive = false
        	if data.active_countries then
        		for k,v in pairs(data.active_countries) do
        		  if v == u['country'] then
        		  	playerActive = true
        		  	break;
        		  end
        		end
        	end
        	local _,roundStatus = p.getNumberMatches()
        	if roundStatus == "complete" then playerActive = false end  -- overrides active_countries
        	
        	-- wikitext for tablulated list    
           	local goalscorerString = p.addLinkedIcon(frame, u['country'])    -- linked flag icon    
        	if playerActive and g.args['bold']~='no' then
        		goalscorerString = goalscorerString  .. " '''" .. u['player'] .. "'''>"    -- bolded name
        	else
       		    goalscorerString = goalscorerString  .. " " .. u['player']                  -- name
        	end
        	goalscorerString = goalscorerString  .. u['comment']                -- comment for o.g.
    
           -- we have a goalscorer
            playerCount = playerCount + 1
            rankCount = rankCount + 1
            
        	if u['goals'] < goalNumber then         -- player belongs to rowspan for new number of goals
        		                                    -- need to generate code for the previous rowspan (if there is one)
        		                                    -- then start the counts and player list for the new one
    	        
    	        if playerCount == 1 then
    	        	firstplayerCell = '\n|' .. goalscorerString           -- if first player in list just create cell and set goals
    	        	goalNumber = u['goals']
    	        	--rank = 1
    	        	rankCount = 0
    	        else    	                                              -- else generate previous rowspan
    		        local rowSpan = rankCount
    		        if playerCount > maxRank * 1.5 then
    		        	firstplayerCell = '\n| style="font-style:italic;text-align:center;"|' .. rankCount .. " players"
    		        	playerCells = ""
    		        	rowSpan = 1
    		        end
    		        tableString = tableString .. '\n|-\n| style="text-align:center;" rowspan="' .. rowSpan .. '"|' .. rank 
    		        --if rankCount > 1 then tableString = tableString  .. "=" end  -- adds equals when rank shared
    		        tableString = tableString .. firstplayerCell 
    		        tableString = tableString .. '\n| style="text-align:center;" rowspan="' .. rowSpan .. '"|'  ..  goalNumber
    		        tableString = tableString .. playerCells
    
    		        rank = rank + rankCount	
    		        if rank > maxRank  then break end -- limit list top ten or value in parameter
    		        rankCount = 0
    	   			goalNumber = u['goals']
    	   			firstplayerCell = '\n|' .. goalscorerString   -- set first player cell for next rowspan
    	   			playerCells = ""
    			end
            else                                                                      -- else another player with same number of goals
            	playerCells = playerCells .. '\n|-' .. '\n|' .. goalscorerString      -- add to player cell list
            end
        end -- reached end of list of goalscorers
    
    	if tableString ~= "" then
            tableString = tableString .. "\n|}"
    		return  tableString
    	else
    		return ("No goals matching requested criteria.")
    	end
    	
    	
    end
    function   p.outputGoalscorers(frame, og) -- output list of goalscorers
        if g.args['table'] then return p.tabulateGoalscorers(frame, og) end  -- optional table output
        
        local outputString = ""	
        if og == "OG" then   end
    
        -- ==============output the lists of goalscorers by goal======================
        local goalNumber = 1000
        --local goalMinimum = tonumber(templateArgs['minimum']) or 0
        
        local listOpen = false -- flag for list started by template {{Div Col}} 
        
        for j,u in pairs(g.goalscorers) do    -- run through sorted list of selected goalscorers
        	
        	--if u['goals'] < goalMinimum then break end -- limit list to goals over a threshold (now handled in select goalscorers)
        		
        	if u['goals'] < goalNumber then         -- start new list of new number of goals
        		if listOpen then                    -- if an open list, close last list
        			outputString = outputString .. p.closeList(frame) 
        			listOpen = false -- redundant as will be set true again
        		end
        		goalNumber = u['goals']
        		
        		local goalString = " goal"
        		--if og == "OG" then 	
        		if goalNumber < 0 then
        			goalString = " own" .. goalString 
        		end
        		if  math.abs(u['goals']) ~= 1 then goalString = goalString .. "s" end
    
        		outputString = outputString .. "\n'''" .. math.abs(u['goals']) .. goalString .. "'''"   -- list caption
        		
        		outputString = outputString .. p.openList(frame,og) --start new list
        		listOpen = true
        		--goalNumber = u['goals']
        	end
        	-- is the player active still?
        	local playerActive = false
        	if data.active_countries then
        		for k,v in pairs(data.active_countries) do
        		  if v == u['country'] then
        		  	playerActive = true
        		  	break;
        		  end
        		end
        	end
        	local _,roundStatus = p.getNumberMatches()
        	if roundStatus == "complete" then playerActive = false end  -- overrides active_countries
        	
        	-- wikitext for bullet list    
           	local goalscorerString = '\n*<span>' .. p.addLinkedIcon(frame, u['country'])    -- linked flag icon    
        	if playerActive and g.args['bold']~='no' then
        		goalscorerString = goalscorerString  .. " <b>" .. u['player'] .. "</b>"    -- bolded name
        	else
       		    goalscorerString = goalscorerString  .. " " .. u['player']                  -- name
        	end
        	goalscorerString = goalscorerString  .. u['comment']   .. '</span>'             -- comment for o.g.
        	                              
        	outputString = outputString .. goalscorerString   --  .. " " .. tostring(u['goals'])
    
        end -- reached end of list of goalscorers
    
    	if outputString ~= "" then
    	    outputString = outputString .. p.closeList(frame)
    
    		return outputString
    	else
    		return ("No goals matching requested criteria.")
    	end
    end
    
    -- output icon linked to national team page
    function p.addLinkedIcon(frame, country)
    	local icon = data.templates['flag_icon_linked']         -- fbicon etc set in data module
    	local level = data.templates['youth_level']  or ""           -- parameter for youth level, ie under-21
        -- equivalent to  {{fbicon|country}}     
        local flagVariant = ""
        if data.templates.flagvar and data.templates.flagvar[country] then
        	flagVariant = data.templates.flagvar[country] 
        end
        if level ~= "" then 
        	return frame:expandTemplate{ title = icon , args = { level, country, flagVariant } }   
        else
        	return frame:expandTemplate{ title = icon , args = { country, flagVariant } }     -- flag icon
        end
    end
    -- formatting of list under each number of goals
    function p.openList(frame,og)
    
    	return mw.getCurrentFrame():extensionTag{
    		name = 'templatestyles', args = { src = 'Div col/styles.css' }
    	} .. '<div class="div-col" style="column-width:25em;">' -- perhaps add "column-count:3;"" to limit max number of columns?
    end
    function p.closeList(frame)
       return '</div>'
    end
    function p.firstToUpper(str)
        return (str:gsub("^%l", string.upper))
    end
    
    -- handles parameters bold, further, extra
    function p.addAdditionHeaderText(text, dateUpdated)
        if g.args['inlineref'] then
        	text = text .. g.args['inlineref']
        end
        if g.args['bold'] and g.args['bold']~='no' then
        	text = text .. " Players highlighted in '''bold''' are still active in the competition."
        end
        if g.args['further'] then
        	if text ~= "" then text = text .. " " end
        	text = text .. g.args['further']
        end
        if g.args['extra'] then
        	text = text .. "\n\n" .. g.args['extra']
        end
        return text
    end
    -- count number of goals for data in template
    function p.countGoals(list, number, totalGoals)
    
        local split = mw.text.split( list, "\n", true )  -- split the list for number of goals scorers with N goals
        local count = #split  * math.abs(number)         -- calculate number of goals (including own goals)
        totalGoals = totalGoals + count
       
        --mw.addWarning( "Entry: " .. list  .. "[" .. count .. "]")
    
    	return totalGoals 
    end
    
    --[[ use data supplied by template 
    ]]
    
    --function p.list(frame)
    function p.useTemplateData(frame)
        --getArgs(frame)
        
        --[[ {{{#if:{{{assists|}}}||There 
                      {{#if:{{{ongoing|}}}|{{#ifexpr:{{{goals}}}=1|has|have}} been
                      |{{#ifexpr:{{{goals}}}=1|was|were}}}} {{{goals}}} 
                      {{#ifexpr:{{{goals}}}=1|goal|goals}} scored{{#if:{{{players|}}}|&nbsp;by {{{players}}} 
                      {{#ifexpr:{{{players}}}=1|player|different players}}
                      {{#if:{{{own goals|}}}|&nbsp;(with {{{own goals}}} of them credited as {{#ifexpr:{{{own goals}}}=1|an own goal|own goals}})|}}|}} in {{{matches}}} 
                      {{#ifexpr:{{{matches}}}=1|match|matches}}, for an average of {{#expr:{{{goals}}}/{{{matches}}} round 2}} 
                      {{#ifexpr:({{{goals}}}/{{{matches}}} round 2)=1|goal|goals}} per match
                      {{#if:{{{updated|}}}|&nbsp;(as of {{{updated}}})}}.}}{{#if:{{{bold|}}}|{{#if:{{{assists|}}}||&nbsp;}}
                      Players highlighted in '''bold''' are still active in the competition.
                      |}}{{#if:{{{further|}}}|{{#if:{{{assists|}}}||&nbsp;}}{{{further}}}|}}
                      {{#if:{{{extra|}}}|{{{extra}}}{{clear}}|}}
        --]]
        local statNumber = g.args['goals'] or g.args['assists'] or 0
        local matches = g.args['matches']
        local statType = "goal"
        if g.args['assists'] then statType = "assist" end
        if g.args['clean sheets'] then statType = "clean sheet" end
        local ongoing = g.args['ongoing']
        local text1 = "There"
        if g.args['lc'] then text1 = "there" end  
        local text2 = "were"
        if ongoing then text2 = "have been" end  
        local updateString = ""
        local averageString = ""
        local goalPlural = "s"                                                                    -- goal(s)
        if g.args['goals'] and tonumber(g.args['goals']) == 1 then 
        	goalPlural = ""
        	text2 = "was"
        	if ongoing then text2 = "has been" end  
        end
        local matchPlural = "es"                                                                     -- match(es)
        if g.args['matches'] and tonumber(g.args['matches']) == 1 then matchPlural = ""   end
        	
        	
        -- auto version: string.format(" in %d match%s, for an average of %."..precision.."g goal%s per match", matches, pluralMatches, average, pluralAverage)
        if g.args['goals'] and g.args['matches'] then
        	local averageGoals = g.args['goals']/g.args['matches']
        	local avGoalPlural = "s"
        	if averageGoals == 1 then avGoalPlural = ""  end
        	averageString = string.format(" in %d match%s, for an average of %.3g goal%s per match", g.args['matches'], matchPlural, averageGoals, avGoalPlural)
        end    
        if g.args['updated'] and g.args['updated'] ~= "complete" then
        	updateString = "&nbsp;(as of " ..g.args['updated'] .. ")"
        end
        local sep = "."
        if g.args['sep'] then sep = g.args['sep'] end
        local text = ""
        if g.args['goals'] then
        	text = string.format("%s %s %d %s%s scored%s", 
        	                     text1, text2, statNumber, statType, goalPlural, averageString..updateString..sep)
        end
        text = p.addAdditionHeaderText(text)  -- handles template parameters bold, further, extra
        
        --[[   {{#if:{{{30 goals|{{{30 assists|}}}}}}|'''30 {{#if:{{{assists|}}}|assists|goals}}'''
                     <div class="div-col columns column-count column-count-3" style="column-count:3;">
                     {{#if:{{{assists|}}}|{{{30 assists}}}|{{{30 goals}}}}}</div>|}}]]
        local output = "\n"
        local number = 30
       
        local totalGoals = 0
        
        while number > -4 do                   -- for the each goals/assists
        	
           local entry = g.args[number .. ' goals'] or g.args[number .. ' goal']
                           or g.args[number .. ' assists'] or g.args[number .. ' assist']
                           or g.args[number .. ' clean sheets'] or g.args[number .. ' clean sheet']
                         
           if number < 0 then  
           	  entry = g.args[math.abs(number) .. ' own goals'] or g.args[math.abs(number) .. ' own goal']
           	  statType = "own goal"
           end
           local plural = "s"
           if number == 1 or number == -1 then plural = "" end
    			
           if entry then                                    -- do we have goals/assists for this number
    
        	 output = output .. "\n'''" .. tostring(math.abs(number)) .. " " .. statType .. plural .. "'''\n" 
        	                 .. p.openList(frame) .. "\n" .. entry .. p.closeList(frame)
        	 totalGoals = p.countGoals(entry, number, totalGoals)
           end
           
           number = number -1
        end
        
        if statType == "goal" or statType == "own goal" then
        	if g.args['goals'] and totalGoals ~= tonumber(g.args['goals']) then 
        	    mw.addWarning("WARNING. Mismatch between number of goals listed (" .. totalGoals .. ") and goals parameter (" .. g.args['goals']  .. ").")
        	end
        end
        
        --{{#if:{{{bottom|}}}|{{small|{{{bottom_text}}}}} <div class="div-col columns column-count column-count-3" style="column-count:3;"> {{{bottom}}}</div>|}}{{#if:{{{source|}}}|{{smaller|Source: {{{source}}}}}|}}
        local footerText = g.args['footer-text']  or g.args['bottom'] or ""
        local footerHeading = g.args['footer-heading'] or  g.args['bottom-text'] or ""
        local footer = ""
        if footerText ~= "" then
        	local heading = ""
        	if footerHeading ~= "" then
        		heading = '<p>' .. footerHeading .. '</p>'
        	end
        	footer =  '\n' ..  heading  .. p.openList(frame)  .. '\n' .. footerText .. p.closeList(frame)
        end
        
        
        --{{#if:{{{source|}}}|{{small|Source: {{{source}}}}}|}}
        local source = g.args['source'] or ""
        if source ~= "" then source = "<small>Source: " .. source .. "</small>" end
        
        return text .. output .. footer .. source
    end
    return p