Bước tới nội dung

Mô đun:Goalscorers

Bách khoa toàn thư mở Wikipedia
require('strict');local yesno = require('Module:Yesno')local p = {} local g = {}         -- for parameters with global scope in this moduleg.goalscorers = {}   -- table where selected and sorted players will be placeg.args = {}g.totalGoals = 0local 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>';	endend-- 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'] endend--[[ ############################## 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    endfunction 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 outputStringendfunction p.addIntroductorySentence()          -- add introductory text		local totalGoalString = "Tổng cộng có " .. g.totalGoals .. " bàn thắng đã ghi được."	--[Đang|Đang|Đã|Đã] có #GOALS bàn thắng ghi được trong #MATCHES trận đấu, trung bình #GOALS/#MATCHES bàn thắng mỗi trận đấu.		local matches, dateUpdated = p.getNumberMatches()	local mdyFormat = yesno(g.args['dmy'])		local Date = require('Module:Date')._Date		local pluralGoals = ""	local text1 = ""	if g.totalGoals == 1 then		pluralGoals = ""		if dateUpdated == 'complete' then text1 = "Đã" else text1 = "Đang" end	else		if dateUpdated == 'complete' then text1 = "Đã" else text1 = "Đang" end	end	local text = string.format("%s có %s bàn thắng%s ghi được", text1, mw.getLanguage('vi'):formatNum(g.totalGoals), pluralGoals)		local pluralMatches = ""	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 = ""		if  tonumber(string.format("%.2f",average))==1 then pluralAverage = "" end	    text = text .. string.format(" trong %d trận đấu%s, trung bình %."..precision.."g bàn thắng%s mỗi trận đấu", 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 = "dmy" else			if mdyFormat == false then dateFormat = "dmy" end   -- template param overrides		end		local lang = mw.language.getContentLanguage()	    text = text .. " (tính đến ngày " .. lang:formatDate('j "tháng" n "năm" Y', Date(dateUpdated):text(dateFormat)) .. ")."	end	text = p.addAdditionHeaderText(text, dateUpdated)  -- handles template parameters bold, further, extra	return text --totalGoalString endfunction 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 footerSentenceendfunction 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, dateUpdatedendfunction 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 outputStringendfunction 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    endfunction 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 validateRoundend--[[ ############################## 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, groupend--[[  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)    endend--[[ 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 "không tìm thấy bảng"    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 .. " Nhập bàn thắng không hợp lệ cho cầu thủ " .. player		return 0, ""	endendfunction 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)endfunction 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 .. " Nhập tên không hợp lệ cho cầu thủ " .. u[1] .. ", " .. u[2] 			return "", ""     --TODO errroer		end	elseif type(u) == 'string' then		return u, ""                 -- return player name	else		p.errorString = p.errorString .. " Nhập tên không hợp lệ cho cầu thủ " .. u or u[1] or "chưa biết"		return "", ""	endend--[[ ############################## 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 alphabeticallyfunction 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 = "trong trận gặp "                    -- 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	endfunction 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	endend--[[ 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)endfunction   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!Hạng !! Cầu thủ !! Bàn thắng'                          -- 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 .. " cầu thủ"		        	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 ("Không có bàn thắng nào khớp với tiêu chí được yêu cầu.")	end		endfunction   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 = " bàn"    		--if og == "OG" then 	    		if goalNumber < 0 then    			goalString = goalString .. " phản lưới nhà"    		end    		if  math.abs(u['goals']) ~= 1 then goalString = goalString .. "" 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 ("Không có bàn thắng nào khớp với tiêu chí được yêu cầu.")	endend-- output icon linked to national team pagefunction 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    endend-- formatting of list under each number of goalsfunction 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?endfunction p.closeList(frame)   return '</div>'endfunction p.firstToUpper(str)    return (str:gsub("^%l", string.upper))end-- handles parameters bold, further, extrafunction 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 .. " Các cầu thủ được thể hiện bằng chữ '''in đậm''' vẫn đang thi đấu tại giải."    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 textend-- count number of goals for data in templatefunction 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( "Nhập: " .. list  .. "[" .. count .. "]")	return totalGoals end--[[ use data supplied by template ]]--function p.list(frame)function p.useTemplateData(frame)    --getArgs(frame)        --[[ {{{#if:{{{assists|}}}||                  {{#if:{{{ongoing|}}}|{{#ifexpr:{{{goals}}}=1|Đang|Đang}}                  |{{#ifexpr:{{{goals}}}=1|Đã|Đã}}}} {{{goals}}}                   {{#ifexpr:{{{goals}}}=1|bàn thắng|bàn thắng}} ghi được{{#if:{{{players|}}}|&nbsp;bởi {{{players}}}                   {{#ifexpr:{{{players}}}=1|cầu thủ|cầu thủ khác nhau}}                  {{#if:{{{own goals|}}}|&nbsp;(với {{{own goals}}} trong số đó được ghi nhận là {{#ifexpr:{{{own goals}}}=1|bàn phản lưới nhà|bàn phản lưới nhà}})|}}|}} trong {{{matches}}}                   {{#ifexpr:{{{matches}}}=1|trận đấu|trận đấu}}, trung bình {{#expr:{{{goals}}}/{{{matches}}} round 2}}                   {{#ifexpr:({{{goals}}}/{{{matches}}} round 2)=1|bàn thắng|bàn thắng}} mỗi trận đấu                  {{#if:{{{updated|}}}|&nbsp;(tính đến ngày {{{updated}}})}}.}}{{#if:{{{bold|}}}|{{#if:{{{assists|}}}||&nbsp;}}                  Các cầu thủ được thể hiện bằng '''chữ đậm''' vẫn đang thi đấu ở giải.                  |}}{{#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 = "bàn thắng"    if g.args['assists'] then statType = "kiến tạo" end    if g.args['clean sheets'] then statType = "giữ sạch lưới" end    local ongoing = g.args['ongoing']    local text1 = ""    if g.args['lc'] then text1 = "" end      local text2 = "Đã"    if ongoing then text2 = "Đang" end      local updateString = ""    local averageString = ""    local goalPlural = ""                                                                    -- goal(s)    if g.args['goals'] and tonumber(g.args['goals']) == 1 then     	goalPlural = ""    	text2 = "Đã"    	if ongoing then text2 = "Đang" end      end    local matchPlural = ""                                                                     -- match(es)    if g.args['matches'] and tonumber(g.args['matches']) == 1 then matchPlural = ""   end    	    	    -- auto version: string.format(" trong %d trận đấu%s, trung bình %."..precision.."g bàn thắng%s mỗi trận đấu", matches, pluralMatches, average, pluralAverage)    if g.args['goals'] and g.args['matches'] then    	local averageGoals = g.args['goals']/g.args['matches']    	local avGoalPlural = ""    	if averageGoals == 1 then avGoalPlural = ""  end    	averageString = string.format(" trong %d trận đấu%s, trung bình %.3g bàn thắng%s mỗi trận đấu", g.args['matches'], matchPlural, averageGoals, avGoalPlural)    end        if g.args['updated'] and g.args['updated'] ~= "complete" then    	updateString = "&nbsp;(tính đến ngày " ..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 có %d %s%s ghi được%s",     	                     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|}}}|kiến tạo|bàn thắng}}'''                 <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 = "bàn phản lưới nhà"       end       local plural = ""       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 == "bàn thắng" or statType == "bàn phản lưới nhà" then    	if g.args['goals'] and totalGoals ~= tonumber(g.args['goals']) then     	    mw.addWarning("CẢNH BÁO. Không khớp giữa số bàn thắng được liệt kê (" .. totalGoals .. ") và tham số goals (" .. 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|Nguồn: {{{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|Nguồn: {{{source}}}}}|}}    local source = g.args['source'] or ""    if source ~= "" then source = "<small>Nguồn: " .. source .. "</small>" end        return text .. output .. footer .. sourceendreturn p