Module:Cycling race

Fonctions :


local p = {}
local wiki = string.match(mw.site.server, "%a+")
if wiki == "www" then
	wiki = "fr"
end
--import translation
local l10n = mw.loadData("Module:Cycling race/l10n")

--import data
local data = mw.loadData("Module:Cycling race/data")

local contentLanguage = mw.getContentLanguage()
local wikilang = contentLanguage:getCode()
local wikibase = mw.wikibase

-- == Structure of the code ==
-- I) Constant
-- II) Translation
-- III) Basic functions
-- IV) Functions less basic called from other functions
-----A) Time functions
-----B) Link functions
-----C) Functions for the output, like table
-----D) Jersey, flag functions
-----E) Other (winner)
-- V) Main functions
----- A) Function race reference
----- B) Calendar
----- C) Victory
----- Cbis) Function for infobox
----- D) Stage infobox
----- E) List of teams
----- F) Classifications
----- G) Infobox
----- H) Race infobox
----- I) Team roster
----- J) Function list of winners (palmarès)
----- K) List of stages
----- L) List of stages classification
----- M) Start list
----- N) Rider ranking
----- O) Rider infobox
----- P) Team infobox
-- ..................
----- Z) Miscellaneous / Other / Tests 

--Tip: search "--==" to navigate between the sections

--== I) Classes declared as global ==
local textalign = "left"
local floattable = "left"
local floatinfobox = "right"
if wiki == "ar" or wiki == "fa" or wiki == "ur" or wiki == "he" then
	textalign = "right"
	floattable = "right"
	floatinfobox = "left"
end

local Wikidatalogosize = "12px"
if wiki == "ar" then Wikidatalogosize = "15px" end
local standardtablecss=data.standardtablecss_part1..textalign..data.standardtablecss_part2

local lang_priority --for lang priority and fallback
if l10n["lang_priority"] then
	lang_priority=l10n["lang_priority"]
else --default
	lang_priority={}
	table.insert(lang_priority,wikilang)
	for _, lang in ipairs({'mul','en', 'fr', 'de','es','nl','it','da'}) do
		if lang~=wikilang then
			table.insert(lang_priority,lang)
		end
	end
end

--"country" means here, that there will be a separated column containing the country name
--otherwise a flag is typically added in another column, for instance before the rider name
local no_country_calendar={'ru','ar'}
local no_country_victories={'ru','ar','da'}
local no_country_classification={'es','da','no','ru','ar'}

--to avoid wrong display, or country names becoming very long,
--available_list==false --> country=false in the old code,
--should be implemented here
if not l10n["country_name_list"] then
	table.insert(no_country_calendar, wiki)
	table.insert(no_country_victories, wiki)
	table.insert(no_country_classification, wiki)
end

--Note about WDlink_on
--On some wikipedia small wikidata flag are displayed after all data coming from wikidata
--to enable that set WDlink_on on true

local no_roll_startlist={'fr','da','no','ar','ru','de'}
local display_language_in_riderinfobox={'ru'}
local display_flag_in_riderinfobox={'ru'}
local display_birthnameastitle_in_riderinfobox={'ru'}
local display_noweight_in_riderinfobox={'fr','pl'}
local display_noage_in_riderinfobox={'pl'}
local display_nonickname_in_riderinfobox={'pl'}
local display_cm_in_riderinfobox={'pl'}

local silver_theme_countries={'da', 'pl'}

local backgroundColor="#FFDF80"
local backgroundColorLight="#FFF7DF"
for _, value in pairs(silver_theme_countries) do -- get data if country should be printed in this wiki
	if value == wiki then 
		backgroundColor="var(--background-color-neutral, #eaecf0)" 
		backgroundColorLight="var(--background-color-neutral-subtle, #f8f9fa)"
	end
end

local dark_mode_countries={'ca', 'pl'}
local picto_track=" [[File:Cycling (track) pictogram.svg|35px]]"
local picto_road=" [[File:Cycling (road) pictogram.svg|35px]]" 

for _, value in pairs(dark_mode_countries) do 
	if value == wiki then 
		picto_track=" [[File:Cycling (track) pictogram.svg|35px|class=skin-invert]]"
		picto_road=" [[File:Cycling (road) pictogram.svg|35px|class=skin-invert]]" 
	end
end

local function istrue(x)
    if x and (x == 1 or x == "1" or x == "true") then return true end
    return nil
end

--== II) Translation ==
local function translate(func_name_short, index, w_race, title)
	if index==1000 then --code for some custom function
		return title
	else
		if func_name_short then
			local func_name
			if w_race then
				func_name=func_name_short.."_women_translate"
				if l10n[func_name] and l10n[func_name][index] then 
					return l10n[func_name][index]
				end
			end
			func_name=func_name_short.."_translate"
			if l10n[func_name][index] then 
				return l10n[func_name][index]
			end
			return "translation for "..func_name.." index ".. tostring(index).." not found"
		else 
			error('func_name found')
		end
	end
end

local function plural(num)
	local plural=false --latin language
	local gen_singular=false --for slavic language
	local gen_plural=false --for slavic language
	if num then
		if num > 1 then
			plural=true
			if num < 5 then -- 2, 3 and 4
				gen_singular = true
			elseif num > 20 then
				local modulo = math.fmod( num, 10)
				--modulo==1 --> nothing, it is singular
				if modulo>1 and modulo<5 then
					gen_singular = true
				elseif modulo>4 then
					gen_plural=true
				end
			else
				gen_plural=true
			end
		end
	end
	
	return plural, gen_singular, gen_plural
end

local function black_list( Label)
	local black_list=l10n.black_list
	--[[ List of Wikipedia articles with the same lemma as the non existing rider article. Those lemmas are printed
		as text "black" in the tables, not "blue" or "red". This way there will be no false wikilinks at the WhatLinksHere entry.
		List should be updated maybe once a year. ]]
	return black_list[Label]
end

local function country_name_from_list(countryID)
	if l10n["country_name_list"] and l10n["country_name_list"][countryID] then
		return l10n["country_name_list"][countryID]
	end
	return nil
end

local function stageLink(x, a, b) -- x= 10a: a = 10, b = a. x = 5: a = 5, b = ""
	local word1 
	local word2=translate("func_prologue",2) --stage
	local word=word2

	if wiki=="ar" then return word2 .. " " .. ( a or "" ) , "#" .. word2 .. " " .. ( a or "" ) end

-- fr: {{1re}} étape, {{2e}} étape
	if wiki=="fr" then
		if b == "" then -- series_ordinal without character
			if a == "1" then word1 = "1<sup>re</sup> "..word else word1 = a.."<sup>e</sup> "..word end -- table text = {{1re}} étape, {{2ae}} étape,
			if a == "1" then word2 = "#1re "..word else word2 = "#"..a.."e  "..word end --text of section header = #1re étape, #2e étape
			return word1, word2
		end
		if b ~= "" then -- series_ordinal with character: instead of eg "1a re" it is "1re a"
			if a == "1" then word1 = "1<sup>re</sup> "..b.." "..word else word1 = a.."<sup>e</sup> "..b.." "..word end -- table text = {{1re}} étape, {{2ae}} étape,
			if a == "1" then word2 = "#1re "..b.." "..word else word2 = "#"..a.."e"..b.." "..word end --text of section header = #1re étape, #2e étape
			return word1, word2
		end
	end
	if wiki=="hu" then
		if b == "" then return a..". "..word, "#"..a..". "..word
		else return a..b.." "..word, "#"..a..b.." "..word end
	end
	if wiki=="de" or wiki=="da" or wiki=="fo" or wiki=="lb" or wiki=="no" then return a..". "..b.." "..word, "#"..a..". "..b.." "..word end
	if wiki=="ca" then return a.."a "..b.." "..word, "#"..a..". "..b.." "..word end
	if wiki=="es" then return a..".ª "..word.." "..b, "#"..a..".ª "..word.." "..b end
	if wiki=="ast" then
		if b == "" then -- series_ordinal without character
			if a == "1" or a == "3" then word1 = a.."ᵉʳ "..word else word1 = a.."ª "..word end -- table text = 1ᵉʳ etapa, 2ª etapa, 3ᵉʳ etapa,
			if a == "1" or a == "3" then word2 = "#"..a.."ᵉʳ "..word else word2 = "#"..a.."ª  "..word end --text of section header = #1ᵉʳ etapa, #2ª etapa, #3ᵉʳ etapa
			return word1, word2
		end
		if b ~= "" then -- series_ordinal with character: instead of eg "1a re" it is "1re a"
			if a == "1" or a == "3" then word1 = a.."ᵉʳ "..b.." "..word else word1 = a.."ª "..b.." "..word end -- table text = {{1ᵉʳ}} etapa, {{2ª}} etapa,
			if a == "1" or a == "3" then word2 = "#"..a.."ᵉʳ "..b.." "..word else word2 = "#"..a.."ª"..b.." "..word end --text of section header = #1ᵉʳ etapa, #2ª etapa
			return word1, word2
		end
	end

	-- default
	word1 = x                  -- table text = 1, 2a, 3
	word2 = "#"..word.." ".. x -- text of section header = #Etappe 2a, #Stage 4
	return word1, word2
end

local function typeofstage(x, typ, noborder)
	-- plain, hilly, inter, ... must be "" or "any text"
	-- l10nDef[""] = {plain = "", hilly="", inter='', mount='', time_prologue='', time_team='', time_indiv='', uphill='', rest=''}
	local l10n=l10n["type_of_stage_translate"]

	local border
	if noborder then border="" else border="|border|right" end
    local stages = {
        ["plain stage"] = "[[File:Plainstage.svg"..border.."|20px|"..l10n.plain.."]]",
        ["hilly stage"] = "[[File:Hillystage.svg"..border.."|20px|"..l10n.hilly.."]]",
        ["intermediate stage"] = "[[File:Mediummountainstage.svg"..border.."|20px|"..l10n.inter.."]]",
        ["mountain stage"] = "[[File:Mountainstage.svg"..border.."|20px|"..l10n.mount.."]]",
        ["uphill time trial stage"] = "[[File:Mountain Time Trial Stage.svg"..border.."|20px|"..l10n.uphill.."]]",
        ["rest day"] = "[[File:Stage rest day.svg"..border.."|20px|"..l10n.rest.."]]"
    }
	if stages[x] then
		return stages[x]
	end
	if x=='time trial stage' then
		if noborder then border="" else border="|right" end
		local stages2 = {
			["Q2348250"] = "[[File:Team Time Trial Stage.svg"..border.."|20px|"..l10n.time_team.."]]",
			["Q2266066"] = "[[File:Time Trial.svg"..border.."|20px|"..l10n.time_indiv.."]]",
			["Q485321"] = "[[File:Time Trial.svg"..border.."|20px|"..l10n.time_prologue.."]]"
		}
		if stages2[typ] then
			return stages2[typ]
		end
	end
end

local function typeofstagelogo(stageID, noborder)
	local sType
	p = mw.wikibase.getBestStatements(stageID, 'P31') -- P31 is 'instance of'
	local stages = {
		["Q20646667"] = {"plain stage", nil},
		["Q20646670"] = {"hilly stage", nil},
		["Q20680270"] = {"intermediate stage", nil},
		["Q20646668"] = {"mountain stage", nil},
		["Q485321"] = {"time trial stage", "Q485321"}, -- prologue
		["Q2266066"] = {"time trial stage", "Q2266066"}, -- individual time trial
		["Q2348250"] = {"time trial stage", "Q2348250"}, -- team time trial
		["Q20679712"] = {"uphill time trial stage", nil}
	}
	for _, t in pairs(p) do
		if t.mainsnak.snaktype == 'value' then
			local iOf = t.mainsnak.datavalue.value.id
			if stages[iOf] then
				sType = typeofstage(stages[iOf][1], stages[iOf][2], noborder)
				break
			end
		end
	end
	return sType or ''
end

--== III) basic functions
--[[ Get any value for a property which is not deprecated ]]
local function firstValue(QID, PID, field)
	if QID then
		local ss = wikibase.getAllStatements(QID, PID)
		for _, s in pairs(ss) do
			if s.rank ~= 'deprecated' and s.mainsnak.snaktype == 'value' then
				return field and s.mainsnak.datavalue.value[field] or s.mainsnak.datavalue.value
			end
		end
	else
		return nil
	end
end

--[[ Go from season of a team to the team ]]
local function getParentID(teamID)
	return firstValue(teamID, 'P5138', 'id') -- P361 is 'part of'
		or firstValue(teamID, 'P361', 'id') -- P5138 is 'season of club or team'
end

--[[ Get a label in any of the languages in the fallback list of language codes ]]
local function getLabelFallback(itemID, fallback)
	local label
	if fallback==nil then --default
		fallback=lang_priority
	end
	for _, lang in ipairs(fallback) do
		label = mw.wikibase.getLabelByLang(itemID, lang)
		if label then break end
	end
	return label
end

--[[ Get a sitelink from the local wiki or from the fallback list of language codes ]]
local function getSitelinkFallback(itemID, fallback)
	local link = mw.wikibase.getSitelink(itemID)
	if link then return link end
	for _, lang in ipairs(fallback) do
		link = mw.wikibase.getSitelink(itemID, lang .. 'wiki')
		if link then return link end
	end
	return nil
end

local arwiki_totemplate = mw.getCurrentFrame():getParent().args["totemplate"] or mw.getCurrentFrame().args["totemplate"]
arwiki_totemplate = (wiki == "ar" and arwiki_totemplate and arwiki_totemplate ~= "") or false

local function get_lf(frame)
	local lf = frame
	if string.match(frame:getParent():getTitle(), '%P+') == mw.site.namespaces.Template.name then
		lf = frame:getParent()
	end
	return lf
end

local function get_and_checkID(frame)
	local lf = get_lf(frame)
	local entityID = mw.text.trim(lf.args[1])
	entityID= string.gsub(entityID, "%c", "") --probably redundant
	if type(entityID) ~= 'string' then error('parameter must be a string') end
	if not entityID:match('Q%d+') then error('parameter must be a valid Wikidata item (ex: Q42)') end
	return entityID, lf
end

local function make_IllWD2_link(q, arlabel, enlabel, text)
	local argse = { ["المعرف"] = q, target='en' }
	if arlabel and arlabel ~= '' then 
		argse.label = arlabel
	elseif enlabel and enlabel ~= '' then
		argse.enlabel = enlabel
	end	
	if text and text ~= "" then
		argse.text = text 
	end
	local final = mw.getCurrentFrame():expandTemplate{ title = 'Ill-WD2', args = argse }
	if arwiki_totemplate then
		final = "{{Ill-WD2"
		for k,v in pairs(argse) do
            final = final .. "|" .. k .. "=" .. v
        end
        final = final .. "}}"
    end
	return final
end

local function change_listofstages(tab, raceID, header, Id)
	-- code used in arwiki only
	return tab
end

--[[ Iterator to get all statements for an entity and property which are not deprecated and have a value]]
local function nextStatement(state, i)
	repeat
		i = i + 1
		local s = state[i]
		if s and s.rank ~= 'deprecated' and s.mainsnak.snaktype == 'value' then
			return i, s
		end
	until s == nil
end
local function statements(QID, PID)
	return nextStatement, wikibase.getAllStatements(QID, PID), 0
end

--[[ Iterator to get all qualifier values for a property for a statement]]
local function nextQualifier(state, i)
	repeat
		i = i + 1
		local q = state[i]
		if q and q.snaktype == 'value' then
			return i, q.datavalue
		end
	until q == nil
end
local function qualifiers(statement, PID)
	return nextQualifier, statement.qualifiers and statement.qualifiers[PID] or {}, 0
end

local function qualifieramount(element, property)
	local result
	for _, q in qualifiers(element, property) do
		result = tonumber(q.value.amount)
		break
	end
	return result
end

local function dispmoney(amount, unit)
	if amount and unit then
		local cost = contentLanguage:formatNum(tonumber(amount))
		if wiki == 'fo' then cost = string.gsub(cost, "%.", ",") end
		if unit == "http://www.wikidata.org/entity/Q4916" then 
			cost = cost .. ' €'
		elseif unit == "http://www.wikidata.org/entity/Q4917" then 
			cost = cost .. ' $'
		end
		return cost
	end
	return nil
end

--== IV) Functions less basic called from other functions ==
--=== A) Time functions ===
--[[ Get a Wikidata statement for an entity and property valid at the given timevalue ]]
local function checktime(s,q, time)
	local start, startPrecision, END, endPrecision, timePrecision
	if not q or not time then
		return s
	end
	local _, _, _, m, _ = string.find(time, "(%d+)%p(%d+)%p(%d+)")
	if m=="00" then
		timePrecision=9
	end
	if q.P580 and q.P580[1] and q.P580[1].snaktype == 'value' then -- P580 is start time
		start = q.P580[1].datavalue.value.time
		startPrecision = q.P580[1].datavalue.value.precision
		if startPrecision == 9 or timePrecision==9 then -- precision is years
			start = string.sub(start, 1, 5) -- Cut of everything after year
		elseif startPrecision == 10 then -- precision is months
			start = string.sub(start, 1, 8) -- Cut of everything after month
		end
	end
	if q.P582 and q.P582[1] and q.P582[1].snaktype == 'value' then -- P582 is end time
		END = q.P582[1].datavalue.value.time
		endPrecision = q.P582[1].datavalue.value.precision
	end
	if not start or start <= time then
		if not END then
			return s
		end
		if endPrecision == 9 or timePrecision==9 then -- precision 9 is 'years'
			END = string.sub(END, 1, 6) .. '13' -- Set month to 13
		elseif endPrecision == 10 then -- precision 10 is 'months'
			END = string.sub(END, 1, 9) .. '32' -- Set day to 32
		end
		if END >= time then
			return s
		end
	end
	return nil
end

local function getStatementForTime(ID, property, time)
	local temp
	for _, s in statements(ID, property) do
		temp =checktime(s, s.qualifiers, time)
		if temp then return temp end
	end
	return nil
end

--Display date interval in a natural way: 
--long:
--4-5 January 2020 
--4 January - 2 February 2020
--4 January 2020 - 2 February 2021
--small is the same with short month names

--Does not work properly if the precision is not sufficient
local function getStartEndTime(sTime, eTime, mode)
	-- Note: Add the 4formats to "formats" and use funcDate
	local lang = contentLanguage
	local starttime, endtime
	
	--local format = formats[wiki] or formats['']
	if mode==nil then mode='long' end
	-- Timevalues is like "+2015-07-04T00:00:00Z"
	local y, m = string.match(sTime, "(%d+)-(%d+)-%d+")
	local y2, m2 = string.match(eTime, "(%d+)-(%d+)-%d+")
	
	if m=='00' then --manage the 30 November issue
		if  mode=='long' or mode=="verylong" then
			starttime =lang:formatDate( "Y", sTime )
		else
			starttime ='-'
		end
	else
		if y ~= y2 then
			if mode=='long' or mode=="verylong" then
				starttime = lang:formatDate( "j F Y", sTime )
			else
				starttime = lang:formatDate( "j M Y", sTime )
			end
		elseif m ~= m2 then
			if mode=='long' or mode=="verylong" then
				starttime = lang:formatDate( "j F", sTime )
			else
				starttime = lang:formatDate( "j M", sTime )
			end
		else
			starttime = lang:formatDate( "j", sTime )
		end
	
		if wiki == "ar" then
			if y ~= y2 then starttime = lang:formatDate( "d F Y", sTime )
			elseif m ~= m2 then starttime = lang:formatDate( "d F", sTime )
			else starttime = lang:formatDate( "d ", sTime ) end
		elseif wiki == "br" then
			if y ~= y2 then starttime = lang:formatDate( "j", sTime ) .." a viz ".. lang:formatDate( "F Y", sTime )
			elseif m ~= m2 then starttime = lang:formatDate( "j", sTime ) .." a viz ".. lang:formatDate( "F", sTime )
			else starttime = lang:formatDate( "j", sTime ) .." "
			end
		elseif wiki == "ca" or wiki == "es" or wiki == "ast" then
			if y ~= y2 then
				starttime = lang:formatDate( "j", sTime ) .." de ".. lang:formatDate( "F", sTime ) .." de ".. lang:formatDate( "Y", sTime )
			elseif m ~= m2 then
				starttime = lang:formatDate( "j", sTime ) .." de ".. lang:formatDate( "F", sTime )
			else starttime = lang:formatDate( "j", sTime ) .." "
			end
		elseif wiki == "cs" then
			if y ~= y2 then starttime = lang:formatDate( "j. xg Y", sTime )
			elseif m ~= m2 then starttime = lang:formatDate( "j. xg", sTime )
			else starttime = lang:formatDate( "j", sTime )
			end
		elseif wiki == "de" or wiki == "da" or wiki == "fo" or wiki == "lb" or wiki == "no" then
			if y ~= y2 then starttime = lang:formatDate( "j. F Y", sTime )
			elseif m ~= m2 then starttime = lang:formatDate( "j. F", sTime )
			else starttime = lang:formatDate( "j.", sTime )
			end
		elseif wiki == "fi" then
			if y ~= y2 then starttime = lang:formatDate( 'j. F"ta" Y', sTime )
			elseif m ~= m2 then starttime = lang:formatDate( 'j. F"ta"', sTime )
			else starttime = lang:formatDate( "j.", sTime )
			end
		elseif wiki == "eo" then
			if y ~= y2 then starttime = lang:formatDate( "j", sTime ) .."-a de ".. lang:formatDate( "F Y", sTime )
			elseif m ~= m2 then starttime = lang:formatDate( "j", sTime ) .."-a de ".. lang:formatDate( "F", sTime )
			else starttime = lang:formatDate( "j", sTime ) .."-a "
			end
		elseif wiki == "eu" then
			if y ~= y2 then starttime = lang:formatDate( "Y", sTime ) ..".eko ".. lang:formatDate( "F", sTime ) .."k ".. lang:formatDate( "j", sTime )
			elseif m ~= m2 then starttime = lang:formatDate( "F", sTime ) .."k ".. lang:formatDate( "j", sTime )
			else starttime = lang:formatDate( "F", sTime ) .."k ".. lang:formatDate( "j", sTime )
			end
		elseif wiki == "hu" then
			starttime = lang:formatDate( "Y. F j.", sTime)
		elseif wiki == "ja" then
			if y ~= y2 then starttime = lang:formatDate( "Y年m月d日", sTime )
			elseif m ~= m2 then starttime = lang:formatDate( "Y年m月d日", sTime )
			else starttime = lang:formatDate( "Y年m月d日", sTime )
			end
		elseif wiki == "lv" then
			if m ~= m2 then starttime = lang:formatDate( "Y. \\g\\a\\d\\a j. F", sTime )
			else starttime = lang:formatDate( "Y. \\g\\a\\d\\a j.", sTime )
			end
		elseif wiki == "pl" then
			if y ~= y2 then starttime = lang:formatDate( "j xg Y", sTime )
			elseif m ~= m2 then starttime = lang:formatDate( "j xg", sTime )
			else starttime = lang:formatDate( "j", sTime )
			end
		end
	end
	
	if m2=='00' then --manage the 30 November issue
		if  mode=='long' or mode=="verylong" then
			endtime= lang:formatDate( "Y", eTime )
		else
			endtime= '-'
		end
	else
		if (mode=='long' and y ~= y2) or mode=="verylong" then
			endtime = lang:formatDate("j F Y", eTime)
		elseif y ~= y2 then --small
			endtime = lang:formatDate("j M Y", eTime)
		elseif mode=='long' then
			endtime = lang:formatDate("j F", eTime)
		else
			endtime = lang:formatDate("j M", eTime)	
		end
		if wiki == "ar" then
			if mode=='long' or mode=="verylong" or y ~= y2 then endtime = lang:formatDate( "d F Y", eTime )
			elseif m ~= m2 then endtime = lang:formatDate( "d F Y", eTime )
			else endtime = lang:formatDate( "d F Y", eTime )
			end
		elseif wiki == "br" then endtime = lang:formatDate( "j", eTime ) .." a viz ".. lang:formatDate( "F Y", eTime )
		elseif wiki == "ca" or wiki == "es" or wiki == "ast" then
			if mode=='long' or mode=="verylong" or y ~= y2 then
				endtime = lang:formatDate( "j", eTime ) .." de "..
				lang:formatDate( "F", eTime ) .." de ".. lang:formatDate( "Y", eTime )
			else
				endtime = lang:formatDate( "j", eTime ) .." de "..
				lang:formatDate( "F", eTime )
			end
		elseif wiki == "cs" then endtime = lang:formatDate( "j. xg Y", eTime )
		elseif wiki == "de" or wiki == "da" or wiki == "fi" or wiki == "fo" or wiki == "lb" or wiki == "no" then
			if mode=='long' or mode=="verylong" or y ~= y2 then
				endtime = lang:formatDate( "j. F Y", eTime )
			else
				endtime = lang:formatDate( "j. M", eTime )
			end
		elseif wiki == "eo" then endtime = lang:formatDate( "j", eTime ) .."-a de ".. lang:formatDate( "F Y", eTime )
		elseif wiki == "eu" then endtime = lang:formatDate( "Y", eTime ) ..".eko ".. lang:formatDate( "F", eTime ) .."k "..
			lang:formatDate( "j", eTime )
		elseif wiki == "fi" then endtime = lang:formatDate('j F"ta" Y', eTime)
		elseif wiki == "hu" then
			if y ~= y2 then endtime = lang:formatDate( "Y. F j.", eTime )
			elseif m ~= m2 then endtime = lang:formatDate( "F j.", eTime )
			else endtime = lang:formatDate( "j.", eTime )
			end
			--endtime = lang:formatDate( "Y", eTime ) ..". ".. lang:formatDate( "F j", eTime ) .."."
		elseif wiki == "ja" then
			if y ~= y2 then endtime = lang:formatDate( "Y年m月d日", eTime )
			elseif m ~= m2 then endtime = lang:formatDate( "m月d日", eTime )
			else endtime = lang:formatDate( "d日", eTime )
			end
		elseif wiki == "lv" then
			if y ~= y2 then endtime = lang:formatDate( "Y. \\g\\a\\d\\a j. F", eTime )
			else endtime = lang:formatDate( "j. F", eTime )
			end
		elseif wiki == "pl" then endtime = lang:formatDate( "j xg Y", eTime )
		end
	end
	return starttime, endtime
end

local formats = data.formats 

-- Display the date, the mode changes the format
local function funcDate(date, mode)
	-- local date = '+2016-05-20'
	-- local mode = 'small'
	local format = formats[wiki] or formats['']
    local lang = contentLanguage
    
	--handle problems with lack of precision
	local dispDate = date

	if date and string.sub(date,7,8)=='00' then	-- lack of month
		dispDate= string.sub(date,1,6).."01-01"..string.sub(date,12)
		if mode == 'long' or mode == 'onlyyear' or mode == 'monthly' then
			mode = 'onlyyear'
		else
			mode = 'nodate'
		end
	elseif date and string.sub(date,10,11)=='00' then -- lack of day
		dispDate= string.sub(date,1,9).."01"..string.sub(date,12)
		if mode == 'long' then
			mode = 'monthly'
		elseif mode == 'small' then
			mode = 'onlymonth'
		elseif mode == 'onlyday' then
			mode = 'nodate'
		end
	end
	if format[mode] == nil then mode = 'nodate' end
	
	return contentLanguage:formatDate(format[mode], dispDate)
end

--[[ get the year for a race as a string, or an empty string]]
local function getYear(raceID)
	local year = firstValue(raceID, 'P580', 'time') or -- P580 is 'start time'
		firstValue(raceID, 'P585', 'time') -- P585 is 'point in time'
	if year then
		return string.sub(year, 2, 5)
	end
	return ''
end

local function isdisqualified(p,q) --disqualification can use deprecated or P1534
	local cancelled=""
	local disqualified=false
	
	if p and p.rank=='deprecated' then
		cancelled='text-decoration:line-through;'
		disqualified=true
	else
		if q and q.P1534 and q.P1534[1].snaktype == 'value' then
			local tempdsq=q.P1534[1].datavalue.value.id
			if tempdsq=='Q1229261' then 
				cancelled='text-decoration:line-through;'
				disqualified=true
			end --disqualified
		end
	end
	return cancelled, disqualified
end

--=== B) Link functions ===
local function getOfficialName(teamID, timeOfRace,season,strict) -- for team
	--return officialName, isLocal
	local strictLang = {mk = true} 
	local cyrillic = {mk = true, ru = true}
	local strictLangBool= strictLang[wiki] or strict
    local correcttime, best, name, nametemp
    local wantedLanguages = {}
    
	for i, lang in ipairs(lang_priority) do
		wantedLanguages[lang] = i
	end
    --case one, one official name / period overloaded with other languages as qualifier
    --for instance https://www.wikidata.org/wiki/Q195833
    best = 999
	for _, p1448 in statements(teamID, 'P1448') do
		correcttime=true
		if timeOfRace and timeOfRace ~='' then
			correcttime =checktime(p1448, p1448.qualifiers, timeOfRace)
		end
		if correcttime then 
			if p1448.qualifiers and p1448.qualifiers.P1448 then
				local q = p1448.qualifiers.P1448
			    best = 999
				for _, l in pairs(q) do
					if l.snaktype == 'value' then
						local lang = l.datavalue.value.language
						if wantedLanguages[lang] and wantedLanguages[lang] < best then
							best = wantedLanguages[lang]
							name = l.datavalue.value.text
						end
					end
				end
				if name then return name, true end
			end
			--p1448 and correct time, look in the not qualifier part
		
			lang=p1448.mainsnak.datavalue.value.language
			if strictLangBool then
				if wiki==lang then
					name = p1448.mainsnak.datavalue.value.text
				end
			elseif wantedLanguages[lang] and wantedLanguages[lang] < best then
				best = wantedLanguages[lang]
				name = p1448.mainsnak.datavalue.value.text
			else
				if cyrillic[lang]==nil then --don't display cyrillic for latin wiki
					nametemp = p1448.mainsnak.datavalue.value.text
				end
			end
		end
	end
    if name then 
    	return name, true
    elseif not strictLangBool and nametemp then
    	return nametemp, false
    end

    --no official name, get label
	local label=wikibase.getLabel(teamID)
	if season and season==true then
		if label then return string.sub(label,1,label:len()-5),true end -- 
	else
		return label, true -- No official name, try label
	end
end

local function revertfirstlast(name)
	local nametable = mw.text.split(name, ",")
	if nametable[2] then --there is a coma
		return nametable[2].." "..nametable[1]
	else
		return nametable[1]
	end
end

local function checksitelink(sitelink, label)
	if sitelink==label then
		return "[[" .. sitelink .."]]"
	else
		return "[[" .. sitelink .. "|" .. label.. "]]"
	end
end
-- RiderID --> RiderLink
local function getRiderLink(riderID, startOfSeason) --startOfSeason optional
	--Priority order
	--#1 P1813, short name, in correct alphabet, correct time
	--#2 P1448, official name, in correct alphabet, correct time
	--#3 sitelink (so label from wikipedia) in correct language
	--#4 label from wikidata in correct language
	--#5 label from wikidata in another language
	local strictLang = {mk = true, ru = true}
	local strictLangBool= strictLang[wiki]

	local sitelink = wikibase.getSitelink(riderID)
	local officialname,officialnametemp, language, name
	local correctlanguage=false
	local listOfProperty={'P1813','P1448'}

	for _, prop in ipairs(listOfProperty) do
		for _, p1813 in statements(riderID, prop) do
			if not officialname or not correctlanguage then
				language = p1813.mainsnak.datavalue.value.language
				officialnametemp = p1813.mainsnak.datavalue.value.text
				if strictLangBool then
					if wiki==language then
						name=officialnametemp --only exact language
						correctlanguage=true
					end
				else
					if wiki==language then --exact language --> ok
						name=officialnametemp
						correctlanguage=true
					elseif strictLang[language]==nil and not officialname then
						--normally all "latin" languages use the same name, except for cyrillic translation
						local russianLabel= wikibase.getLabelByLang(riderID, "ru")
						if russianLabel then
							local russianEnd=string.sub(russianLabel, -3)
							if russianEnd~="вна" and russianEnd~="вич" then --otherwise rejected
								name=officialnametemp 
								correctlanguage=false
							end
						else -- no russian label, it is most probably not a cyrillic translation
							name=officialnametemp --any language latin
							correctlanguage=false
						end
					end
				end
				if startOfSeason~= nil then
					local q = p1813.qualifiers
					if q then
						local temp = checktime(name,q,startOfSeason)
						if temp then officialname = name end--if the time is correct than it is finished
					else
						officialname = name
					end
				else
					officialname = name
				end
			end
		end
	end

	if sitelink and officialname then --if there is an official name, then use it
		return checksitelink(sitelink, officialname), correctlanguage
	else
		if officialname then return officialname end
		if sitelink then
			if wiki == "de" then
				local label = wikibase.getLabelByLang(riderID, wiki)
				if label then
					local p27 = wikibase.getBestStatements(riderID, 'P27') -- P27 is country of citizenship
					if p27[1] and p27[1].mainsnak.snaktype == 'value' then
						local c = p27[1].mainsnak.datavalue.value.id
						if c=="Q159" or c=="Q184" or c=="Q212" or c=="Q232" then -- Q159, Q184, Q212, Q232 is Russia, Belarus, Ukraine, Kazakhstan
							return checksitelink(sitelink, label), correctlanguage
						end
					end
				end
			end
			if wiki == 'ru' then
				local label = revertfirstlast(mw.text.trim(string.gsub(sitelink, "%b()", ""), " "))
				return checksitelink(sitelink, label), correctlanguage
			else
				return checksitelink(sitelink, mw.text.trim(string.gsub(sitelink, "%b()",""), " ")), correctlanguage
			end
		end

		-- No WP article. Display label, and make it a red link if no other article uses the title
		local link
		local label = wikibase.getLabelByLang(riderID, wiki)
		if label then
			if wiki == 'ar' then
				link = make_IllWD2_link(riderID, label)
			else
				if wiki=='ru' then
					label=revertfirstlast(label)
				end

				if black_list( label) then
					link = label
				else
					local title = mw.title.new(label)
					if title and title.exists then
						link = label
					else
						link = "[[" .. label.. "]]"
					end
				end
			end
			return link, correctlanguage
		end

		-- No label in the local language. Try other languages, but don't link.
		correctlanguage=false
		if wiki == 'ar' then
			link = make_IllWD2_link(riderID)
		else
			link = getLabelFallback(riderID)
			if link then
				link = string.gsub(link, "%b()", "")
			else
				link = "(label missing)"
			end
		end
		return link, correctlanguage
	end
end

-- Get the countryID, return a single one, not a list
local function getCountryID(entityID, timeOfRace)
	local countryID
	
	if entityID then
		local stm = getStatementForTime(entityID, 'P1532', timeOfRace) -- P1532 is country for sport
		if stm == nil then
			stm = getStatementForTime(entityID, 'P17', timeOfRace) -- P17 is country
		end
		if stm then countryID = stm.mainsnak.datavalue.value.id end
	end
	return countryID
end

--[[ Get the name of a country ]]
local function getCountryName(countryID)
	local name = country_name_from_list(countryID)
	if name == nil then
		local label, lang = wikibase.getLabelWithLang(countryID)
		--[[ Uses standard language fallback. Should not return nil, nil, as all countries have English labels. ]]
		if lang == wikilang then
			name = label
		elseif lang then
			name = label .. ' (' .. lang .. ')'
		end
	end
	return name or ''
end

--[[ Get sitelink with no wiki no formating ]]
local function getRawTeamLink(teamID)
	local sitelink
	local parentID = getParentID(teamID)
	if parentID then -- try parent team first
		sitelink = mw.wikibase.getSitelink(parentID)
	end
	if not sitelink then
		sitelink = mw.wikibase.getSitelink(teamID)
	end
	return sitelink
end

--[[ Get sitelink, categoryID and maybe country for a team.
	Returns sitelink, team category ID, countryID (only countryID if country arg is true ]]
local function getTeamLinkCat(teamID, timeOfRace, country, forceParentlink)
	local name, sitelink, catID, countryID, p31
	local parentID = getParentID(teamID)
	local season=false
	-- Find team category
	--Hypothesis, it is a season, look in P2094
	for _, p2094 in statements(teamID, 'P2094') do
		if checktime(p2094, p2094.qualifiers, timeOfRace) then
			if data.teamCats[p2094.mainsnak.datavalue.value.id] then
				catID = p2094.mainsnak.datavalue.value.id
				season=true
				break
			end
		end
	end	
	--check if season
	if season==false then --otherwise already clear
		for _, p in statements(teamID, 'P31') do
			local natureID = p.mainsnak.datavalue.value.id
			if natureID=="Q53534649" then
				season=true
				break
			end
		end
	end

	--look by the parent, then P31 is used for the category
	if (not catID and parentID and season) then
		p31 = getStatementForTime(parentID, 'P31', timeOfRace)
	elseif not season then --it is the team look in the team directly
		p31 = getStatementForTime(teamID, 'P31', timeOfRace)
	end
	if p31 and data.teamCats[p31.mainsnak.datavalue.value.id] then 
		catID = p31.mainsnak.datavalue.value.id 
	end
	-- Find country if needed
	if country or data.natTeamCats[catID] then
		countryID = getCountryID(teamID, timeOfRace)
	end
	if countryID and data.natTeamCats[catID] then
		if countryID=='Q145' then
			name = getCountryName('Q23666')
		else --to solve the United-Kingdom/Great Britain problem by national team
			name = getCountryName(countryID)
		end
		local t={Q20738667=34, Q54555994=35, Q99658502=36}
		if t[catID] then --add U23, U19, B, (note: why "B" and not B)
			name = name ..' '..translate("headoftableIII",t[catID])
		end
		sitelink = getRawTeamLink(teamID)
	else
		-- It is not a national cycling team
		local isLocal
		if season and not forceParentlink then
			sitelink = wikibase.getSitelink(teamID)
			name, isLocal = getOfficialName(teamID, timeOfRace,true) --problem here is that the label will be used if no official name, official name of the parent would actually be better...
			if not sitelink and parentID then
				sitelink = wikibase.getSitelink(parentID)
			end
		else
			if parentID then -- try parent team first
				sitelink = wikibase.getSitelink(parentID)
				name, isLocal = getOfficialName(parentID, timeOfRace)
			end
			if not sitelink then
				sitelink = wikibase.getSitelink(teamID)
			end
		end
        
		if not name or (not isLocal and l10n["lang_priority"]) then
			local partName, partIsLocal = getOfficialName(teamID, timeOfRace)
			if partName and (not name or partIsLocal) then
				name = partName
			end
		end
	end
	if sitelink then
		if name then
			sitelink = '[[' .. sitelink .. '|' .. name .. ']]'
		else
			sitelink = '[[' .. sitelink .. ']]'
		end
	else
        if wiki == "ar" then
			local arlabel = mw.wikibase.getLabelByLang((parentID or ''), 'ar') or ""
            local texte = mw.wikibase.getLabelByLang(teamID, 'ar') or ""
            sitelink = make_IllWD2_link((parentID or teamID), arlabel, name, texte)
        else
            if name then
                sitelink = name
            else
                sitelink = (parentID and wikibase.getLabel(parentID)) or
                    wikibase.getLabel(teamID) or 'No name'
            end
        end
	end
	return sitelink, catID, countryID
end

local function getTeamCodeCat(teamID, timeOfRace)
	-- Find team category
	local codeUCI
	local p1998 =getStatementForTime(teamID, 'P1998', timeOfRace)
	if p1998 then
		codeUCI = p1998.mainsnak.datavalue.value
	else
		local parentID = getParentID(teamID)
		if parentID then
			p1998 =getStatementForTime(parentID, 'P1998', timeOfRace)
			if p1998 then
				codeUCI = p1998.mainsnak.datavalue.value
			end
		end
	end
	return codeUCI
end

local function getReference(lf,statement, outputLocal)
	local function formatRefDate(date, precision)
		if precision == 9 then -- Precision is year
			return string.sub(date, 2, 5)
		elseif precision == 10 then -- Precision is month
			return contentLanguage:formatDate("F Y", string.sub(date, 2, 8))
		elseif precision >= 11 then -- Precision is day (or less)
			return funcDate(date, 'long')
		end
	end

	local ref = statement.references
	if not ref or not ref[1] then
		return nil
	end
	ref = ref[1].snaks
	if ref.P854 and ref.P854[1] and ref.P854[1].snaktype == 'value' then -- P854 is 'reference URL'
		local refURL = ref.P854[1].datavalue.value
		local refTitle = ''
		local refDate = ''
		local refRetrieved = ''
		local refLang = ''
		if ref.P1476 and ref.P1476[1] and ref.P1476[1].snaktype == 'value' then -- P1476 is 'title URL'
			refTitle = ref.P1476[1].datavalue.value.text
			local lang = ref.P1476[1].datavalue.value.language
			if lang ~= wikilang then
				refLang = '(' .. lang .. ')'
                if wiki == 'ar' then refLang = lang end
            end
		end
		if ref.P577 and ref.P577[1] and ref.P577[1].snaktype == 'value' then -- P577 is 'publication date'
			local value = ref.P577[1].datavalue.value
			refDate = formatRefDate(value.time, value.precision)
			if (wiki == 'ar') then refDate = refDate
			else refDate = ', ' .. refDate
			end
		end
		if ref.P813 and ref.P813[1] and ref.P813[1].snaktype == 'value' then -- P813 is 'retrieved'
			local value = ref.P813[1].datavalue.value
			refRetrieved = formatRefDate(value.time, value.precision)
			if wiki == "de" then
				refRetrieved = ", (abgerufen am " .. refRetrieved .. ')'
			elseif wiki == "ar" then
				refRetrieved = refRetrieved
			elseif wiki == "fr" then
				refRetrieved = " (consulté le " .. refRetrieved .. ')'
			elseif wiki == "da" then
				refRetrieved = " Hentet " .. refRetrieved .. '.'
			else
				refRetrieved = " Retrieved " .. refRetrieved .. '.'
			end
		end
		local domain = string.match(refURL, '//([^/]+)')
		if string.sub(domain, 1, 4) == 'www.' then
			domain = string.sub(domain, 5)
		end
		local refText
		if wiki == "ar" then
            refText = '{{web cite' ..
			'|url = ' .. refURL ..
			'|title= ' .. refTitle ..
			'|lang = ' .. refLang .. 
			'|website=' .. domain .. 
			'|date=' .. refDate ..
			'|accessdate=' .. refRetrieved ..
			'}}'
        elseif wiki == "fr" then
                -- fr: "(en) « Lloyd Mondory ... EPO », sur velonews.competitor.com (consulté le 30 april 2016), 30 octobre 2015."
			local sur = ', sur <span style="font-style:italic;"> ' .. domain .. '</span>'
			refText = refLang .. ' « ['.. refURL .. ' '.. refTitle .. '] »' .. sur .. refRetrieved .. refDate .. '.'
		elseif wiki == "de" then
			local In = ' In: <span style="font-style:italic;">' .. domain .. '</span>'
			refText = '<span style="font-style:italic;">['.. refURL.. ' '.. refTitle.. '.]</span> ' ..
				In .. refDate .. refRetrieved ..'.'
		else
			local at = ', <span style="font-style:italic;"> ' .. domain .. '</span>'
			refText = refLang .. ' [' .. refURL .. ' ' .. refTitle .. ']' .. at .. refDate .. '.' .. refRetrieved
		end
		if outputLocal==1 then
			return refText
		else
            local refargs = {}
            if wiki ~= "ar" then 
                refargs.name = refText
            end
			return lf:extensionTag('ref', refText, refargs)
		end
	end
end

--Some wikipedia, like WP:ar, don't use model like
--{{#invoke:Cycling race/infobox|Q123}}
--But have the module included in another module
--{{#invoke:wikidata|Cycling race/infobox|...
--in this case frame does not refer to the arguments of /infobox but to the wanted ones
--read https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#frame-object

local function get_arg(index, lf, number)
	if lf.args[index] then
		if number then
			return tonumber(lf.args[index])
		else
			return string.gsub(lf.args[index], "%c", "")
		end
	end
	return nil
end

local function getImageOrMap(QID, PID)
	local p18 = wikibase.getBestStatements(QID, PID) -- P18 is 'image'
	local first
	for _, image in pairs(p18) do
		if image.mainsnak.snaktype == 'value' then
			if not first then
				first = image.mainsnak.datavalue.value
			end
			local q = image.qualifiers
			if q and q.P2096 then
				for _, caption in pairs(q.P2096) do -- P2096 is 'caption'
					if caption.snaktype == 'value' and caption.datavalue.value.language == wikilang then
						return image.mainsnak.datavalue.value, caption.datavalue.value.text
					end
				end
			end
		end
	end
	return first
end

local function getLogo(QID)
	return getImageOrMap(QID, 'P154')
end

local function getImage(QID)
	return getImageOrMap(QID, 'P18')
end

local function getMap(QID)
	return getImageOrMap(QID, 'P242')
end

local function getSectionalView(QID)
	return getImageOrMap(QID, 'P2713')
end

--[[ Get link for race or competition]]
local function raceLink(QID)
	local sitelink = wikibase.getSitelink(QID)
	local instanceOf = firstValue(QID, 'P3450', 'id')
	if instanceOf == nil then
		instanceOf = firstValue(QID, 'P31', 'id') -- P31 is 'instance of'
	end
	if instanceOf == 'Q1137352' then -- Q1137352 is 'French Road Cycling Cup'
		local label2 = wikibase.getLabel(instanceOf)
		if sitelink then
			if label2 then return '[[' .. sitelink .. '|' .. label2 .. ']]' end
			return '[[' .. sitelink .. ']]'
		end
		local sitelink2 = wikibase.getSitelink(instanceOf)
		if sitelink2 then return '[[' .. sitelink2 ..'|' .. string.gsub(sitelink2, " %b()", "") .. ']]' end
		if label2 then return label2 end
	end
	if sitelink then return "[[".. sitelink.. "]]" end
	return wikibase.getLabel(QID) or ''
end

local function getPlaceLink(placeID,timeOfRace)
	local sitelink = wikibase.getSitelink(placeID)
	local name = country_name_from_list(placeID)
	if name==nil then
		name=getOfficialName(placeID, timeOfRace,nil,true) --name should be in the right language
	end
	if sitelink then
		-- Delete " (...)" form e.g. "Unley (South Australia)"
		if name ~=nil then
			return '[[' .. sitelink .. '|' .. name .. ']]'
		else
			return '[[' .. sitelink .. '|' .. string.gsub(sitelink, ' %b()', '') .. ']]'
		end
	end
	local label = wikibase.getLabel(placeID) or ''
	if wiki == 'ar' then
		arlabel = wikibase.getLabelByLang(placeID, "ar")
		return make_IllWD2_link(placeID, arlabel)
	end
	return contentLanguage:ucfirst(label)
end	

-- ClassID --> ClassLink
-- some WPs use a unique article for this case
local function classLinkFn(classID, circuitID)
	local link, label
	if wiki~="fr" then --not used
		link= wikibase.getSitelink('Q22348500') -- Q22348500 is 'cycling race class'
	elseif circuitID then
		link =wikibase.getSitelink(circuitID) --optional parameter to obtain [circuitlink|class label] 
	end

	if classID=="Q18536594" then 
		if wiki=="fr" then
			label="JO"
		else
			label="OG"
		end
	else
		 label = getLabelFallback(classID)
	end

	if label and link then
		link = '[[' .. link .. '|' .. label .. ']]'
	elseif link then
		link = '[[' .. link .. ']]'
	elseif label then
		link = label
	else
		link=''
	end
	if wiki == "ar" then-- right now Q22348500 has no link in "ar"
		link = make_IllWD2_link(classID , "", label)
	end
	return link
end
--[[ Get local content to a infoboxe from template args ]]
local function getLocalContent(contents, args)
	for _, content in pairs(contents) do
		local name = content.name
		if not name then error('translation missing in Module:Cycling race/l10n of your wikipedia') end
		local nameNoShy = string.gsub(name, '&#173;', '')  -- filter soft hyphen out
		local nameNoShyLow, name_pluralNoShyLow
		if nameNoShy then
			nameNoShyLow = mw.ustring.lower(nameNoShy)
		end
		local name_plural = content.name_plural
		local name_pluralNoShy = name_plural and string.gsub(name_plural, '&#173;', '')  -- filter soft hyphen out
		if name_pluralNoShy then
			name_pluralNoShyLow = mw.ustring.lower(name_pluralNoShy)
		end
		
		if args[nameNoShy] and args[nameNoShy] ~= '' then
			if content.special then
				local newname, value = string.match(args[nameNoShy], '([^:]+):(.*)')
				if value and mw.text.trim(value) ~= '' then
					content.name = mw.text.trim(newname)
					content.content = mw.text.trim(value)
				end
			else
				content.content = mw.text.trim(args[nameNoShy])
			end
		elseif nameNoShyLow and args[nameNoShyLow] and args[nameNoShyLow] ~= '' then
			if content.special then
				local newname, value = string.match(args[nameNoShyLow], '([^:]+):(.*)')
				if value and mw.text.trim(value) ~= '' then
					content.name = mw.text.trim(newname)
					content.content = mw.text.trim(value)
				end
			else
				content.content = mw.text.trim(args[nameNoShyLow])
			end
		elseif args[name_pluralNoShy] and args[name_pluralNoShy] ~= '' then
			content.name = content.name_plural
			content.content = mw.text.trim(args[name_pluralNoShy])
		elseif name_pluralNoShyLow and args[name_pluralNoShyLow] and args[name_pluralNoShyLow] ~= '' then
			content.name = content.name_plural
			content.content = mw.text.trim(args[name_pluralNoShyLow])
		end
	end
end

local function checkDis(q) --discipline
	dis="road"
	local sport_id=nil
	if q and q.P641 and q.P641[1] and q.P641[1].snaktype == 'value' then
		sport_id=q.P641[1].datavalue.value.id
	elseif q and q.P642 and q.P642[1] and q.P642[1].snaktype == 'value' then --fallback
		sport_id=q.P642[1].datavalue.value.id
	end
	
	if sport_id then
		if sport_id == 'Q520611' or sport_id =='Q1031445' then
			onlyRoad=false
			dis="mountainBike"
		elseif sport_id == 'Q335638' then
			onlyRoad=false
			dis="cycloCross"
		elseif sport_id == 'Q221635' then
			onlyRoad=false
			dis="track"			
		end
	end
	return dis
end

-- Rider --> Team link
local function getTeam(riderID, timeOfRace, q)
	-- q: qualifiers of statement in race entity where the rider is the value
	local teamID, link, catID, countryID
	if q and q.P54 and q.P54[1].snaktype == 'value' then -- P54 is member of sports team
		teamID = q.P54[1].datavalue.value.id
		link, catID, countryID = getTeamLinkCat(teamID, timeOfRace)
	else
		for _, s in statements(riderID, 'P54') do
			if not link then --like a break
				p54 =checktime(s, s.qualifiers, timeOfRace) 
				if p54 then
					dis=checkDis(p54.qualifiers)
			    	if dis=='road' then --by default
						teamID = p54.mainsnak.datavalue.value.id
						link, catID, countryID = getTeamLinkCat(teamID, timeOfRace)
					end
				end
			end
		end
	end
	return link, teamID, catID, countryID
end

--RiderID --> UCI code
local function getTeamCode(riderID, timeOfRace, q)
	-- q: qualifiers of statement in race entity where the rider is the value
	local teamID, code
	if q and q.P54 and q.P54[1].snaktype == 'value' then -- P54 is member of sports team
		teamID = q.P54[1].datavalue.value.id
		code = getTeamCodeCat(teamID, timeOfRace)
	else
		local p54 = getStatementForTime(riderID, 'P54', timeOfRace)
		if p54 then
			teamID = p54.mainsnak.datavalue.value.id
			code= getTeamCodeCat(teamID, timeOfRace)
		end
	end
	return code
end

local function seasonToTeamID(teamID)
	if teamID then
		local parentID=getParentID(teamID)
		if parentID then--season was used
			return parentID
		else
			return teamID
		end
	else
		return nil
	end
end

local function wdLink(id)
	local text = "[[File:Wikidata-logo S.svg| " .. Wikidatalogosize .. "|link=d:" .. id .. "]]"	 
	if arwiki_totemplate then
        text = '{{عدل في ويكي بيانات|type1=1|id=' .. id .. '}}'
    end
    return text
end

local function WPlinkpure(Qnumber)
	local link=''
	local Sitelink = wikibase.getSitelink(Qnumber) -- link to WParticle
	local Label = getLabelFallback(Qnumber) or ''

	if Sitelink ~= nil then link = "[[" .. Sitelink .. "|" .. mw.text.trim(string.gsub(Sitelink, "%b()", "")..' ') .. "]]"
	elseif wiki == 'ar' then
		arlabel = mw.wikibase.getLabelByLang(Qnumber, 'ar') or ""
		link = make_IllWD2_link(Qnumber , arlabel , Label)
	else 
        link = mw.ustring.gsub(Label, "^(%a)", function (x) return mw.ustring.upper(x) end)
	end

	return link
end

--=== C) Function for the output ===
local function getCountryBool(no_country_list)
	local country = true
	if no_country_list then
		for _, value in pairs(no_country_list) do -- get data if country should be printed in this wiki
			if value == wiki then country = false end
		end
	end
	return country
end

local function handle_error_message(s)
	local error_message=''
	if s.error_message and s.error_message ~= 0 then
		error_message = func_error_message( 1)
		error_message = mw.ustring.gsub(error_message, "<1>", s.property)
		error_message = mw.ustring.gsub(error_message, "<2>", mw.wikibase.label( s.item ))
		error_message = mw.ustring.gsub(error_message, "<3>", s.item)
		error_message = ' [[File:Exclam icon.svg|12px|'.. error_message .. ']]'
	end
	return error_message 
end

local function tableA(s)
	local error_message=handle_error_message(s)

	local t = mw.html.create('table')
		:addClass('sortable')
		:attr('cellpadding', '0')
		:attr('cellspacing', '0')
		:css('border' , '1px solid var(--border-color-subtle, #c8ccd1)')
		:css('padding', '3px')
	
	local title =translate(s.header_function,s.header_1, s.w_race, s.title) 
	if s.header_1 == 19 and wiki == "ar" then title = title .. " " .. s.year end	
		
	local wd_link = mw.html.create('span'):cssText('float:left; margin: 0 5px'):wikitext(wdLink(s.item..'#'..s.property))
	if arwiki_totemplate then wd_link = wdLink(s.item..'#'..s.property) end
	local caption = t:tag('tr'):tag('th'):attr('colspan', tostring(#s.header_2 + 1))
	:cssText('padding:2px; text-align:center; line-height: 1.8em; color: inherit;')
	:css('background-color',backgroundColor)
	caption:wikitext(tostring(wd_link)..' '..error_message ..' '..title)

	local country=getCountryBool(s.no_country)

	local header = t:tag('tr')
	for i,k in ipairs(s.header_2) do
		if i == s.country_column then
			if country == true then
				header:tag('th')
					:cssText('text-align:center;padding:2px 20px 2px 2px;white-space:nowrap')
					:wikitext(translate(s.header_function,k,s.w_race))
			end
		end
		if i ~= s.country_column then
			local column = header:tag('th')
					:cssText('text-align:center;padding:2px 20px 2px 2px;white-space:nowrap')
					:wikitext(translate(s.header_function,k,s.w_race))
			if s.data_sort_type[i] == 'unsortable' then
				column:addClass('unsortable')
			end
		end
	end

	return t
end

local function tableB(s) --for startlist
	local error_message=handle_error_message(s)
	
	local roll = true
	for _, value in pairs(s.no_roll_startlist) do -- get data if country should be printed in this wiki
		if value == wiki then roll = false end
	end

	local cssTable= "border: 1px solid var(--border-color-subtle, #c8ccd1); margin: 0 0 0 0;"..
				"background-color: var(--background-color-base, #fff); padding: 0px; float: left;"..
				"clear: left; color: var(--color-base, #202122); text-align: left; vertical-align: top; font-size: 85%; line-height: 1.8em;"
	local wdlink_span = mw.html.create('span'):css('float',floattable):wikitext(wdLink(s.item.. '#'.. s.property)..' '..error_message)
	if arwiki_totemplate then wdlink_span = wdLink(s.item..'#'..s.property) end
	if roll == true then
		local rollTable1 = mw.html.create('div'):addClass("mw-collapsible")
		:cssText('center = margin: 0 0.5em 0;clear:both; border: 1px solid var(--border-color-subtle, #c8ccd1);' ..
		'cellpadding="4" cellspacing="0" style="width:100%; background-color: var(--background-color-base, #fff); color:inherit; padding: 5px;'..
		'margin-bottom:1em; background-color:'..backgroundColor..';')
		:attr('title','['..translate("startlist",14)..']/['..translate("startlist",15)..']')
		local tDiv= rollTable1:tag('div')
		:cssText('text-align:'.. textalign ..";height:1.8em; color:inherit;font-weight:bold;")
		:css('background-color',backgroundColor)
		tDiv:tag('span')

		local tSpan=tDiv:wikitext(tostring(wdlink_span))
		tDiv:wikitext(translate("startlist",1,s.w_race or false))
		
		tDiv = rollTable1:tag('div'):addClass("mw-collapsible-content"):cssText("margin:0; background:var(--background-color-base, #fff); color: inherit; display:block; text-align:left;")
	
		local tTable= tDiv:tag('table'):cssText("border:1px solid var(--border-color-subtle, #c8ccd1)")
		local tCell = tTable:tag('tr'):tag('td')
		local insideTable =tCell:tag('table'):attr('cellpadding','4')  -- cellspacing="0" style="width:100%;"  color: black;
		:cssText(cssTable)

		return rollTable1, insideTable
	else
		--otherwise problem of clear
		local tab = mw.html.create('table')
		tCell=tab:tag('td')
		
		local tTable =tCell:tag('table')
		:attr('cellpadding','0')
		:cssText(cssTable)
		tCell = tTable:tag('tr'):tag('th')
		:css("background-color",backgroundColor)
		:css('color', 'inherit')
		:attr('colspan','3'):attr('align','center')
		tCell:node(wdlink_span)
		tCell:wikitext(translate("startlist",1,s.w_race or false))
	    local tRow=tCell:tag('tr')

		return tab, tRow
	end
end

--=== D) Jersey, flag functions ===
--used from 2 functions
local flags = {
		Q16 = {'CAN', {'Flag of Canada.svg', '+1965-02-15'}},
		Q17 = {'JPN', {'Flag of Japan.svg', '+1999-08-13'},
			{'Flag of Japan (1870–1999).svg', '+1870-02-27', '+1999-08-12'}},
		Q20 = {'NOR', {'Flag of Norway.svg', '+1821-07-13'}},
		Q27 = {'IRL', {'Flag of Ireland.svg', '+1980-07-29'},
			{'Olympic flag.svg', '+1980-07-19', '+1980-07-29'}, -- OG-1980			
			{'Flag of Ireland.svg', '+1937-12-29', '+1980-07-19'}},
		Q28 = {'HUN', {'Flag of Hungary.svg', '+1957-05-23'}},
		Q29 = {'ESP', {'Flag of Spain.svg', '+1981-12-06'},
			{'Flag of Spain (1977–1981).svg', '+1977-01-21', '+1981-12-06'},
			{'Flag of Spain (1945–1977).svg', '+1945-10-11', '+1977-01-21'},
			{'Flag of Spain (1938–1945).svg', '+1939', '+1945-10-11'},
			{'Flag of the Second Spanish Republic.svg', '+1931-04-14', '+1939'},
			{'Flag of Spain (1785–1873, 1875–1931).svg', '+1874', '+1931-04-13'}},
		Q30 = {'USA', {'Flag of the United States.svg', '+1960-07-04'}},
		Q31 = {'BEL', {'Flag of Belgium (civil).svg', '+1980-07-29'},
			{'Olympic flag.svg', '+1980-07-19', '+1980-07-29'}, -- OG-1980		
			{'Flag of Belgium (civil).svg', '+1800', '+1980-07-19'}},
		Q32 = {'LUX', {'Flag of Luxembourg.svg'}},
		Q33 = {'FIN', {'Flag of Finland.svg', '+1918-05-29'}},
		Q34 = {'SWE', {'Flag of Sweden.svg'}},
		Q35 = {'DEN', {'Flag of Denmark.svg', '+1980-07-29'},
			{'Olympic flag.svg', '+1980-07-19', '+1980-07-29'}, -- OG-1980			
			{'Flag of Denmark.svg', '+1800', '+1980-07-19'}},
		Q36 = {'POL', {'Flag of Poland.svg'}},
		Q37 = {'LTU', {'Flag of Lithuania.svg', '+2004-09-01'},
			{'Flag of Lithuania (1988-2004).svg', '+1990-03-11', '+2004-09-01'}},
		Q38 = {'ITA', {'Flag of Italy.svg', '+1980-07-29'},
			{'Olympic flag.svg', '+1980-07-19', '+1980-07-29'}, -- OG-1980	
			{'Flag of Italy.svg', '+1946-06-19', '+1980-07-19'},
			{'Flag of Italy (1861–1946).svg', '+1861', '+1946-06-19'}},
		Q39 = {'SUI', {'Flag of Switzerland.svg', '+1980-08-29'},
			{'Olympic flag.svg', '+1980-07-19', '+1980-07-29'}, -- OG-1980	
			{'Flag of Switzerland.svg', '+1879-01-01', '+1980-07-19'}},
		Q40 = {'AUT', {'Flag of Austria.svg', '+1945-05-01'},
			{'Flag of Austria.svg', '+1919-10-21', '+1938-03-13'}},
		Q41 = {'GRE', {'Flag of Greece.svg', '+1978'}},
		Q43 = {'TUR', {'Flag of Turkey.svg'}},
		Q45 = {'POR', {'Flag of Portugal.svg', '+1911-06-30'}},
		Q55 = {'NED', {'Flag of the Netherlands.svg', '+1980-07-29'},
			{'Olympic flag.svg', '+1980-07-19', '+1980-07-29'}, -- OG-1980			
			{'Flag of the Netherlands.svg', '+1806', '+1980-07-19'}},
		Q77 = {'URU', {'Flag of Uruguay.svg'}},
		Q96 = {'MEX', {'Flag of Mexico.svg', '+1968-09-16'},
			{'Flag of Mexico (1934-1968).svg', '+1934', '+1968-09-16'}},
		Q114 = {'KEN', {'Flag of Kenya.svg'}},
		Q115 = {'ETH', {'Flag of Ethiopia.svg', '+1996-10-31'}},
		Q117 = {'GHA', {'Flag of Ghana.svg', '+1966-02-28'}},
        Q142 = {'FRA', {'Flag of France (1794–1815, 1830–1974, 2020–present).svg', '+2020-07-14'},
 		    {'Flag of France.svg', '+1980-07-29', '+2020–07-14'},       	
			{'Olympic flag.svg', '+1980-07-19', '+1980-07-29'}, -- OG-1980	        	
		    {'Flag of France.svg', '+1794-05-20', '+1980-07-19'}},
		Q145 = {'GBR', {'Flag of the United Kingdom (3-5).svg', '+1980-07-29'},
			{'Olympic flag.svg', '+1980-07-19', '+1980-07-29'}, -- OG-1980			
			{'Flag of the United Kingdom (3-5).svg', '+1980-07-19'}},
		Q148 = {'CHN', {"Flag of the People's Republic of China.svg", '+1985'}},
		Q155 = {'BRA', {'Flag of Brazil.svg', '+1992-05-11'},
			{'Flag of Brazil (1968–1992).svg', '+1968-05-28', '+1992-05-11'}},
		Q159 = {'RUS', {'Flag of Russia.svg', '+1993-12-11'},
			{'Flag of Russia (1991–1993).svg', '+1991-08-22', '+1993-12-11'},
			{'Flag of the Russian Soviet Federative Socialist Republic.svg', '+1954', '+1991-08-22'},
			{'Flag of the Russian Soviet Federative Socialist Republic (1937–1954).svg', '+1937', '+1954'}},
		Q183 = {'GER', {'Flag of Germany.svg', '+1949-05-23'},
			{'Flag of the German Reich (1935–1945).svg', '+1935-09-15', '+1945-05-23'},
			{'Flag of the German Reich (1933–1935).svg', '+1933-03-12', '+1935-09-15'},
			{'Flag of Germany (3-2 aspect ratio).svg', '+1919-04-11', '+1933-03-12'},
			{'Flag of the German Empire.svg', '+1871-04-16', '+1919-04-11'}},
		Q184 = {'BLR', {'Flag of Belarus.svg', '+2012-05-11'},
			{'Flag of Belarus (1995–2012).svg', '+1995-06-07', '+2012-05-11'},
			{'Flag of Belarus (1918, 1991–1995).svg', '+1991-09-19', '1995-06-07'}},
		Q189 = {'ISL', {'Flag of Iceland.svg', '+1944-06-17'}},
		Q191 = {'EST', {'Flag of Estonia.svg'}},
		Q211 = {'LAT', {'Flag of Latvia.svg'}},
		Q212 = {'UKR', {'Flag of Ukraine.svg', '+1992-01-28'}},
		Q213 = {'CZE', {'Flag of the Czech Republic.svg', '+1920-03-30'}},
		Q214 = {'SVK', {'Flag of Slovakia.svg'}},
		Q215 = {'SLO', {'Flag of Slovenia.svg'}},
		Q217 = {'MDA', {'Flag of Moldova.svg'}},
		Q218 = {'ROU', {'Flag of Romania.svg', '+1989-12-27'},
			{'Flag of Romania (1965-1989).svg', '+1989-12-27', '+1965'},
			{'Flag of Romania (1952-1965).svg', '+1952', '+1965'},
			{'Flag of Romania (1948-1952).svg', '+1948-01-08', '+1952'},
			{'Flag of Romania.svg', '12. april 1867-04-12', '+1948-01-08'}},
		Q219 = {'BUL', {'Flag of Bulgaria.svg', '+1990-11-22'},
			{'Flag of Bulgaria (1971 – 1990).svg', '+1971-05-18', '+1990-11-22'}},
		Q222 = {'ALB', {'Flag of Albania.svg', '+1992'}},
		Q224 = {'CRO', {'Flag of Croatia.svg', '+1990-12-21'},
			{'Flag of Croatia (white chequy).svg', '+1990-06-27', '+1990-12-21'}},
		Q227 = {'AZE', {'Flag of Azerbaijan.svg'}},
		Q228 = {'AND', {'Flag of Andorra.svg'}},
		Q229 = {'CYP', {'Flag of Cyprus.svg', '+2006-08-20'},
			{'Flag of Cyprus (1960-2006).svg', '+1960-08-16', '+2006-08-20'}},
		Q232 = {'KAZ', {'Flag of Kazakhstan.svg'}},
		Q235 = {'MON', {'Flag of Monaco.svg'}},
		Q238 = {'SMR', {'Flag of San Marino.svg', '+1980-07-29'},	
			{'Olympic flag.svg', '+1980-07-19', '+1980-07-29'}, -- OG-1980		
			{'Flag of San Marino.svg', '+1980-07-19'}},	
		Q241 = {'CUB', {'Flag of Cuba.svg'}},
		Q244 = {'BAR', {'Flag of Barbados.svg'}},
		Q252 = {'INA', {'Flag of Indonesia.svg'}},
		Q258 = {'RSA', {'Flag of South Africa.svg', '+1994-04-27'},
			{'Flag of South Africa (1982–1994).svg', '+1982-06-01', '+1994-04-27'},	-- exacte datum in 1982 onbekend
			{'Flag of South Africa (1928-1982).svg', '+1928-05-31', '+1982-05-31'}
		},
		Q262 = {'ALG', {'Flag of Algeria.svg'}},
		Q265 = {'UZB', {'Flag of Uzbekistan.svg'}},
		Q298 = {'CHI', {'Flag of Chile.svg'}},
		Q334 = {'SGP', {'Flag of Singapore.svg'}},
		Q347 = {'LIE', {'Flag of Liechtenstein.svg'}},
		Q398 = {'BRN ', {'Flag of Bahrain.svg','+2002-02-17'},
			{'Flag of Bahrain (1972–2002).svg', '+1972-08-19', '+2002-02-16'}},
		Q403 = {'SRB', {'Flag of Serbia.svg', '+2004-08-18'},
			{'Flag of Serbia (1992–2004).svg', '+1992-04-27', '+2004-08-17'}},
		Q408 = {'AUS', {'Flag of Australia.svg', '+1980-07-29'},
			{'Olympic flag.svg', '+1980-07-19', '+1980-07-29'}, -- OG-1980			
			{'Flag of Australia.svg', '+1980-07-19'}},		
		Q414 = {'ARG', {'Flag of Argentina.svg'}},
		Q419 = {'PER', {'Flag of Peru.svg', '+1950'},
			{'Flag of Peru (1825-1950).svg', '+1825-02-25', '+1950'}},
		Q424 = {'CAM', {'Flag of Cambodia.svg', '+1993-06-30'},
			{'Flag of Cambodia.svg', '+1948-10-20', '+1970-10-09'}},		
		Q664 = {'NZL', {'Flag of New Zealand.svg'}},
		Q711 = {'MGL', {'Flag of Mongolia.svg'}},
		Q717 = {'VEN', {'Flag of Venezuela.svg', '+2006-03-12'},
			{'Flag of Venezuela (1930–2006).svg', '+1930','+2006-03-12'}},
		Q733 = {'PAR', {'Flag of Paraguay.svg', '+2013-07-15'},
			{'Flag of Paraguay (1990–2013).svg', '+1990', '+2013-07-14'}},
		Q736 = {'ECU', {'Flag of Ecuador.svg'}},
		Q739 = {'COL', {'Flag of Colombia.svg'}},
		Q750 = {'BOL', {'Flag of Bolivia.svg', '+1851-10-31'}},
		Q754 = {'TTO', {'Flag of Trinidad and Tobago.svg'}},
		Q769 = {'GRN', {'Flag of Grenada.svg'}},
		Q774 = {'GUA', {'Flag of Guatemala.svg'}},
		Q778 = {'BAH', {'Flag of the Bahamas.svg'}, '+1973-07-10'},
		Q783 = {'HON', {'Flag of Honduras.svg'}, '+1949'},
		Q786 = {'DOM', {'Flag of the Dominican Republic.svg'}},
		Q794 = {'IRI', {'Flag of Iran.svg', '+1980-07-29'},
			{'Flag of Iran (1964–1980).svg', '+1964', '+1980-07-29'}},
		Q800 = {'CRC', {'Flag of Costa Rica (state).svg', '+1906-11-27'}},
		Q801 = {'ISR', {'Flag of Israel.svg'}},
		Q804 = {'PAN', {'Flag of Panama.svg'}},
		Q813 = {'KGZ', {'Flag of Kyrgyzstan.svg', '+1992-03-03'}},
		Q817 = {'KUW', {'Flag of Kuwait.svg', '+1961-09-07'}},
		Q833 = {'MAS', {'Flag of Malaysia.svg', '+1963-09-16'}},
		Q842 = {'OMA', {'Flag of Oman.svg', '+1995'}},
		Q846 = {'QAT', {'Flag of Qatar.svg'}},
		Q858 = {'SYR', {'Flag of Syria.svg', '+1980-03-29'}},
		Q865 = {'TPE', {'Flag of the Republic of China.svg', '+1928-12-17'}},
		Q869 = {'THA', {'Flag of Thailand.svg'}},
		Q878 = {'UAE', {'Flag of the United Arab Emirates.svg'}},
		Q881 = {'VIE', {'Flag of Vietnam.svg', '+1976-02-07'}},
		Q884 = {'KOR', {'Flag of South Korea.svg', '+1997-10'}},
		Q889 = {'AFG', {'Flag of Afghanistan (2013–2021).svg','+2013-08-19'},
			{'Flag of Afghanistan (2004-2021, Variant).svg', '+2004-10-09', '+2013-08-18'},
			{'Flag of Afghanistan (2002–2004, variant with golden arms).svg', '+2002-06-27', '+2004-10-08'},
			{'Flag of Afghanistan (2002–2004).svg', '+2002-01-28', '+2002-06-26'},
			{'Flag of Afghanistan (2001–2002).svg', '+2001-11-13', '+2002-01-27'},
			{'Flag of Afghanistan (1992–2001).svg', '+1992-12-07', '+2002-01-26'},
			{'Flag of Afghanistan (1992).svg', '+1992-04-27', '+1992-12-06'},
			{'Flag of Afghanistan (1987–1992).svg', '+1987-11-30', '+1992-04-26'},
			{'Flag of Afghanistan (1980–1987).svg', '+1980-04-22', '+1987-11-29'},
			{'Flag of Afghanistan (1978–1980).svg', '+1978-10-19', '+1980-04-21'},
			{'Flag of Afghanistan (1978).svg', '+1978-04-27', '+1978-10-18'},
			{'Flag of Afghanistan (1974–1978).svg', '+1974-05-9', '+19780-4-26'},
			{'Flag of Afghanistan (1973–1974).svg', '+1973-03-17', '+1974-05-8'},
			{'Flag of Afghanistan (1931–1973).svg', '+1930-03-27', '+1973-03-16'},
			{'Flag of Afghanistan (1929–1931).svg', '+1929-01-1', '+1930-03-26'}},		
		Q902 = {'BAN ', {'Flag of Bangladesh.svg','+1972-01-17'},
			{'Flag of Bangladesh (1971).svg', '+1971-03-06', '+1972-01-16'}},		
		Q916 = {'ANG', {'Flag of Angola.svg', '+1975-11-11'}},
		Q917 = {'BHU ', {'Flag of Bhutan.svg','+1972-06-08'},
			{'Flag of Bhutan (1956–1969).svg', '+1956-07-01', '+1972-06-07'},
			{'Flag of Bhutan (1949–1956).svg', '+1949-01-01', '+1956-06-30'}},		
		Q921 = {'BRU', {'Flag of Brunei.svg', '+1959-09-29'}},
		Q928 = {'PHI', {'Flag of the Philippines.svg', '+1998'}},
		Q948 = {'TUN', {'Flag of Tunisia.svg', '+1999-07-03'}},
		Q954 = {'ZIM', {'Flag of Zimbabwe.svg', '+1980-04-18'}},
		Q965 = {'BUR', {'Flag of Burkina Faso.svg'}},
		Q983 = {'GEQ', {'Flag of Equatorial Guinea.svg', '+1979-08-21'},
			{'Flag of Equatorial Guinea (1973–1979).svg', '+1973', '+1979-08-21'},
			{'Flag of Equatorial Guinea (without coat of arms).svg', '+1968-10-12', '+1973'}},
		Q986 = {'ERI', {'Flag of Eritrea.svg'}},
		Q1000 = {'GAB', {'Flag of Gabon.svg', '+1960-08-09'}},
		Q1007 = {'GBS', {'Flag of Guinea-Bissau.svg', '+1973-09-24'}},
		Q1008 = {'CIV', {"Flag of Côte d'Ivoire.svg"}},
		Q1009 = {'CMR', {'Flag of Cameroon.svg'}},
		Q1027 = {'MRI', {'Flag of Mauritius.svg', '+1968-03-13'}},
		Q1028 = {'MAR', {'Flag of Morocco.svg'}},
		Q1030 = {'NAM', {'Flag of Namibia.svg', '+1990-03-21'}},
		Q1036 = {'UGA', {'Flag of Uganda.svg', '+1962-10-09'}},
		Q1037 = {'RWA', {'Flag of Rwanda.svg', '+2001-10-25'},
			{'Flag of Rwanda (1962–2001).svg', '+1962', '+2001-10-25'}},
		Q1183 = {'PUR', {'Flag of Puerto Rico.svg'}},
		Q9676 = {'IMN', {'Flag of the Isle of Man.svg'}},
		Q15180 = {'URS', {'Flag of the Soviet Union.svg', '+1980-08-15', '+1991-12-25'},
			{'Flag of the Soviet Union (1955–1980).svg', '+1955-08-19', '+1980-08-14'},
			{'Flag of the Soviet Union (1924–1955).svg', '+1923-11-13', '+1955-08-18'}},
		Q16957 = {'GDR', {'Flag of East Germany.svg', '+1959-10-01'},
			{'Flag of Germany.svg', '+1949-10-07', '+1959-10-01'}}, --German Democratic Republic
		Q8646 = {'HKG', {'Flag of Hong Kong.svg'}},
		Q25228 = {'AIA', {'Flag of Anguilla.svg'}},
		Q29999 = {'NED', {'Flag of the Netherlands.svg', '+1980-07-29'}, --Kingdom of the Netherlands
			{'Olympic flag.svg', '+1980-07-19', '+1980-07-29'}, -- OG-1980			
			{'Flag of the Netherlands.svg', '+1690', '+1980-07-19'}},		
		Q33946 = {'TCH', {'Flag of the Czech Republic.svg', '+1920'}}, -- Czechoslovakia (1918–1992)
		Q36704 = {'YUG', {'Flag of Yugoslavia (1992–2003).svg', '+1992-04-27', '+2003-02-04'}, --Yugoslavia
			{'Flag of Yugoslavia (1943–1992).svg', '+1946', '+1992-04-27'}},
		Q41304 = {'GER', {'Flag of Germany (3-2 aspect ratio).svg', '+1918-11-09'}}, -- Weimar Republic
		Q47588 = {'EU', {'Flag_of_the_Basque_Country.svg'}},
		Q83286 = {'YUG', {'Flag of Yugoslavia (1943–1992).svg'}}, --Socialist Federal Republic of Yugoslavia
		Q172579 = {'ITA', {'Flag of Italy (1861–1946).svg'}}, --Kingdom of Italy (1861-1946)
		Q216923 = {'TPE', {'Flag of Chinese Taipei for Olympic games.svg'}}, -- Chinese Taipei
		Q268970 = {'AUT', {'Flag of Austria.svg', '+1918-11-12', '+1919-09-10'}}, -- German-Austria (1918-1919)
		Q713750 = {'FRG', {'Flag of Germany.svg'}}, --West Germany
		Q853348 = {'TCH', {'Flag of the Czech Republic.svg'}, '+1960-07-11', '+1990-03-29'}, -- Czechoslovak Socialist Republic (1960-1990)
		Q2415901 = {'GER', {'Merchant flag of Germany (1946–1949).svg', '+1945-05-09', '+1949-05-23'}}, -- Allied-occupied Germany
		Q13474305 = {'ESP', {'Flag of Spain (1945–1977).svg', '+1945-10-11', '+1977-01-21'}, -- Francoist Spain (1935-1976)
			{'Flag of Spain (1938–1945).svg', '+1939', '+1945-10-11'},
			{'Flag of the Second Spanish Republic.svg', '+1931-04-14', '+1939'}},
		Q113486069={'NEUTRAL', {'Flag white.svg'}} --Russia and Belarus during the ban, cannot replace the flags above, because there are cases where it does not apply
	}

local function flag(countryID, date)
	local trackingCategory = ''
	--[[ If you uncomment the line under this comment, all pages with look-up misses in
	the flag table will be placed in a tracking category. You can use this to find more flags
	to add to the table. ]]
	-- trackingCategory = '[[Category:Missing flag in Module:Cycling race]]'

	local entry = flags[countryID]
	local IOC
	local file
	local result = ""
	if entry then
		for i, v in ipairs(entry) do
			if i == 1 then
				IOC = v
			else
				if not date then
					file = v[1]
					break
				else
					local from = v[2]
					local to = v[3]
					if (not from or from <= date) and (not to or to > date) then
						file = v[1]
						break
					end
				end
			end
		end
	end
	local flagpxSize = '20px'
	if countryID == 'Q39' then flagpxSize = '16px'end -- Small size for an square flag as Switzerland
	if file then
		result = '[[File:' .. file .. '|border|' .. flagpxSize ..'|' .. IOC .. ']]'
		if arwiki_totemplate then
			result = '{{flagicon|' .. IOC .. '}}'
		end
	elseif not date then
		local p41 = firstValue(countryID, "P41") -- P41 is flag image
		if p41 then
			result = '[[File:' .. p41 .. '|border|' .. flagpxSize ..'|(Wikidata:' .. countryID .. ')]]'
			if arwiki_totemplate then
				result = '{{flagicon image|' .. p41 .. '}}'
			end
		end
	else
		-- Search flag for specific date
		local p41 = getStatementForTime(countryID, "P41", date) -- P41 is flag image
		if p41 then
			result = '[[File:' .. p41.mainsnak.datavalue.value .. '|border|' .. flagpxSize ..'|(Wikidata:' .. countryID .. ')]]'
			if arwiki_totemplate then
				result = '{{flagicon image|' .. p41.mainsnak.datavalue.value .. '}}'
			end
		end
	end
	return result .. trackingCategory
end

-- countryID --> shape ([[France|FRA]])
local function uciCodeCountry(countryID)
    local uciCode, countryName 
    local blacklist={Q736=true}
	if countryID then
		--get UCI code
		if flags[countryID] then
			uciCode=flags[countryID][1]
		end
		--get link, assumed for a country the label is equal to the link, where not correct in the blacklist
		--if the black list becomes too long, we could create a second list for the sitelinks
		countryName=country_name_from_list(countryID)
		if countryName == nil or blacklist[countryID] then
			countryName = mw.wikibase.getSitelink(countryID)
		end
		if uciCode and countryName then
			return ' <small>([['..countryName..'|'..uciCode..']])</small> '
		end
	end
	return '' --else
end

local function jersey_infobox( winner_classification, item, timeOfRace)
	local jersey, jersey_name = '', ''
	local jerseyWPID = ''

	-- 1. Item of race, e.g. Tour de France = 'Q33881'
	-- 2. type of winner, names are the ones in variable t_s
	-- 3. and 4. start and end time. '+2500' means year 2500. Always beginning with a '+'
	-- 5. item of the jersey
	-- 6. item of the Wikipedia article of that jersey

	--timeOfRace = '+1968-07-01T00:00:00Z'
	timeOfRace = string.match(timeOfRace, "+%d%d%d%d") or ''
	for _, v in pairs(item) do
		for _, value in pairs(data.stageinfobox_jersey) do
			if v == value[1] then
				if winner_classification == value[2] then
					if (timeOfRace >= value[3]) and (timeOfRace <= value[4]) then
						jersey = value[5]
						jerseyWPID = value[6]
					end
				end
			end
		end
	end

	-- local starttime, endtime = '', '+2500'
	if jersey ~= '' then --and (timeOfRace > starttime) and (timeOfRace < endtime) then
		local entity_jersey = mw.wikibase.getEntity(jersey)
			jersey = entity_jersey.claims['P18'][1].mainsnak.datavalue.value
			jersey_name = entity_jersey:getLabel(wikilang) or ''
		if jerseyWPID ~= '' then
			local entity = mw.wikibase.getEntity( jerseyWPID )
			local Sitelink = entity:getSitelink(wiki..'wiki') -- link to WParticle
			if Sitelink ~= nil then jerseyWPID = wiki..':'..Sitelink else jerseyWPID = '' end
		end
		return jersey, jersey_name, jerseyWPID
	else return '', '', ''
	end
end

local function jersey(h)
	local jersey_string = ' '
	local jerseys = {
	['Q24257871'] = {file = 'Jersey yellow.svg',
		name_ar = 'قميص أصفر لمتصدر الترتيب العام',
		name_fr = 'maillot jaune de leader du classement général',
		name_es = 'maillot amarillo de líder de la clasificación general',
		name_ru = 'жёлтая майка лидера генеральной классификации'
		},
	['Q24645209'] = {file = 'Jersey green.svg',
		name_ar = 'قميص أخضر لمتصدر ترتيب النقاط',
		name_fr = 'maillot vert de leader du classement par points',
		name_es = 'maillot verde de líder de la clasificación por puntos',
		name_ca = 'mallot verd del líder de la classificació per punts',
		name_ru = 'зелёная майка лидера очковой классификации'
		},
	['Q640430'] = {file = 'Jersey white.svg',
		name_ar = 'قميص أبيض لمتصدر ترتيب الشباب',
		name_fr = 'maillot blanc de leader du classement du meilleur jeune',
		name_es = 'maillot blanco de líder de la clasificación de los jóvenes',
		name_ru = 'белая майка лидера молодёжной классификации',
		name_de = 'weißes Trikot des Führenden der Nachwuchswertung'
		},
	}

	if type(h) == 'table' and h[1] then
		for _, v in ipairs(h) do
			local jersey_name
			if jerseys[v] then
				jersey_string = jersey_string .. '[[File:' .. jerseys[v].file .. '|20px'
				jersey_name = jerseys[v]['name_' .. wiki] or mw.wikibase.getLabel(v) or jerseys[v]['name_fr']
				if jersey_name then
					jersey_string = jersey_string .. '|' .. jersey_name
				end
				jersey_string = jersey_string .. ']]'
			else
				local p18 = mw.wikibase.getBestStatements(v, 'P18')
				if p18[1] and p18[1].mainsnak.snaktype == 'value' then
					jersey_string = jersey_string .. '[[File:' .. p18[1].mainsnak.datavalue.value .. '|20px'
					jersey_name = getLabelFallback(v)
					if jersey_name then
						jersey_string = jersey_string .. '|' .. jersey_name
					end
					jersey_string = jersey_string .. ']]'
				end
			end
		end
	end
	return jersey_string
end -- function end

--=== E) Other (winner) ===
local function isHuman(riderId)
	local isHuman = false
	if riderId then
		local p31 = wikibase.getBestStatements(riderId, 'P31')
		for _, iOf in pairs (p31) do
			if iOf.mainsnak.snaktype == 'value' and iOf.mainsnak.datavalue.value.id == "Q5" then
				isHuman = true
				break
			end
		end
	end
	return isHuman
end

local function isCountry(inputID)
	local isCountry = false
	if inputID then
		local p31 = wikibase.getBestStatements(inputID, 'P31')
		for _, iOf in pairs (p31) do
			-- exception Hong-Kong and Taiwan
			if iOf.mainsnak.snaktype == 'value' and (iOf.mainsnak.datavalue.value.id == "Q6256" or iOf.mainsnak.datavalue.value.id =="Q15634554" or iOf.mainsnak.datavalue.value.id =="Q779415") then
				isCountry = true
				break
			end
		end
	end
	return isCountry
end

local function isWomenrace(raceID) --for translation
	for _, p2094 in statements(raceID, 'P2094') do 
		if p2094.mainsnak.datavalue.value.id == "Q1451845" then
			return true
		end
	end
	return false
end

local function isWomenteam(teamID, timeOfRace)
	if isWomenrace(teamID) then --simplest way
		return true
	end
	--else we can identify with teamCat
	local _, catID= getTeamLinkCat(teamID, timeOfRace, false)
	if data.womenCats[catID] then
		return true
	end
	return false
end

local function getNationality(wID, timeOfRace,q) --for a rider
	local p27, countryID
	--allow overload of the property, for cases like Russian/BLR ban, or Commonwealth games, only for P1532
	if q and q.P1532 and q.P1532[1].snaktype == 'value' then
		countryID = q.P1532[1].datavalue.value.id
	else
		local listOfProperty={'P1532','P27'}
		if wID then
			for _, prop in ipairs(listOfProperty) do
				if countryID==nil then
					p27 = getStatementForTime(wID, prop, timeOfRace) --P27 is country of citizenshi
					if p27 then
						countryID = p27.mainsnak.datavalue.value.id
					end
				end
			end
		end
		
		if wiki=='eu' and (countryID=="Q142" or countryID=="Q29") then --look for people or location in the Basque Country, quite expensive function
			local birth_place = firstValue(wID, 'P19','id') --birth place
			if data.BasqueTown[birth_place] then
				return "Q47588"
			end
		end
	end
	return countryID
end

local function subwinner(riderId, timeOfRace, q)
	local outTable={}
	local riderTeam, riderLink, countryID

	if riderId then
		if isHuman(riderId) then
			riderLink = getRiderLink(riderId, timeOfRace)
			countryID = getNationality(riderId, timeOfRace,q)
			if countryID then
				riderLink = flag(countryID, timeOfRace) .. ' ' .. riderLink
			end
			riderTeam = getTeam(riderId, timeOfRace, q) or ''
		else
			local _
			riderLink, _, countryID = getTeamLinkCat(riderId, timeOfRace, true)
			if countryID then
				riderLink = flag(countryID, timeOfRace) .. ' ' .. riderLink
			end
		end
	end
	return riderLink, riderTeam
end

local function winner(lf,raceID, winners, timeOfRace, country, WDlink_on, team, ref, winnersId)
	local p1346 = wikibase.getAllStatements(raceID, 'P1346') -- P1346 is 'winner'
	for _, winner in pairs(p1346) do
		local wID = winner.mainsnak.snaktype == 'value' and winner.mainsnak.datavalue.value.id
		local wOf, wCause, wCriterion, riderLink
		local q = winner.qualifiers
		if q then
			local _, disqualified =isdisqualified(winner,q)
			local propertyOf=nil
			if q.P2501 and q.P2501[1].snaktype == 'value' then
				propertyOf=q.P2501 --result
			elseif q.P828 and q.P828[1].snaktype == 'value' then --cause, for cancellation
				propertyOf=q.P828
			elseif q.P642 and q.P642[1].snaktype == 'value' then
				propertyOf=q.P642 --fallback
			end
			
			if propertyOf and propertyOf[1].snaktype == 'value' then
				for _, qprop in pairs(propertyOf) do
					wOf = qprop.datavalue.value.id 
					if not wOf then
						-- Try P1346 (winner) instead
						-- Assume Q20882667 ('overall winner general classification') if neither are found
						wOf = q.P1346 and q.P1346[1].snaktype == 'value' and q.P1346[1].datavalue.value.id or 'Q20882667'
					end
					wCause = q.P828 and q.P828[1].snaktype == 'value' and q.P828[1].datavalue.value.id
						-- P828 is 'has cause'
					wCriterion = q.P1013 and q.P1013[1].snaktype == 'value' and q.P1013[1].datavalue.value.id
						-- P1013 is 'criterion used'

					if winners[wOf] then
						if wID then
							local reference = ref and getReference(lf,winner)
							local _, countryID
							if isHuman(wID) then
								riderLink = getRiderLink(wID, timeOfRace)
								if reference then
									riderLink = riderLink .. reference
								end
								if team then
									local riderTeam = getTeam(wID, timeOfRace, q)
									if riderTeam then
										riderLink = riderLink .. ' (' .. riderTeam .. ')'
									end
								end
							elseif isCountry(wID) then
								riderLink = flag(wID, timeOfRace).." "..getCountryName(wID) 
								if reference then
									riderLink = riderLink .. reference
								end
								country=true	
							else --team
								local _
								riderLink, _, countryID = getTeamLinkCat(wID, timeOfRace, country)
								if reference then
									riderLink = riderLink .. reference
								end
							end
							if not country then
								if not countryID then
									if isHuman(wID) then
										countryID = getNationality(wID, timeOfRace,q)
									else
										countryID = getCountryID(wID, timeOfRace)
									end
								end
								if countryID then
									riderLink = flag(countryID, timeOfRace) .. ' ' .. riderLink
								end
							end
							if WDlink_on then
								riderLink = riderLink .. ' ' .. wdLink(wID)
							end
						else
							riderLink = wCriterion and contentLanguage:ucfirst(wikibase.getLabel(wCriterion) or '') or ''
							if wCause then
								local cause = wikibase.getLabel(wCause)
								if cause then
									riderLink = riderLink .. ' (' .. cause .. ')'
								end
							end
						end
						if disqualified==true then
							riderLink='<s>'..riderLink..'</s>'
						end
						if winnersId and winnersId[wOf] then
							if disqualified or ((not wID) and wCriterion) then 
								winnersId[wOf]= 'Q666' --to identify disqualification
							else
								winnersId[wOf]= wID --identify cancelled
							end
						end
						if winners[wOf] == '' then
							winners[wOf] = riderLink
						else
							winners[wOf] = winners[wOf] .. '<br/>' .. riderLink
						end
					end
				end
			end
		end
	end
end

local function sortAndConcat(t_Body, resultTable)
	table.sort(t_Body, function(a, b) return a['sortkey'] < b['sortkey'] end)
	for _, m in ipairs(t_Body) do resultTable:node(m['body']) end
	return resultTable
end

--------- Definition sub-functions for calendar and victory ------
local function getTimeOfRace(raceID, mandatory, p582_prio)
	local timeOfRace, properties
	if p582_prio then --for case like  UCI Europe Tour 2006 (Q1455600) where most of the competition is in the next year
		properties={'P582','P585','P580'}
	else
		properties={'P580','P585','P582'}
	end
	
	for _, prop in ipairs(properties) do
		timeOfRace= firstValue(raceID, prop, 'time')
		if timeOfRace ~= nil then return timeOfRace end
	end

	local link = getSitelinkFallback(raceID, {'en', 'fr', 'de','es'}) --language is not important here, it is just to get the year
	if link then
		local year = string.match(link, '%d%d%d%d')
		if year then
			return year .. '-01-01T00:00:00Z'
		end
	end
	if wiki == "ar" then
		return '+1970-01-01T00:00:00Z'
	end
	if mandatory then
		error('> Wikidata is missing data about start time (P580) or point in time (P582)')
	end
	return nil
end

local function get_formatted_date(entityID, functionName)
	local sTime = firstValue(entityID, 'P580', 'time') -- P580 is 'start time'
	local eTime = firstValue(entityID, 'P582', 'time') -- P582 is 'end time'
	
	local style1, style2 
	if functionName=="infobox" then
		style1='verylong' --force to display the year
		style2='long'
	else
		style1='small'
		style2='small'
	end
	
	if sTime and eTime then
		local startTime, endTime = getStartEndTime(sTime, eTime, style1)
		if functionName==nil or functionName=='infobox' then --calendar, infobox
        	return startTime .. ' – ' .. endTime, sTime, true
        else --victory, general classification
        	return endTime, eTime, true
		end
	else
		local pTime = firstValue(entityID, 'P585', 'time') -- P585 is 'point in time'
		if pTime then
			return funcDate(pTime, style2), pTime, false
		end
	end
	return nil
end

local function fn_date(entityID, functionName)  --to move as a general function
	local tempdate, timeOfRace, _ = get_formatted_date(entityID, functionName) --is there a reason why timeofrace cannot be sTime??

	local _, _, y, m, d = string.find(timeOfRace or "", "(%d+)-(%d+)-(%d+)")
	local sortkey=(y or '')..(m or '')..(d or '')
	if sortkey =='' then sortkey = '0000' end

	local tCell = mw.html.create('td'):attr('data-sort-value',sortkey)
	:cssText("style=text-align:right;padding:0 0.5em")
	:wikitext(tempdate)

	return timeOfRace, tostring(tCell), sortkey
end

local function fn_country(entityID, timeOfRace,country, raceCell, parentID)
	-- This function gives countries where the race take place
	-- parentID taken from fn_race, optional
	local country_str, country_name, country_flag
	local cssCell="text-align:" .. textalign .. ";padding:0 0.5em"
	local tCell= mw.html.create('td'):cssText(cssCell)

	local countryID = getCountryID(entityID, timeOfRace)
	if countryID==nil then countryID = getCountryID(parentID, timeOfRace) end
	
	if countryID then
		country_flag=flag(countryID, timeOfRace)
		country_str=country_flag
		country_name = getCountryName(countryID)
		if country_name~='' then
			tCell:attr('data-sort-value',country_name)
			if country~= false then 
				country_str=country_str.." "..country_name
			end
		end
	else
		country_flag="no flag"
	end

	if country==false then
		tCell:wikitext(country_flag.." "..(raceCell or ''))
		country_name=''
	else
		if country_str then 
			tCell:wikitext(country_str) 
		end
	end
	return country_flag, country_name, tCell
end

local function commaStage(stageID,raceLabel) --how to write "stage, "
	local outTable={}
	local stageNumber=''
	local subStage = ''
	local stageNumberonly, stageLetter

	local temp=firstValue(stageID, 'P1545')
	if temp then stageNumber = temp end

	if stageNumber=='0' then --prologue
		stageNumber= translate("victories",9)
	else
		if stageNumber==nil then
			stageNumber= translate("victories",8)
		else
			--look for subStage
			local i,j = string.find(stageNumber, "%a+") --if letter in the stage number
			if i ~= nil then --we have to do something
				local k,l = string.find(stageNumber, "%d+") --select the number in the stage number
				stageNumberonly = string.sub(stageNumber, k, l)--cut the string in 2
				stageLetter = string.sub(stageNumber, i, j)
				stageNumber=stageNumberonly
				if stageLetter ~= nil then subStage=stageLetter end
			end
			if wiki == 'ar' then
				stageNumber= translate("victories",8)..' '..number('f', tonumber(stageNumber), wiki)
			else
				stageNumber= number('f', tonumber(stageNumber), wiki)..subStage..' '..translate("victories",8)
			end
		end
	end

	local comma = ", "
	if wiki == 'ar' then comma = " ، " end
	if wiki == 'fr' then
		local correpondance={
		{name="^Trois", article= " des "},
		{name="^Quatre", article= " des "},
		{name="^Boucles", article= " des "},
		{name="^Triptyque", article= " du "},
		{name="^Tour", article= " du "},
		{name="^Grand Prix", article= " du "},
		{name="^Circuit", article= " du "},
		{name="^Mémorial", article= " du "},
		{name="^Trophée", article= " du "},
		{name="^Ronde", article= " de la "},
		{name="^Semaine", article= " de la "},
		{name="^Classica", article= " de la "},
		{name="^Flèche", article= " de la "},
		{name="^Course", article= " de la "},
		{name="^Classique", article= " de la "},
		{name="Race", article= " de la "},
		{name="^Étoile", article= " de l'"},
		{name="^La", article= " de "}
		}

		for _, v in ipairs(correpondance) do
			if string.find(raceLabel, v.name) then
				comma = v.article
				break
			end
		end
	end

	if wiki == 'fr' or wiki=="ca" or wiki=="es" or wiki=="ast" then
		outTable["prefix"]=stageNumber..comma
		outTable["postfix"]=''
	else
		--if wiki=="de" or wiki=="da" or wiki=="fo" or wiki == "lb" or wiki=="no" or wiki=="ru" or wiki=="ar" or wiki=="lv" or wiki=="pl" then
		outTable["prefix"]=''
		outTable["postfix"]=comma..stageNumber
	end
	return outTable
end

local function getMainRaceLink(entityID,entity_type,stageID, functionName,timeOfRace) --the link to the edition but with a general name
	local instanceOf, instanceOfTemp, label, Sitelink, isclass, prefix, postfix
	local arlabel
	local stage_link=false
	
	if stageID then
		Sitelink=wikibase.getSitelink(stageID)
		if Sitelink then stage_link=true end
	end
	if Sitelink==nil then
		Sitelink=wikibase.getSitelink(entityID)
	end
	prefix=''; postfix='' --general classification
	listOfProperty={'P2561','P1448'}
    
    --main race link is in the parent	--can be improved
	for _, p31 in statements(entityID, 'P31') do
		instanceOfTemp = p31.mainsnak.datavalue.value.id
		if instanceOfTemp ~= "Q27020041" and instanceOfTemp ~= 'Q88903067' and data.class_dic[instanceOfTemp]==nil then	--but the main race
			instanceOf=instanceOfTemp
		end
	end

    --get information from the parent
	if instanceOf then
		--look for
		for _, prop in ipairs(listOfProperty) do
			for _, p2561 in statements(instanceOf, prop) do --name for championship
				if label==nil then
					local lang_WD = p2561.mainsnak.datavalue.value.language
					if wiki == lang_WD then
						local nametemp = p2561.mainsnak.datavalue.value.text
						if timeOfRace~= nil then
							local q = p2561.qualifiers
							if q then
								local temp = checktime(nametemp,q,timeOfRace)
								if temp then label = nametemp end--if the time is correct than it is finished
							else
								label = nametemp
								arlabel = label
							end
						end
					end
				end
			end
		end

		if label==nil then
			label=getLabelFallback(instanceOf,lang_priority) --the case of 'ar' should be handled in lang_priority
			if not label then
				label=getLabelFallback(entityID,lang_priority) or ''
			end
		end
		if Sitelink==nil and entity_type~=0 then --only if no link to the race direct
			Sitelink=wikibase.getSitelink(instanceOf)
		end
		if Sitelink==nil and entity_type==0 then --only for champ
			local temp=firstValue(entityID, 'P361','id') --temp is NC France 2019 for instance
			if temp then 
				Sitelink= wikibase.getSitelink(temp) 
			end
			if Sitelink == nil then
				local temp2=firstValue(entityID, 'P31','id') -- French NC Men ITT
				if temp2 then
					Sitelink= wikibase.getSitelink(temp2)  
					if Sitelink == nil then
						local temp3=firstValue(temp2, 'P361','id') -- French NC ITT
						if not temp3 then temp3=firstValue(temp2, 'P31','id') end
						if temp3 then
							Sitelink= wikibase.getSitelink(temp3)  
							if Sitelink == nil then
								local temp4=firstValue(temp3, 'P361','id') -- French NC 
								if not temp4 then temp4=firstValue(temp3, 'P31','id') end
								if temp4 then
									Sitelink= wikibase.getSitelink(temp4)  
								end
							end
						end
					end
				end
			end	
		end
	end
	--affect the label
	if label==nil then
		label=getLabelFallback(entityID,lang_priority) or ''
	end
	--look for link to the race if nothing
	--if different languages have to be added, a language table can be created
	if entity_type==2 then
		if functionName~=nil then --calendar=nil
			if wiki == 'fr' then prefix= translate("victories",1)..', ' --general classification
			elseif wiki == 'ar' then postfix ='، '..translate("victories",1)
			else postfix = ', '..translate("victories",1)
			end
		end
	elseif entity_type=='stage' then
		--how to write "stage, " is concentrated in one function
		local commaTable=commaStage(stageID, label)
		prefix= commaTable["prefix"]
		postfix=commaTable["postfix"]
	end

	if Sitelink == nil then
		if wiki == 'ar' then 
			label = make_IllWD2_link(entityID,arlabel,label)
		end
		return prefix..label..postfix
	elseif stage_link then
		return '[['..Sitelink..'|'..prefix..label..postfix..']]'
	else
		return prefix..'[['..Sitelink..'|'..label..']]'..postfix
	end
end

--look for the circuitID to create a link as [[World Tour|1.UWT]]
--a bit redundant with classLink which needs less computation
--for infobox classLink gives enough info
local function classToCircuit(classID, entityID, child, q) 
	local displayedCircuitID, circuitID
	
	if classID then
		if classID=='Q23005601' or classID=='Q23005603' then --1WWT 2WWT clear
			displayedCircuitID = 'Q21075974'
		elseif classID=='Q22231106' or classID=='Q22231107' then --1UWT 2UWT clear
			displayedCircuitID = 'Q635366'
		else --we have to look in the item
			if child then --for instance Flèche wallonne 2020
				for _, p361 in statements(entityID, 'P361') do
					circuitID = p361.mainsnak.datavalue.value.id
					for _, p31 in statements(circuitID, 'P31') do --is it a UCI circuit?
						parentCircuitID = p31.mainsnak.datavalue.value.id
						if data.UCI_Circuits[parentCircuitID] then
							displayedCircuitID=circuitID
						end
					end
				end
			else --for instance Flèche wallonne
				if q then
					if q.P118 and q.P118[1].snaktype == 'value' and q.P118[1].datavalue.value.id then --fallback
						displayedCircuitID =  q.P118[1].datavalue.value.id
					elseif q.P642 and q.P642[1].snaktype == 'value' and q.P642[1].datavalue.value.id then --fallback
						displayedCircuitID =  q.P642[1].datavalue.value.id
					end
				end
			end
		end
	end
	return displayedCircuitID
end

local function getStartEndfromQuali(q) --return sTime and eTime as date
	local sTime, eTime
	if q then
		if q.P580 and q.P580[1] and q.P580[1].snaktype == 'value' then -- P580 is start time
			sTime = q.P580[1].datavalue.value.time
		end
		if q.P582 and q.P582[1] and q.P582[1].snaktype == 'value' then -- P582 is end time
			eTime = q.P582[1].datavalue.value.time
		end
	end
	return sTime, eTime
end

local function funcDateFigure(date,mode)
	local y, m = string.match(date, "(%d+)-(%d+)-%d+")
	
	if mode=='Y' or m=='00' or not m then
		return y
	elseif y then
		return string.gsub(m,'0','').."."..y
	else
		return nil
	end
end

local function getPeriodSubSub(sTime, eTime, startTime,endTime,brackets)
	local period
	if sTime and eTime then
		if startTime==endTime then
			period=startTime --only (1990)
		else
			period=startTime .. '-'..endTime
		end
	elseif sTime then
		period=startTime .. '-'
	elseif eTime then
		period='-'..endTime
	else
		period=""
	end
	
	if brackets and period~="" then
		period="("..period..")"
	end
	return period
end
	
local function getPeriodSub(sTime, eTime, brackets) 
	local startTime, endTime, y, m, y2, m2

	if sTime then
		y, m = string.match(sTime, "(%d+)-(%d+)-%d+")
		if m=='00' or m=='01' then 
			startTime= funcDateFigure(sTime, 'Y')
		else
			startTime= funcDateFigure(sTime,'m') 
		end
	end
	
	if eTime then
		y2, m2 = string.match(eTime, "(%d+)-(%d+)-%d+")
		if m2=='00' or m2=='12' then
			endTime=funcDateFigure(eTime, 'Y')
		else
			endTime=funcDateFigure(eTime, 'm')
		end
	end
	return getPeriodSubSub(sTime, eTime, startTime,endTime,brackets)
end

local function getPeriodSub_season(sTime, eTime, brackets) 
	local startTime, endTime
	if sTime and eTime then
		startTime, endTime = getStartEndTime(sTime, eTime, 'small')
	elseif sTime then
		startTime=funcDate(sTime, 'small')
	elseif eTime then
		endTime=funcDate(eTime, 'small')
	end
	return getPeriodSubSub(sTime, eTime, startTime,endTime,brackets)
end
-- for display period with only year, for instance (2020-2021)
local function getPeriod(q, brackets,season)
	local sTime, eTime = getStartEndfromQuali(q)
	if season then
		return getPeriodSub_season(sTime, eTime, brackets), sTime
	else
		return getPeriodSub(sTime, eTime, brackets), sTime
	end
end

-- For infobox
local function getClass(entityID)
	local classLink, circuitID, circuitLink
	local classTable={}

	for ii, p279 in statements(entityID, 'P279') do
		if p279 and p279.mainsnak.snaktype == 'value' then
			local classID = p279.mainsnak.datavalue.value.id

			if data.class_dic[classID]~=nil then 
			    circuitID=classToCircuit(classID, entityID, false, p279.qualifiers) 
			    classLink=classLinkFn(classID,circuitID)
			    if classLink then
			    	local period, sTime=getPeriod(p279.qualifiers, true)
			    	local classStr = classLink .. " <small>"..period.."</small>"
					table.insert(classTable, {sTime, classStr, circuitID})
				end
			end
		end
	end
	if #classTable~=0 then
		table.sort(classTable, function(a, b) return a[1] < b[1] end)
	end
	for _, class in pairs(classTable) do
		if not str then str='' else str=str..'<br>' end
		str=str..class[2]
		if class[3] then
			circuitLink=WPlinkpure(class[3])
		end
	end
    return str, circuitLink, #classTable
end

local function fn_race(entityID,displayed_class,display_class,timeOfRace, functionName,country)--return link to the race and class
	--first function read from victory main
	local Sitelink, entity_type, classID, stageID, race_tCell, class_tCell, parentID

	for _, p31 in statements(entityID, 'P31') do
		if data.stages[p31.mainsnak.datavalue.value.id] then
			entity_type = 'stage'  --then the class is one stage above!
			parentID = getParentID(entityID)
			classID=firstValue(parentID, 'P279', 'id') 
			stageID= entityID --everything slide from one rank
			entityID = parentID
		end
	end
	--Now we have the class and know the type of race it is
	if entity_type == 'stage' then
		Sitelink=getMainRaceLink(entityID,entity_type,stageID, functionName,timeOfRace)
	else
		classID=firstValue(entityID, 'P279', 'id')
		Sitelink=getMainRaceLink(entityID,data.class_dic[classID],nil, functionName,timeOfRace)
	end
	
	if country~=false then
		local tCell=mw.html.create('td'):cssText("text-align:".. textalign ..";padding:0 2.3em"):wikitext(Sitelink)
		race_tCell=tostring(tCell)
	else
		race_tCell=Sitelink --already opened
	end
	
	if display_class == true and classID~=nil and (displayed_class==nil or displayed_class[classID]~=nil) then
		local circuitID=classToCircuit(classID, entityID, true,nil) 
		local classLink=classLinkFn(classID,circuitID) --return '' worst case

		class_tCell=mw.html.create('td')
		:attr('data-sort-value',data.class_sort[classID]) --sortkey
		:cssText("text-align:center;padding:0 0.5em")
		:wikitext(classLink)
	end
	return parentID, race_tCell, class_tCell
end

local function fn_rider(lf,entityID,timeOfRace,display_team,only_winner,country)
	local winners, countrytemp, result
	local WDlink_on = (wiki == "mk" or wiki == "ja")
	local thereisawinner=false
	
	if only_winner == 1 then
		winners = {Q20882667 = '', Q20882747=''} -- first, general or stage
	elseif only_winner == 0 then
		winners = { Q20882667 = '', Q20882668 = '',Q20882669 = ''} -- Q20882668 is 'second overall'
	else --3
		winners = { Q47640757='' } -- World Tour -- name not used here
	end
	if country==nil then countrytemp=false else countrytemp=country end
	winner(lf,entityID, winners, timeOfRace, countrytemp, WDlink_on, display_team, true)
	
	local tCell=mw.html.create('td'):css("text-align:".. textalign ..";padding:0 0.5em")
	
	if only_winner == 0 then
		tCell:wikitext(winners.Q20882667)
		result=tostring(tCell)
		tCell=mw.html.create('td'):css("text-align:".. textalign ..";padding:0 0.5em"):wikitext(winners.Q20882668)
		result=result..tostring(tCell)
		tCell=mw.html.create('td'):css("text-align:".. textalign ..";padding:0 0.5em"):wikitext(winners.Q20882669)
		return result..tostring(tCell)
	else
		local tempwinner
		if only_winner == 1 then
			if winners.Q20882667~=nil and winners.Q20882667~='' then
				tempwinner=winners.Q20882667
			else
				tempwinner=winners.Q20882747
			end
		else
			tempwinner=winners.Q47640757
		end
		if tempwinner~='' and tempwinner~=nil then thereisawinner=true end
		return tCell:wikitext(tempwinner), thereisawinner
	end
end

local function compareDate(tdate) --test future
	if tdate then
		local today=os.date("*t") 
		local _, _, y, m, d = string.find(tdate, "(%d+)%p(%d+)%p(%d+)")
		local tYear=tonumber(y)
		local tMonth=tonumber(m)
		local tDay=tonumber(d)
		
		if tYear>today['year'] then
			return true
		elseif tYear<today['year'] then
			return false  --the last race is the future
		else
			if tMonth>today['month'] then
				return true
			elseif  tMonth<today['month'] then
				return false
			else
				if tDay>today['day'] then	
					return true
				elseif  tDay<today['day'] then	
					return false
				else
					return false --arbitrary
				end
			end
		end
	else
		return false --arbitrary
	end
end

local function calculateAge(birthDate, endDate) --test future
	local eYear, eMonth, eDay
	local longestcontractyears=10
	if birthDate then
		if not endDate then
			local today=os.date("*t") 
		    eYear=today['year']
		    eMonth=today['month']
		    eDay=today['day']
		else
			local _, _, y, m, d = string.find(endDate, "(%d+)%p(%d+)%p(%d+)")
			eYear=tonumber(y)
			eMonth=tonumber(m)
			eDay=tonumber(d)
		end

		local _, _, y, m, d = string.find(birthDate, "(%d+)%p(%d+)%p(%d+)")
		local tYear=tonumber(y)
		local tMonth=tonumber(m)
		local tDay=tonumber(d)
		local alreadyThisYear

		if eMonth>tMonth then
			alreadyThisYear=true	
		elseif  eMonth<tMonth then
			alreadyThisYear=false
		else
			if eDay>tDay then	
				alreadyThisYear=true
			elseif  eDay<tDay then	
				alreadyThisYear=false
			else
				alreadyThisYear=true
			end
		end
		
		if alreadyThisYear then
			return eYear-tYear, tYear, eYear+longestcontractyears
		else
			return eYear-tYear-1, tYear, eYear+longestcontractyears
		end
	else
		return 0, tYear, eYear+longestcontractyears
	end
end
			

local function evaluateWinnerMax(t)
	local winners = t.vainqueur
	local result
	local most_wins = 0
	local most_wins_ID = {}
	for winnerID, winner in pairs(winners) do
		if winner.count > most_wins then
			most_wins = winner.count
			most_wins_ID = { winnerID }
		elseif winner.count == most_wins then
			most_wins_ID[#most_wins_ID + 1] = winnerID
		end
	end

	if most_wins > 1 then
		for _, id in pairs(most_wins_ID) do
			if not result then
				result=winners[id].link
			else
				result=result.."<br>"..winners[id].link
			end
		end
		
		local _, gen_singular, gen_plural=plural(most_wins)
		if gen_singular then --slavic plural, 1 victory is not displayed
			word_victory=translate("raceinfobox",29)
		elseif gen_plural then
			word_victory=translate("raceinfobox",30)
		else
			word_victory=translate("raceinfobox",32) --singular
		end
		result=result.."<br>("..tostring(most_wins).." "..word_victory..")"
	end
	t.maxWinner=result
end

local function listOfWinners(itemID,t, team,lf, mandatory_prop)
	local winners = {	Q20882667 = '',}-- Q20882667 is 'overall winner general classification'
	local winnersId={	Q20882667 = '',}--to detect disqualification
	local WDlink_on, sitelink

	if wiki == "mk" or wiki == "ja" or wiki == "ru" then WDlink_on = true else WDlink_on = false end

    -- Get the date to sort the editions
	for _, p527 in statements(itemID, 'P527') do  --_, p527
		local raceDate, year, raceID, entity_race, a, b 
		raceId = p527.mainsnak.datavalue.value.id -- Qnumbers of the parts of a tour
		raceDate=getTimeOfRace(raceId)
		table.insert(t.race, { raceId=raceId, raceDate=raceDate, future=compareDate(raceDate)} ) --check if future
		table.sort(t.race, function(a,b) return a['raceDate'] < b['raceDate'] end) -- t.race is sorted after year
	end 
	--look for the next race
	local lastRunEdition, lastEditionDate, nextEdition
	
	for num, race in ipairs(t.race) do
		if race['future'] then
			nextEdition=num
			break
		end
	end
		--Get the winners
	local numberOfEditions=0
	local lastWinner, winnerId

	if not team then --for race, a test shall be performed
		for num=1,#t.race do
			winners.Q20882667=''
			winnersId.Q20882667=''
			winner(lf,t.race[num]['raceId'], winners, t.race[num]['raceDate'], false, WDlink_on, nil, nil, winnersId )
			if t.race[num]['future']==false then --in the past
				if winnersId.Q20882667~="Q30108381" and winnersId.Q20882667~="Q54806642" then --cancelled
					numberOfEditions=numberOfEditions+1
					lastRunEdition=num
					lastEditionDate=t.race[num]['raceDate']
					lastWinner=winners.Q20882667
				end
			end
		
			winnerId=winnersId.Q20882667
			if winnerId~=nil and winnerId~='' and winnerId~='Q666' and winnerId~='Q30108381' and winnersId.Q20882667~="Q54806642" then --code for disqualification
				if not t.vainqueur[winnerId] then
					t.vainqueur[winnerId]={}
					t.vainqueur[winnerId].link=winners.Q20882667
					t.vainqueur[winnerId].count=0
				end
				t.vainqueur[winnerId].count=t.vainqueur[winnerId].count+1
			end	
		end
	else --for team the check is lighter
		for num=1,#t.race do
			if t.race[num]['future']==false then --in the past
				if mandatory_prop==nil then
					numberOfEditions=num
					lastRunEdition=num
					lastEditionDate=t.race[num]['raceDate']
				else
					local ss = wikibase.getAllStatements(t.race[num]['raceId'], mandatory_prop)
					if #ss >0 then
						numberOfEditions=num
						lastRunEdition=num
						lastEditionDate=t.race[num]['raceDate']
					end
				end
			end
		end		
	end

	local monthId=firstValue(itemID, 'P2922','id') 
	if monthId then 
		t.lastEditionMonth=getLabelFallback(monthId) or ''
	else
		t.lastEditionMonth=contentLanguage:formatDate("M", lastEditionDate)
	end

	if lastEditionDate then
		t.lastEditionYear=funcDate(lastEditionDate,"onlyyear")   
	end
	t.numberOfEditions=numberOfEditions
	if not team then evaluateWinnerMax(t) end
	
	if lastRunEdition then
		t.lastWinner=lastWinner or '' --t.vainqueur[lastRunEdition]['link']
		t.lastID=t.race[lastRunEdition]['raceId']
		sitelink = wikibase.getSitelink(t.lastID)
		if sitelink ~= nil then
			t.lastLink = "[[" .. sitelink .. "]]"
		else
			t.lastLink = nil
		end
	end
	
	if nextEdition then 
		t.nextID=t.race[nextEdition]['raceId']
		sitelink = wikibase.getSitelink(t.nextID)
		if sitelink ~= nil then
			t.nextLink = "[[" .. sitelink .. "]]"
		else
			t.nextLink = nil
		end
	end	
end

local function getPeriodicity(itemID, t)
	local p = wikibase.getBestStatements(itemID, 'P2257')
	if p[1] and p[1].mainsnak.snaktype == 'value' then
		local period=p[1].mainsnak.datavalue.value.amount
		local periodunit=p[1].mainsnak.datavalue.value.unit
		if tonumber(period)==1 and periodunit == 'http://www.wikidata.org/entity/Q577' then
			return translate("raceinfobox",1).." ("..t.lastEditionMonth ..")"
		elseif tonumber(period)==1 and periodunit == 'http://www.wikidata.org/entity/Q5151' then
			return translate("raceinfobox",2)
		else
			return nil
		end
	else
		return nil
	end
end

local function getType(itemID)
	local result, typeID
	typeID =firstValue(itemID, 'P31', 'id')
	if typeID ~= nil then
		if typeID=="Q2912397" and wiki=="fr" then
			result="[[Cyclisme_sur_route#Épreuve_d'un_jour|Course d'un jour]]"
		else
			result=WPlinkpure(typeID)
		end
	end --else result=nil
   	return result  
end

local function getFormerNames(itemID, PID, season)
	local listOfNames={}
	local officialname,language

	local kk=1
	while #listOfNames == 0 and kk<=#lang_priority do
		lang=lang_priority[kk]
		kk=kk+1
		for _, prop in ipairs({PID}) do
			for _, p1813 in statements(itemID, prop) do
				language = p1813.mainsnak.datavalue.value.language
				officialname = p1813.mainsnak.datavalue.value.text
				if lang==language then --only exact language
					local period, sTime=getPeriod(p1813.qualifiers, nil, season)
					if not sTime then sTime="+1900-01-01T00:00:00Z" end --first
					table.insert(listOfNames,{sTime, period, officialname, language})
				end
			end
		end
	end			
	table.sort(listOfNames, function(a, b) return a[1] < b[1] end)
	return listOfNames
end

local function officialSite(itemID)
	local url=firstValue(itemID, 'P856')
	if url then 
		return '['..url.." "..translate("raceinfobox",3)..']'
	end
	return nil
end

local function checkkm(p)
	local km, unit
	if p[1] and p[1].mainsnak.snaktype == 'value' then
		km = tonumber(p[1].mainsnak.datavalue.value.amount)
		unit = p[1].mainsnak.datavalue.value.unit
		if unit == 'http://www.wikidata.org/entity/Q828224' then
			return km
		end
	end
	return nil
end

local function checkm(p, in_cm)
	local m, unit, res
	if p[1] and p[1].mainsnak.snaktype == 'value' then
		m = tonumber(p[1].mainsnak.datavalue.value.amount)
		unit = p[1].mainsnak.datavalue.value.unit
		if unit == 'http://www.wikidata.org/entity/Q11573' then
			res=m
		elseif unit=='http://www.wikidata.org/entity/Q174728' then --cm
			res=m*0.01
		end
		if res then
			if in_cm then
				res=res*100
			end
			return res
		end
	end
	return nil
end

local function checkkmh(p)
	if p[1] and p[1].mainsnak.snaktype == 'value' then
		kmh = tonumber(p[1].mainsnak.datavalue.value.amount)
		unit = p[1].mainsnak.datavalue.value.unit
		if unit == 'http://www.wikidata.org/entity/Q180154' then -- Q180154 is 'kilometre per hour'
			return kmh
		end
	end
	return nil
end

local function checkkg(p)
	local kg, unit
	if p[1] and p[1].mainsnak.snaktype == 'value' then
		kg = tonumber(p[1].mainsnak.datavalue.value.amount)
		unit = p[1].mainsnak.datavalue.value.unit
		if unit == 'http://www.wikidata.org/entity/Q11570' then
			return kg
		end
	end
	return nil
end

local function formatNumber(e, addUnit, trans)
	local text
	if e then
		text = contentLanguage:formatNum(e)
		if wiki == 'fo' then
			text = string.gsub(text, "%.", ",")
		end
		if addUnit then
			local t=translate("unit",trans)
			if string.find( t," ")==1 then
				text = text ..t
			else
				text = text .. ' ' ..t
			end
		end
	end
	return text
end


local function getHeight(entityID, in_cm)
	local p = mw.wikibase.getBestStatements(entityID, 'P2048')
	if in_cm then
		return formatNumber(checkm(p, in_cm), true, 11)
	else
		return formatNumber(checkm(p, in_cm), true, 9)
	end
end

local function getWeight(entityID)
	local p = mw.wikibase.getBestStatements(entityID, 'P2067')	
	return formatNumber(checkkg(p), true, 10)
end

local function getDistance(raceID, addUnit)
	local p = mw.wikibase.getBestStatements(raceID, 'P3157') -- P3157 is 'event distance'
	local km =checkkm(p)
	if not km then --for stage race we can sum the distances from each stage
		local stagep, tempkm
		for _, p527 in statements(raceID,'P527') do
			stagep=mw.wikibase.getBestStatements(p527.mainsnak.datavalue.value.id, 'P3157')
			tempkm=checkkm(stagep)
			if tempkm then
				if not km then km=0 end
				km=km+tempkm
			end
		end
	end
	return formatNumber(km, addUnit, 8), km
end

local function getElevation(raceID)
	local p =mw.wikibase.getBestStatements(raceID, 'P7297')
	return formatNumber(checkm(p), true, 9)
end

local function getSpeed(raceID, addUnit,kmdistance, property)
	local timeOfRace
	local p = mw.wikibase.getBestStatements(raceID, 'P2052') -- P2052 is 'speed'
	local kmh=checkkmh(p)

	if not kmh and kmdistance then --calculate speed
		local p2321= wikibase.getBestStatements(raceID, property) --winner supposed to be first of overall classification
		if p2321 and p2321[1] and p2321[1].mainsnak.snaktype == 'value' then
			local q = p2321[1].qualifiers
			if q and q.P1352 and q.P1352[1].snaktype == 'value' then --rank
				for _, q1352 in pairs(q.P1352) do
					rank = tonumber(q1352.datavalue.value.amount)
				end
				if rank == 1 then
					timeOfRace=qualifieramount(p2321[1], 'P2781') --get time
				end
			end

			if timeOfRace then
				kmh=math.modf(1000*kmdistance/(timeOfRace/3600))/1000
			end
		end
	end
	return formatNumber(kmh, addUnit, 5)
end

local function getGenderCode(riderID, default)
	local gender=default -- default is for teams, n or f
	local g = firstValue(riderID, 'P21', 'id')
	if g == 'Q6581097' then gender = 'm' -- Male
	elseif g == 'Q6581072' then gender = 'f' -- Female
	elseif g == 'Q1052281' then gender = 't' -- Transgenre
	end
	return gender 
end

function number(gender, b, wiki)
	local str
	if b==nil or b=="" then return "" end
	if wiki=="ar" then
		str = b
	elseif wiki == "ca" then
	if b==1 then str = b.."r"
		elseif b==2 then str = b.."n"
		elseif b==3 then str = b.."r"
		elseif b==4 then str = b.."t"
		else str = b.."è"
		end
	elseif wiki=="es" then
		if gender == 'm' or gender == 'n' then str = b..".º"
		elseif gender == 'f' then str = b..".ª"
		else str = b.."."
		end
	elseif wiki=="fr" then
		if b==1 then
			if gender == 'm' then str="1<sup>er</sup>"
			elseif gender == 'f' or gender == 'n' then str="1<sup>re</sup>"
			else str="1<sup>e</sup>"
			end
		else str=b.."<sup>e</sup>"
		end
	elseif wiki=="nl" then str=b.."e"
	elseif wiki=="ru" then str=b.."-й"
	elseif wiki=="eo" then str=b.."-a"
	elseif wiki=="ast" then
		if gender == 'm' or gender == 'n' then str = b.."ᵘ"
		elseif gender == 'f' then str = b.."ª"
		else str = b.."."
		end
	else str = b .. ". "
	end
	return str
end

local function calculateTime(t)
	local time = tonumber(t)
	local h, m, s = 0, 0, 0
	local str = ''

	if time == nil then return '' end
	if time < 60 then s = time
	elseif time < 3600 then m = math.modf(time/60) s = time - m*60
	else h = math.modf(time/3600) m = math.modf((time - h*3600)/60) s = time - h*3600 - m*60
	end

	if h>0 then str = str..mw.ustring.format ('%i'..translate("unit",2), h) end
	if m>=0 and h>0 then str = str.. mw.ustring.format('%02i'..translate("unit",3), m) end
	if m>0 and h==0 then str = str.. mw.ustring.format('%i'..translate("unit",3), m) end
	if s>=0 and (h>0 or m>0) then str = str.. mw.ustring.format('%02i'..translate("unit",4), s) end
	if s>=0 and h==0 and m==0 then str = str.. mw.ustring.format('%i'..translate("unit",4), s) end
	return str --time..': '..h..' '..m..' '..s
end

local function func_error_message(x)
	local l10nDef = {
		["fr"] = {"La propriété <1> est manquante dans l'item <2> (<3>)"},
		["en"] = {'Property <1> is missing in item "<2>" (<3>)'},
		["ar"] = {'الخاصية <1> غير موجودة في العنصر "<2>" (<3>)'},
	}
	local l10n = l10nDef[wiki]
	if not l10n then l10n = l10nDef["en"] end  -- default
	return l10n[x]
end

local function getMissingLabelTrackingCategory()
	local l10nDef = {
		["cs"] = '[[Kategorie:Údržba:Doplnit štítek na Wikidatech]]',
		["lv"] = '[[Category:Vikidatos trūkst nosaukuma latviešu valodā]]',
		["he"] = '[[קטגוריה:ויקינתונים:ערכים חסרי תווית בעברית: קבוצת אופניים]]',
	}
	local l10n = l10nDef[wiki]
	if not l10n then
		l10n = ''
	end
	return l10n
end

local function getStageLabel(inp)
	local a
	local b='' 
	local this_label=''
	if inp then
		a, _ = string.gsub(inp, "%a", "") -- 20, not 20a
		if string.find(inp, "%a") then 
			b = string.sub(inp, string.find(inp, "%a"))
		end
		if inp == "0" then 
			this_label = translate("func_prologue",1)
		else
		    this_label = stageLink(inp, a, b)
		end
	end
	return this_label
end

--[[ Make a table row for infoboxes with links to previous and next ]]
local function getPreviousNextLine(raceID, stage)
	local previousID = firstValue(raceID, 'P155', 'id') -- P155 is 'follows'
	local nextID = firstValue(raceID, 'P156', 'id') -- P156 is 'followed by'
	if not nextID or not previousID then
		for _, s in statements(raceID, 'P3450') do		-- for items using P3450
			local q = s.qualifiers
			if q then
				if not previousID and q.P155 and q.P155[1] and	q.P155[1].snaktype == 'value' then
					previousID = q.P155[1].datavalue.value.id
				end
				if not nextID and q.P156 and q.P156[1] and	q.P156[1].snaktype == 'value' then
					nextID = q.P156[1].datavalue.value.id
				end
			end
		end
	end
	if not previousID and not nextID then
		return ''
	end

	local previousText, nextText = '', ''
	
	local direction = contentLanguage:getDir()
	local previous_sign = (direction == 'ltr') and '&#x25C0;' or '&#x25B6;'
	local next_sign = (direction == 'ltr') and '&#x25B6;' or '&#x25C0;'
	
	local this_label
	if previousID then
		if stage  then
			 local series_ordinal= firstValue(previousID, 'P1545', 'value')
			 this_label=getStageLabel(series_ordinal)
		else
			this_label = getYear(previousID)
		end
		local link = wikibase.getSitelink(previousID)
		if link then
			previousText = '<span style="color:#3366CC">[[' .. link .. '| ' .. previous_sign .. this_label .. ']]</span>'
		else
			previousText = '<span style="color:#3366CC">' .. previous_sign .. '</span> ' .. this_label
		end
	end
	if nextID then
		if stage then
			local series_ordinal= firstValue(nextID, 'P1545', 'value')
			this_label=getStageLabel(series_ordinal)
		else
			this_label = getYear(nextID)
		end
		local link = wikibase.getSitelink(nextID)
		if link then
			nextText = '<span style="color:#3366CC">[[' .. link .. '|' .. this_label .. next_sign .. ']]</span>'
		else
			nextText = this_label .. ' <span style="color:#3366CC">' .. next_sign .. '</span>'
		end
	end
	local direction = contentLanguage:getDir()
	
	local outTable = mw.html.create('tr')
	local tCell=outTable:tag('td')
	tCell:cssText("text-align:" .. ((direction == 'ltr') and 'left' or 'right')):wikitext(previousText)
	if stage ~= nil and wiki=="ar" then 
		tCell:css('width','50%')
	end
	 tCell=outTable:tag('td')
	 :cssText("text-align:" .. ((direction == 'ltr') and 'right' or 'left')):wikitext( nextText)
    if stage ~= nil and wiki=="ar" then 
		tCell:css('width','50%')
	end
	return outTable
end

--== Functions for infobox
-- functions for infoboxs 
local function get_others_dic()
	return {
		{ name = translate("infobox",29,w_race)}, -- picture
		{ name = translate("infobox",30,w_race)}, -- caption
		{ name = translate("infobox",31,w_race)}, -- map
		{ name = 'sectional'},             -- sectional
		{ name = translate("infobox",30,w_race)}, -- caption map
		{ name = translate("infobox",30,w_race)}, -- caption sectional
	}
end

local function infoGetOthers(others, entityID)
	if not others[1].content then --picture
		others[1].content, others[2].content = getLogo(entityID)
		if not others[1].content then
			others[1].content, others[2].content = getImage(entityID) -- picture, caption
		end
	end

	if not others[3].content then  -- map
		others[3].content, others[5].content = getMap(entityID)  -- P242 is 'locator map image'
	end
	
	if not others[4].content then  -- map
		others[4].content, others[6].content = getSectionalView(entityID) -- sectional_view
	end	
end

local function infoGetPlaceOrCountry(details,index, entityID, timeOfRace, PID) --generalized infoGetCountry
	if not details[index].content then -- country
		-- This function gives countries where the race take place
		local place = {}

	    if not place[1] then 
			for _, p17 in statements(entityID, PID) do -- P17 is 'country'
				local countryID = p17.mainsnak.datavalue.value.id
				if PID=='P17' then
					place[#place + 1] = flag(countryID, timeOfRace) .. ' ' .. getCountryName(countryID) 
				else
					place[#place + 1] =  wikibase.getLabel(countryID)
				end
			end
		end

		if place[1] then
			if #place > 1 then
				details[index].name = details[index].name_plural
			end
			details[index].content = table.concat(place, '<br/>')
		end
	end
end

local function infoGetPlace(details,index, entityID, timeOfRace)
	infoGetPlaceOrCountry(details,index, entityID, timeOfRace, "P276")
end

local function infoGetCountry(details,index, entityID, timeOfRace)
	infoGetPlaceOrCountry(details,index, entityID, timeOfRace, "P17")
end

local function infoGetStartEnd(details,index, entityID, timeOfRace)
	if not details[index].content then -- start place
		local place = firstValue(entityID, 'P1427', 'id') -- P1427 is 'start point'
		details[index].content = place and getPlaceLink(place, timeOfRace)
	end

	if not details[index+1].content then -- end place
		local place = firstValue(entityID, 'P1444', 'id') -- P1444 is 'destination point'
		details[index+1].content = place and getPlaceLink(place, timeOfRace)
	end
end

local function infoGetParticipants(details,index, entityID)
		-- Function that give the number of cyclists at the beginning and at the finishing of a race
	for _, p1132 in statements(entityID, 'P1132') do -- P1132 is 'number of participants'
		local amount = tonumber(p1132.mainsnak.datavalue.value.amount) -- tonumber to remove starting '+'
		for _, q in qualifiers(p1132, 'P276') do -- P276 is 'location'
			local location = q.value.id
			if location == "Q529711" then -- Q529711 is 'beginning'
				if not details[index].content then details[index].content = amount end -- participants at start
			elseif location == "Q12769393" then -- Q12769393 is 'end'
				if not details[index+1].content then details[index+1].content = amount end -- participants at end
			end
		end
	end
end

local function infoInitTab(width, name, icon, cellpadding)
	if width==nil then width= '320px' end
	
	local tab = mw.html.create('table'):addClass('infobox')
	if wiki == "eo" then
		tab:cssText(standardtablecss):css('width','23em')
	else
		cellpadding=tostring(cellpadding or 4)
		tab:attr('cellpadding',cellpadding)
		:attr('cellspacing','0')
		:cssText(standardtablecss)
		:cssText("float:"..floatinfobox.."; max-width:"..width)
	end
	local tCell=tab:tag('tr'):tag('td'):attr('colspan','2')
	:cssText('border-bottom:5px solid var(--background-color-base, #fff); color:inherit; font-size:175%; text-align:center')
	:css('background-color',backgroundColor)
	local topTable = tCell:tag('table')
	:cssText('width:100%')
	local tRow=topTable:tag('tr')
	tRow:tag('td'):wikitext(name or '')
	tRow:tag('td'):wikitext(icon or '')
	
	return tab
end

local function addARow(name, content)
	local tRow
	if content then
		tRow= mw.html.create('tr'):css('vertical-align','top')
		tRow:tag('td'):css('width','40%'):css('font-weight','bold')
		:wikitext(name)
		tRow:tag('td'):wikitext(content)
	end
	return tRow
end

local function addATitle(title)
	local tRow
	if title then
		tRow= mw.html.create('tr'):tag('td'):attr('colspan','2')
		:css('text-align','center')
		:css('background-color',backgroundColor)
		:css('font-weight','bold')
		:css('color', 'inherit')
		:wikitext(title)
	end
	return tRow
end

local function infoFillOthersDetails(tab, others, details,title, pxmax)
	if not pxmax then
		pxmax="300px"
	end
	
	if others and others[1].content then -- picture
		tab:tag('tr'):tag('td'):attr('colspan','2'):css('text-align','center')
		:wikitext("[[File:" .. others[1].content .."|center|"..pxmax.."]]")
		if others and others[2].content then -- caption
			tab:tag('tr'):tag('td'):attr('colspan','2'):css('text-align','center'):css('font-size','80%')
			:wikitext(others[2].content)
		end
	end
	if details then
		tab:node(addATitle(title))
		for _, row in ipairs(details) do
	    	tab:node(addARow(row.name, row.content)) --node check itself if nil
		end
	end
end

local function infoFillOthersMap(tab, others)
	if others[3].content then -- map
		tab:tag('tr'):tag('td'):attr('colspan','2'):css('text-align','center')
		:wikitext("[[File:".. others[3].content .. "|center|300px]]")
		if others[5].content then -- caption
			tab:tag('tr'):tag('td'):attr('colspan','2'):css('text-align','center'):css('font-size','80%')
			:wikitext(others[5].content)
		end
	end
	if others[4].content then -- map
		tab:tag('tr'):tag('td'):attr('colspan','2'):css('text-align','center')
		:wikitext("[[File:".. others[4].content .. "|center|300px]]")
		if others[6].content then -- caption
			tab:tag('tr'):tag('td'):attr('colspan','2'):css('text-align','center'):css('font-size','80%')
			:wikitext(others[6].content)
		end
	end
end

local function wdDoc(tab, s, translation, ID)
	local tCell=tab:tag('tr'):tag('td')
	local tC, link
	local commons_cat=firstValue(ID, 'P373', 'id')
	
	if commons_cat then
		commons_cat=string.gsub(commons_cat, '%s', '_') 
		local icon="[[File:Commons-logo.svg|12px|link=https://commons.wikimedia.org/wiki/Category:"..commons_cat.."]]"
		tC=tCell:cssText('text-align:left; border-top:3px solid '..backgroundColor..'; font-size:93%')
		:wikitext(icon):tag('td')
	else
		tC=tCell:attr('colspan','2')
	end
	if wiki == "ar" then
		link = wdLink(ID) .." [[" .. s .. "|" .. translation .. "]]"
	else
		link = "[[" .. s .. "|" .. translation .. "]] "..wdLink(ID)
	end
	tC:cssText('text-align:right; border-top:3px solid '..backgroundColor..'; font-size:93%')
	:wikitext(link)
end

local function listWPlink(details, index, entityID, PID, bool_link)
	local org={}
	for _, p in statements(entityID, PID) do 
		if p and p.mainsnak.snaktype == 'value' then
			if bool_link then
				table.insert(org,WPlinkpure(p.mainsnak.datavalue.value.id))
			else
				local label=wikibase.getLabelByLang(p.mainsnak.datavalue.value.id, wiki)
				table.insert(org,label)
			end
		end
	end
	if org[1] then
		if #org > 1 then
			details[index].name = details[index].name_plural
		end
		details[index].content = table.concat(org, '<br/>')
	end	
end

--Display in a chronological order fields in a table
local function listWPlinkChrono(details, index, entityID, listOfProperty, option, initialYear, display_flag, comma,season)
	local period, sTime, value, ID, temp
	local list={}
	
	if not initialYear then initialYear="1900" end
	
	if not details[index].content then	
		for _, prop in ipairs(listOfProperty) do
			if #list==0 then --if P1532 is used P17 is not used
				for _, p in statements(entityID, prop) do
					if p and p.mainsnak.snaktype == 'value' then
						ID=p.mainsnak.datavalue.value.id		
						if p.qualifiers then
							period, sTime=getPeriod( p.qualifiers, true,season)
						end
						if not sTime then sTime="+"..initialYear.."-01-01T00:00:00Z" end --first
					
						if option =='label' then
							value=wikibase.getLabelByLang(ID, wiki)	
						elseif option == 'country' then
							value=getCountryName(ID)
							if display_flag then	
								value= flag(ID, sTime).." "..value
							end
						elseif option=='officialname' then
							value=getOfficialName(ID, sTime,false) --official name is necessary because of continental team change in ProTeam
						elseif option =='place' then
							value=getPlaceLink(ID, sTime)
						elseif option=='UCIcode' then
							value=getTeamCodeCat(entityID, sTime) --! getTeamCodeCat uses teamID
						elseif option=='money' then
							local amount=p.mainsnak.datavalue.value.amount
							local unit=p.mainsnak.datavalue.value.unit
							value=dispmoney(amount, unit) or ''
						else --rider
							value=getRiderLink(ID, sTime)
						end
						if value then
							table.insert(list,{sTime,period,value})
						end
					end
				end
			end
		end
		if #list ~=0 then
			table.sort(list, function(a, b) return a[1] < b[1] end)
		end
		local separator='<br/>'
		if comma then separator=', ' end
		
		
		if list and #list==1 then		
			details[index].content=list[1][3] or ''
		elseif list and #list~=0 then
			details[index].name = details[index].name_plural	
			details[index].content=''			
			for _, v in pairs(list) do
				temp=v[3] or ''
				if v[2] then
					temp=temp..' <small>'..v[2]..'</small>'..separator
				else
					temp=temp..separator
				end
				details[index].content=details[index].content..temp
			end	
		end
	end	
end

-- == Functions for team roster
local function getReason(riderReason, riderRef, p527,timeOfRace,riderEnd,lf) --reason for end
	local listofproperty={'P1642','P1643','P1534'}
	local outTable={}
	local seasonYear, endYear
	if timeOfRace then
		seasonYear=tonumber(string.sub(timeOfRace, 2, 5))
	end
	if riderEnd then
		endYear=tonumber(string.sub(riderEnd, 2, 5))
	end
	
	--if not the last season, do not display the reason for end
	if (riderReason == nil and (not endYear or 
		(seasonYear and endYear and (seasonYear== endYear)))) then --if no riderReason before then look for it, otherwise don't touch it
		for _,v in ipairs(listofproperty) do
			for _, q in qualifiers(p527, v) do
				riderReason = q.value.id
			end
		end
		if riderReason then
			local label =string.gsub(getLabelFallback(riderReason,lang_priority), "%b()", "")
			riderRef = getReference(lf,p527, 1)
			riderReason = ', ' .. label
		end
	end
	return riderReason, riderRef
end

local function getPosition(riderPosition,v)
	local stagiaire
	if riderPosition == nil then -- find the 'position' (P39) of a rider
		for _, q in qualifiers(v, 'P39') do
			stagiaire = q.value.id
			local label = string.gsub(getLabelFallback(stagiaire,lang_priority), "%b()", "")
			Sitelink = wikibase.getSitelink('Q2328847')
			if Sitelink then 
				riderPosition=', ' .. "[["..Sitelink .."|"..label.."]]" 
			else
				riderPosition =', ' .. label
			end
		end
	end
	return riderPosition
end

local function trans(date, month, day)
	if date ~= '' and date~=nil then
		local _, _, y, m, d = string.find(date, "(%d+)-(%d+)-(%d+)")
		if m == '00' then m = month end
		if d == '00' then d = day end
		date = '+'..y..'-'..m..'-'..d..'T00:00:00Z'
		return date
	end
	return nil
end

local function parseDate(date, defaultYear, defaultMonth, defaultDay, errortext, etext)
	local y, m, d
	local date=trans(date, defaultMonth, defaultDay)
	if not date then 	
		date = '+'..defaultYear..'-'..defaultMonth..'-'..defaultDay..'T00:00:00Z'
		y=defaultYear
		m=defaultMonth
		d=defaultDay
		errortext=errortext..etext
	else
		_, _, y, m, d = string.find(date, "(%d+)-(%d+)-(%d+)")
		if not y or y=="0000" then 
			y=defaultYear 
			errortext=errortext..etext
		end
		date = '+'..y..'-'..m..'-'..d..'T00:00:00Z'
	end
	
	return date, y, m, d, errortext
end

local function findLastName(label,wiki)
	if not label then label = '' end
	local _, count = string.gsub(label, " ", " ")
	local names
	local a,b,c,d = '', '', '', ''
	local done = false
	if count ~= nil then count = count + 1 else count = 1 end

	if count > 1 then
		if count == 2 then
			if label ~= '' then
				a, b = string.match(label, "(%S+)%s+(%S+)")
				names = b..' '..a
			end
		else
			local name_parts_mk = {'да', 'ди', 'де', 'Де', 'ла', 'Ле', 'тен', 'ван', 'Ван'}
			local name_parts_ru = {'да', 'ди', 'де', 'Де', 'ла', 'Ле', 'тен', 'ван', 'Ван'}
			local name_parts    = {'da', 'de', 'di', 'De', 'la', 'Le', 'ten', 'van', 'Van'}
			if count == 3 and label ~= '' then
				a, b, c = string.match(label, "(%S+)%s+(%S+)%s+(%S+)")
				if wiki == 'mk' then
					for _,v in ipairs(name_parts_mk) do if b == v then names = b..' '..c..' '..a done = true break end end
				elseif wiki == 'ru' then
					for _,v in ipairs(name_parts_ru) do if b == v then names = b..' '..c..' '..a done = true break end end
				else
					for _,v in ipairs(name_parts) do if b == v then names = b..' '..c..' '..a done = true break end end
				end
				if not done then
					names = tostring(c)..' '..tostring(a)..' '..tostring(b)
					done = true
				end
			end
			if count > 3 and label ~= '' then
				a, b, c, d = string.match(label, "(%S+)%s+(%S+)%s+(%S+)%s+(%S+)")
				if wiki == 'mk' then
					for _,v in ipairs(name_parts_mk) do if c == v then names = c..' '..d..' '..a..' '..b done = true break end end
					for _,v in ipairs(name_parts_mk) do if b == v then names = b..' '..c..' '..d..' '..a done = true break end end
				elseif wiki == 'ru' then
					for _,v in ipairs(name_parts_ru) do if c == v then names = c..' '..d..' '..a..' '..b done = true break end end
					for _,v in ipairs(name_parts_ru) do if b == v then names = b..' '..c..' '..d..' '..a done = true break end end
				else
					for _,v in ipairs(name_parts) do if c == v then names = c..' '..d..' '..a..' '..b done = true break end end
					for _,v in ipairs(name_parts) do if b == v then names = b..' '..c..' '..d..' '..a done = true break end end 

				end
				if not done then names = label.."%"..b end --b..' '..c..' '..d..' '..a end
			end
		end
	end
	return names or ''
end

local function findSortKey(riderID, correctlanguage, wikiIsSlavic)
	--find the last name to sort
	if wikiIsSlavic and correctlanguage then
		local label = wikibase.getLabelByLang(riderID, wiki)
		if label then
			local nametable = mw.text.split(label, ",")
			if nametable[2] then --there is a coma so the lastname is first
				return nametable[1]..nametable[2]
			else --no coma
				return findLastName(label,wiki) 
			end
		end
	end
	--all other cases
	label = getLabelFallback(riderID)
	return findLastName(label,wiki)
end

--== V) Main functions ==
--=== A) Function race reference ===
local function race_reference(raceID,lf)
	-- Allow to display the reference below the classifications --
	local bases={
		{"ProCyclingStats", "P2327", "http://www.procyclingstats.com/race.php?id="},
		{"Cycling Quotient", "P2648", "http://www.cqranking.com/men/asp/gen/race.asp?raceid="},
		{"Cycling Archives", "P2330", "http://www.cyclingarchives.com/ritfiche.php?ritid="},
		{"Cycling Quotient", "P2708", "http://www.cqranking.com/women/asp/gen/race.asp?raceid="},
	-- cycling team	
		{"ProCyclingStats", "P2328", "http://www.procyclingstats.com/team/"},
		{"Cycling Quotient", "P2649", ""}, --The entire link is indicated in full
		{"Cycling Archives", "P2331", "http://www.cyclingarchives.com/ploegfiche.php?id="}		
	}
	local links = {}
	local ref
	for _, base in pairs(bases) do
		local p = mw.wikibase.getBestStatements(raceID, base[2])
		if p[1] and p[1].mainsnak.snaktype == 'value' then
		    if base[2]=="P2648" and p[1].mainsnak.datavalue.value=="1" then --code for general reference of results
				ref=getReference(lf,p[1], 1)
				if ref then	table.insert(links, ref) end
			else
				table.insert(links, ' [' .. base[3] .. p[1].mainsnak.datavalue.value .. " " .. base[1] ..']')
			end
		end
	end
	if #links == 1 then
		return translate("race_reference", 1) .. table.concat(links)
	elseif #links > 1 then
		return translate("race_reference", 2) .. table.concat(links)
	else
		return ''
	end
end

--=== B) Calendar ===
function p.calendarcustom(frame)
	local headers={2} --date
	local calendarID, lf =get_and_checkID(frame)

	local display_numbering=false --default
	local country_column=2
	if istrue(get_arg('display_numbering',frame)) then
		display_numbering=true
		table.insert(headers, 3)
		country_column=3
	end
    --no_country modify the way the country is displayed
    local no_country={}
    if istrue(get_arg('no_country',frame)) or wiki == "ar" then
		no_country={wiki}
	end
	-- country --
	table.insert(headers, 5)
	--race--
	table.insert(headers, 4)

	local display_class=false
	if istrue(get_arg('display_class',frame)) or wiki == "ar" then
		display_class=true
		table.insert(headers, 6)
	end
	
    table.insert(headers, 7) --winner
	local only_winner=1
	if istrue(get_arg('podium',frame)) or wiki == "ar" then
		only_winner =0
		table.insert(headers, 8) --second
		table.insert(headers, 9)	--third	
	end
	
	local display_leader=false
	if istrue(get_arg('display_leader',frame)) then
		 display_leader=true
		 table.insert(headers, 10)
	end
	local display_team =false
	if istrue(get_arg('display_team',frame)) then
		display_team =true
	end

	local data_type={}
	for ii=1,#headers do
		table.insert(data_type,'')
	end
	
    local w_race=isWomenrace(calendarID)
	local s = {
		header_function = "calendar", -- translations are in function Calendar
		header_1 = 1000, -- translation 1 in function Calendar is printed in the upper part of the table header
		header_2 = headers,-- translations 2, 3, 4, 5, 6 in function Calendar are printed in this order
		title=wikibase.getLabel(calendarID),  -- in the lower part of the table header. The second value 3 in {4, 3} tells where the icon will go.
		country_column = country_column,
		data_sort_type = data_type, -- see https://meta.wikimedia.org/wiki/Help:Sorting
		item = calendarID,
		property = 'P527',
		no_country = no_country,
		only_winner = only_winner,
		display_numbering =  display_numbering,
		displayed_class =nil,
		display_team=display_team,
		display_class=display_class,
		display_leader= display_leader,
		w_race=w_race,
		lf=lf
	}
	return calendar_main(s, tableA(s))
end

function p.calendar(frame)
	----- function to display UCI calendar of one year ----
	----- based on WWTcalendar function -----
	----- author: Mr. Ibrahem -----
	local calendarID --determined later
	local lf = get_lf(frame)
	local UCI = data.UCIYearToQ
	
	local header_1_tab = {["UWT"]=13 ,["europe"]=14 ,["asia"]=15,["america"]=16 ,["africa"]=17 ,["oceania"]=18, ["WWT"]=11, ["women"]=1, ["Pro"]=22}
	local display_code_tab=  {["UWT"]=1 ,["europe"]=2 ,["asia"]=2,["america"]=2 ,["africa"]=2 ,["oceania"]=2, ["WWT"]=1, ["women"]=2, ["Pro"]=2}
	local header_1_number = 12
	
	local tempdic, year, keyk, yeary
	local tempdic1 = {
		header_2 =  {2, 3,5, 4, 7, 8, 9, 10},
		only_winner =0,
		display_numbering=true,
		display_team=false,
		display_class=false,
		display_leader=true
	}	
	local tempdic2 = {
		header_2 =   {2, 5, 4, 6, 7},
		only_winner =1,
		display_numbering=false,
		display_team=true,
		display_class=true,
		display_leader=false
	}

	for key, v in pairs(UCI) do
		year = get_arg(key,frame) --with lf does not work
		if not calendarID  and year then
			if v[year] then
				calendarID = v[year]
				header_1_number = header_1_tab[key]
				display_code = display_code_tab[key]
				keyk=key
				yeary=year				
			end
		end
	end
	if wiki == "ar" then
		if not (frame.args["code"] and frame.args["code"] == "2") then
			display_code = 1
		end
		if calendarID == "" and frame.args.test then
			calendarID = frame.args.test
		end
	end
	if not calendarID or calendarID == "" then return "" end
	if display_code == 1 then
		tempdic=tempdic1
		if keyk=="UWT" and tonumber(yeary) > 2018 then
			tempdic.display_leader=false --no more leader after 2018
			tempdic.header_2 ={2, 3,5, 4, 7, 8, 9}
		end
	else
		tempdic=tempdic2
	end
	if istrue(get_arg('display_numbering',lf)) then
		tempdic.display_numbering=true
	elseif get_arg('display_numbering',lf) and istrue(get_arg('display_numbering',lf)) == nil then
		tempdic.display_numbering=false
	end
	local w_race=isWomenrace(calendarID)
	local s = {
		header_function = "calendar", -- translations are in function Calendar
		header_1 = header_1_number, -- t
		header_2 = tempdic.header_2,
					-- in the lower part of the table header. The second value 3 in {4, 3} tells where the icon will go.
		country_column = 3,
		data_sort_type ={'', 'unsortable', '', '', '','',''},   -- -- see https://meta.wikimedia.org/wiki/Help:Sorting
		item = calendarID,
		property = 'P527',
		no_country = no_country_calendar,
		only_winner = tempdic.only_winner,
		display_numbering = tempdic.display_numbering,
		displayed_class = nil, --all
		display_team=tempdic.display_team,
		display_class=tempdic.display_class,
		display_leader=tempdic.display_leader,
		w_race=w_race,
		lf=lf
	}
	return calendar_main(s, tableA(s))
end

function calendar_main(s, resultTable)--Display the UCI women calendar of one year
	local lf = s.lf
	local calendarID=s.item
	local t_Body ={}
	local w_race=isWomenrace(calendarID)

	local temp=firstValue(calendarID, s.property)
	if not temp or temp=="" then 
		s.error_message = 2 
		if wiki == "ar" then return "" end
	end
	local country=getCountryBool(s.no_country)

	----- Begin of the main part of the code
	for kk, p527 in statements(calendarID, 'P527') do
		local RaceID = p527.mainsnak.datavalue.value.id
		---- Create a row ----
		local timeOfRace, date_tCell, date_sortkey = fn_date(RaceID)
		local parentID, race_tCell, class_tCell= fn_race(RaceID,s.displayed_class,s.display_class,timeOfRace,nil,country)

		if race_tCell~=nil then --otherwise the class is not display
			local country_flag, country_name, country_tCell=fn_country(RaceID, timeOfRace, country, race_tCell, parentID) 
			--create the table
			local tRow = mw.html.create('tr'):cssText( "line-height: 1.8em; padding: 5px;")
			tRow:node(date_tCell)
			if s.display_numbering == true then
				tRow:tag('td'):cssText("text-align:center;padding:0 0.5em"):wikitext(tostring(kk))
			end
			tRow:node(country_tCell)
			if country then	tRow:node(race_tCell) end
			if class_tCell then tRow:node(class_tCell) end
			local rider_tCell =fn_rider(lf,RaceID,timeOfRace,s.display_team,s.only_winner)
			tRow:node(rider_tCell)
			if s.display_leader==true then
				local leader_tCell=fn_rider(lf,RaceID,timeOfRace,s.display_team,3)
				tRow:node(leader_tCell)
			end
			---- Add the row to the table
			table.insert(t_Body, {sortkey=date_sortkey, body=tRow})
		end 
	end
	return sortAndConcat(t_Body, resultTable)
end

function p.nationalchampionships(frame)
	local calendarroadID, calendarITTID, year
	local lf=get_lf(frame)
	local listOfCalendar={data.NationalRoadCyclingChampionships,data.NationalITTCyclingChampionships}

	for ii, thisCalendar in pairs(listOfCalendar) do --road/ITT
		for key, v in pairs(thisCalendar) do --look for the key of the dictionnary, here women/men
			year = get_arg(key,frame) --with lf does not work
			if ((ii==1 and calendarroadID==nil) or (ii==2 and calendarITTID ==nil)) and year then
				if v[year] then
					if ii==1 then
						calendarroadID = v[year]
					else
						calendarITTID = v[year]
					end
				end
			end
		end
	end
	
	local w_race=isWomenrace(calendarroadID)
	local s = {
		header_function = "calendar", -- translations are in function Calendar
		header_1 = 19, --
		header_2 = {5, 20, 21},
		country_column = 1,
		data_sort_type = {'', '', ''},   -- -- see https://meta.wikimedia.org/wiki/Help:Sorting
		item= calendarroadID,
		calendarroadID = calendarroadID,
		calendarITTID = calendarITTID,
		property = 'P527',
		year = year,
		no_country = {}, --no sense here to hide the country
		display_team = true,
		display_countrylink = false, --too expensive
		w_race=w_race,
		lf=lf
	}
	return nationalchampionships_main(s,tableA(s))
end

function nationalchampionships_main(s, resultTable)--Display the list of national champions for one year
	local lf = s.lf
	local tableChamp, t_Body = {}, {}, {}
	local timeOfRace ='+'..tostring(s.year).."-01-01T00:00:00Z"
	local rider_tCell, thereisawinner, parentID, parentParentID, sitelink
	local country_flag, country_name, country_tCell

	local temp=firstValue(s.calendarroadID, s.property)
	if not temp or temp=="" then 
		s.error_message = 2 
		if wiki == "ar" then return "" end
	end

	local listOfCalendarID={s.calendarroadID, s.calendarITTID}

	--create the table with the information
	for ii, thisCalendarID in ipairs(listOfCalendarID) do
		if thisCalendarID ~= nil then
			for _, p527 in statements(thisCalendarID, 'P527') do
				thisID = p527.mainsnak.datavalue.value.id
				country_flag, country_name, country_tCell=fn_country(thisID,timeOfRace,s.country)
				if country_name == nil then	country_name="country not found" end
				sortkey=string.gsub(country_name, 'É', 'E') --case États Unis
				--create the table
				if tableChamp[sortkey]==nil then 
					tableChamp[sortkey]={}
					tableChamp[sortkey]['countryname']=country_name
					tableChamp[sortkey]['roadwinner']='<td></td>'
					tableChamp[sortkey]['ITTwinner']='<td></td>'
					--look for sitelink to championship
					sitelink=nil --reinit
					if s.display_countrylink then --expensive
						parentID = firstValue(thisID, 'P361', 'id') --part of
						if parentID then 
							parentParentID = firstValue(parentID, 'P31', 'id') 
							if parentParentID then sitelink = wikibase.getSitelink(parentParentID) end
						end
					end
					tableChamp[sortkey]['sitelink']=sitelink
					tableChamp[sortkey]['flag']=country_flag
				end
				
				--fill the table
				rider_tCell, thereisawinner=fn_rider(lf,thisID,timeOfRace,s.display_team,1,true)
				if tableChamp[sortkey]['thereisawinner']~=true then --all other cases
					tableChamp[sortkey]['thereisawinner']=thereisawinner 
				end
				
				if ii==1 then
					tableChamp[sortkey]['roadwinner']=rider_tCell
				else
					tableChamp[sortkey]['ITTwinner']=rider_tCell
				end
			end
		end
	end

	-- structure the display
	for key, thisRow in pairs(tableChamp) do
		if thisRow['thereisawinner'] then --there is a winner
			local tRow = mw.html.create('tr'):cssText( "line-height: 1.8em; padding: 5px;")
			if thisRow['sitelink']~=nil then
				tRow:tag('td'):wikitext(thisRow['flag']..' [['..thisRow['sitelink']..'|'..thisRow['countryname']..']]')
			else
				tRow:tag('td'):wikitext(thisRow['flag']..' '..thisRow['countryname'])
			end
			tRow:node(thisRow['roadwinner'])
			tRow:node(thisRow['ITTwinner'])
			table.insert(t_Body, {sortkey=key, body=tRow})
		end --no winner
	end --end list of key

	return sortAndConcat(t_Body, resultTable)  
end

--=== C) Victory ===
function p.victories(frame)
	local tempID, lf=get_and_checkID(frame)
	local w_race=isWomenrace(tempID)
	
	local s = {
		header_function = "victories", -- translations are in function victories
		header_1 = 2, -- translation 1 in function victories is printed in the upper part of the table header
		header_2 = {3, 4, 5, 6, 7},-- translations 2, 3, 4, 5, 6 in function victories are printed in this order
										-- in the lower part of the table header. The second value 3 in {4, 3} tells where the icon will go.
		data_type = {'date', 'race', 'country', 'class', 'rider'},
		country_column = 3,
		data_sort_type = {'', 'unsortable', '', '', ''}, -- see https://meta.wikimedia.org/wiki/Help:Sorting
		item = tempID,
		property = 'P2522',
		no_country = no_country_victories,
		lf=lf,
		w_race=w_race
	}
	return victory_main(s ,tableA(s))
end

function victory_main(s, resultTable)
	local lf = s.lf
	local _
	_, _, s.item = string.find(s.item, "(%w+)")

	local temp=firstValue(s.item, s.property,'id')
	if not temp or temp=="" then 
		s.error_message = 2 
		if wiki == "ar" then return "" end
	end

	local country=getCountryBool(s.no_country)
	local t_Body = {}

	for _, p2522 in statements(s.item, 'P2522') do
		local RaceID = p2522.mainsnak.datavalue.value.id
		local tRow = mw.html.create('tr'):cssText( "line-height: 1.8em; padding: 5px;")

		local timeOfRace, date_tCell, date_sortkey = fn_date(RaceID, 'victory')
		local parentID, race_tCell, class_tCell=fn_race(RaceID,nil ,true,timeOfRace, 'victory',country)--displayed_class=nil
		
		if race_tCell~= nil then --otherwise class not to be displayed
			country_flag, country_name, country_tCell=fn_country(RaceID, timeOfRace, country, race_tCell, parentID)
			--Build the table
			tRow:node(date_tCell)
			if country==true then
				tRow:node(race_tCell)  --race site link is in fn_countrytable
			end
			tRow:node(country_tCell) 
			tRow:node(class_tCell) --class
			local rider_tCell =fn_rider(lf,RaceID,timeOfRace,false,1)
			tRow:node(rider_tCell)
			table.insert(t_Body, {sortkey=date_sortkey, body=tRow})
		end --no winner
	end --end list of key
	
	return sortAndConcat(t_Body, resultTable)
end

--== D) Stage infobox
function p.stageinfobox(frame)
	local stageID, lf = get_and_checkID(frame)
	local w_race=isWomenrace(stageID)
		
	local details = {
		{ name = translate("stageinfobox",2,w_race)}, -- course / not used
		{ name =  translate("stageinfobox",2,w_race)}, -- competition
		{ name = translate("stageinfobox",3,w_race), name_plural = translate("infobox",4,w_race)}, -- stage type 
		{ name = translate("stageinfobox",4,w_race), name_plural = translate("infobox",7,w_race)}, -- date
		{ name = translate("stageinfobox",6,w_race)}, -- distance
		{ name = translate("stageinfobox",7,w_race), name_plural = translate("infobox",10,w_race)}, -- country
		{ name = translate("stageinfobox",9,w_race)}, -- start place
		{ name = translate("stageinfobox",10,w_race)}, -- endplace
		{ name = translate("stageinfobox",11,w_race)}, -- participants at start
		{ name = translate("stageinfobox",12,w_race)}, -- participants at end
		{ name = translate("stageinfobox",13,w_race)}, -- speed
		{ name = translate("stageinfobox",44,w_race)}, -- elevation
		{ name = translate("infobox",32,w_race), special = true}, -- special 1
		{ name = translate("infobox",33,w_race), special = true}, -- special 2
	}
	local others = get_others_dic()
			--begin of the function
	local t_Of = {
			Q20882747={'results', 'first'}, 
			Q20882748={'results', 'second'}, 
			Q20882749={'results', 'third'}, 
			Q21686770={'results', 'winner_fighting'},
			Q2250962={'results', 'cima_coppi'}, 
			Q10452933={'results', 'cima_pantani'},
			Q20882763={'gen', 'leader'}, 
			Q20882764={'gen', 'deuxieme'}, 
			Q20882765={'gen', 'troisieme'},
			Q20883213={'annex', 'montagne'}, 
			Q20883140={'annex', 'jeune'}, 
			Q20883008={'annex', 'points'},
			Q20883329={'annex', 'sprints'}, 
			Q20893984={'annex', 'super_combatif'}, 
			Q20965880={'annex', 'combine'},
			Q27104688={'annex', 'stage_volantes'}, 
			Q27104684={'annex', 'regularite'}, 
			Q20882922={'annex', 'equipe'},
			Q27104271={'annex', 'equipe_points'},
			Q20882667={'gen', 'leader'}, 
			Q20882668={'gen', 'deuxieme'}, 
			Q20882669={'gen', 'troisieme'},
			Q20883212={'annex', 'montagne'}, 
			Q20883139={'annex', 'jeune'}, 
			Q20883007={'annex', 'points'},
			Q20883328={'annex', 'sprints'}, 
			Q20893983={'annex', 'super_combatif'}, 
			Q20893979={'annex', 'combine'},
			Q27067359={'annex', 'stage_volantes'}, 
			Q27067170={'annex', 'regularite'},
			Q27907747={'annex', 'azzurri_ditalia'}, 
			Q27907748={'annex', 'azzurri_ditalia'},
			Q27907714={'annex', 'breakaway'}, 
			Q27907715={'annex', 'breakaway'},
			Q20882921={'annex', 'equipe'}, 
			Q27104269={'annex', 'equipe_points'}
	}
	
	getLocalContent(details, lf.args)
	getLocalContent(others, lf.args)

	local timeOfRace
	local temp = firstValue(stageID, 'P31','id')
	icon = ''
	if temp and temp ~= 'Q18131152' then
		if temp=='Q2266066' or temp=='Q2348250' or temp=='Q485321' then 
			icon = picto_track
		else 
			icon = picto_road
		end
		details[3].content = typeofstagelogo(stageID, true).." "..WPlinkpure(temp)
	end
	
	local name =  getLabelFallback(stageID) or ''
	if wiki == 'fr' and name ~= nil then 
		name= mw.ustring.gsub(name, "^(%d+)([re]+)", "%1<sup>%2</sup> ") 
	end
    name= mw.ustring.gsub(name, "^(%a)",function (x) return mw.ustring.upper(x) end)
		
	infoGetOthers(others, stageID)	

	--name
	local race={}
	
	if course==nil then
		temp = firstValue(stageID, 'P1545')
		if temp then
			details[2].content =getStageLabel(temp)
			raceId = getParentID(stageID) --for instance Tour de France 2020
			if raceId then
				details[2].content = (details[2].content or '') .. '، '.. WPlinkpure(raceId)
				for k, p31 in statements(raceId, 'P31') do --get Tour de France
					race[k] = p31.mainsnak.datavalue.value.id --for the jersey
				end
			end
		end
	end

	-- This function give a format to dates when P585 (date) is used in a single day race
	local pTime = firstValue(stageID, 'P585', 'time') -- P585 is 'point in time'
	if pTime then
		details[4].content = funcDate(pTime, 'long')
		timeOfRace = pTime
	end
	
	local kmdistance
	if not details[5].content then details[5].content, kmdistance = getDistance(stageID, true) end -- distance
	
	infoGetCountry(details,6, stageID, timeOfRace)
	infoGetStartEnd(details,7, stageID, timeOfRace)
	infoGetParticipants(details,9, stageID)
	if not details[11].content then details[11].content = getSpeed(stageID, true, kmdistance, 'P2417') end --speed
	if not details[12].content then 
		local elevation=getElevation(stageID) 
		if  elevation ~= nil then details[12].content =elevation else details[12].content = nil end
	end --Elevation

	local jerseyWPID, jersey_name
	local t_s = {
		order={'results', 'gen', 'annex'},
		results={show=false, 
			header=15, 
			order = {'first','second','third','winner_fighting','winner_fighting2','cima_coppi','cima_pantani'},
			first={translation=16},
			second={translation=17},
			third={translation=18},
			winner_fighting={translation=19},
			winner_fighting2={translation=19}, -- two winner_fighting possible
			cima_coppi={translation=40},
			cima_pantani={translation=41}
			},
		gen={show=false, 
			header=20, 
			order = {"leader", "deuxieme", "troisieme"},
			leader={translation=21},
			deuxieme={translation=22},
			troisieme={translation=23}
			},
		annex={show=false, 
			header=24, 
			order={"points","montagne","sprints","jeune","super_combatif","combine",
			"stage_volantes","regularite","azzurri_ditalia","breakaway","equipe","equipe_points"},
			points={translation=25},
			montagne={translation=26},
			sprints={translation=27},
			jeune={translation=28},
			super_combatif={translation=29},
			combine={translation=30},
			stage_volantes={translation=31},
			regularite={translation=32},
			azzurri_ditalia={translation=42},
			breakaway={translation=43},
			equipe={translation=33},
			equipe_points={translation=34}
			}
		}

	--Winner
	for _, p1346 in statements(stageID, 'P1346') do
		local id_speed, id_time, id_time_gap, id_points_a, id_points_b, type_ofclas, name_ofclas
		local q = p1346.qualifiers
		local riderId = p1346.mainsnak.datavalue.value.id

		id_time = qualifieramount(p1346, 'P2781')
		id_time_gap =qualifieramount(p1346, 'P2911')
		id_speed =qualifieramount(p1346, 'P2052')
		id_points_a = qualifieramount(p1346, 'P1358')
		id_points_b =qualifieramount(p1346, 'P1351')

		if riderId ~= nil then
			local riderLink,riderTeam  = subwinner(riderId, timeOfRace, q) --sub function to avoid code in double
			-- looks into race item if the winner has a P642 statement for showing the type of winner(points, mountain, ..)
			propertyOf=nil
			if q.P2501 and q.P2501[1].snaktype == 'value' then
				propertyOf=q.P2501
			elseif q.P642 and q.P642[1].snaktype == 'value' then --fallback
				propertyOf=q.P642
			end

			if propertyOf and propertyOf[1].snaktype == 'value' then
				for _, vv in pairs(propertyOf) do
					local qual = vv.datavalue.value.id
					if qual~=nil and deprecated~='deprecated' and t_Of[qual] then
						if qual=="Q21686770" and t_s['results']['winner_fighting'][1] ~= "" then 
							t_Of[qual][2] = 'winner_fighting2' 
						end
						type_ofclas=t_Of[qual][1] --annex or gen
						name_ofclas=t_Of[qual][2] --name of ranking
						local v=t_s[type_ofclas][name_ofclas]

						v['link']=riderLink    
						v['team']=riderTeam 
						v['rank']=isdisqualified(p1346,q) 
						v['time']=id_time 
						v['gap']=id_time_gap 
						if id_points_a then v['points']=id_points_a end 
						if id_points_b then v['points']=id_points_b end
						v['speed']=id_speed 
						if qual=="Q27104271" and t_s.annex.equipe_points['link']==nil then
							t_s.annex.equipe_points['link']=riderId 
						end
						if qual=="Q20882922" and t_s.annex.equipe['link']==nil then 
							t_s.annex.equipe['link']=riderId 
						end
						v['genre'] = getGenderCode(riderId,'f')
					end
				end
			end
		end
	end
	local rank, deprecated, prop, order, thisorder

	-- look into P2417, stage classification, then p2321 gen classification
	for ii, thistable in ipairs({'results','gen'}) do
		if ii==1 then
			prop='P2417'
			order = {'first', 'second', 'third'}
		else
			prop='P2321'
			order = {'leader', 'deuxieme', 'troisieme'}
		end
		
		for _, p2417 in statements(stageID, prop) do
			local q = p2417.qualifiers
			if q.P1352 and q.P1352[1].snaktype == 'value' then
				for _, q1352 in pairs(q.P1352) do
					rank = tonumber(q1352.datavalue.value.amount)
				end
				if rank == 1 or rank == 2 or rank == 3 then
					thisorder=order[rank]
					local v=t_s[thistable][thisorder]
					v['rank'] = isdisqualified(p2417, q)
					local thisid= p2417.mainsnak.datavalue.value.id
					v['link'],_  = subwinner(thisid, timeOfRace, q) 

					if v['gap'] == nil and v['time'] == nil then
						v['gap'] = qualifieramount(p2417, 'P2911') 
					end
					if v['gap'] == nil and v['time'] == nil then
						v['time'] = qualifieramount(p2417, 'P2781') 
					end
					v['speed'] = qualifieramount(p2417, 'P2052') 
					v['genre'] = getGenderCode(thisid, 'f')
				end
			end
		end
	end

	for _, thistable in ipairs({t_s.results,t_s.gen,t_s.annex}) do
		for _, v in ipairs(thistable.order) do --order is the list of all classification names
			if thistable[v]['link'] then
				thistable.show = true 
			end
		end
	end
	
	---General table
	local temp
	local width= '320px' -- size standard 320px, special 340px
	if t_s.annex.show == true and (wiki == 'no' or wiki == '..') then width= '340px' end
	tab= infoInitTab(width, name, icon)
	infoFillOthersDetails(tab, others, details,translate("stageinfobox",1,w_race))

-- ranking table, general and stage
	for _, value_order in ipairs(t_s.order) do
		local thistable =t_s[value_order] --results or gen or annex
		
		if thistable.show then -- if a section of the stageinfobox should be shown
			tCell=tab:tag('tr'):tag('td'):attr('colspan','2')
			tTab=tCell:tag('table'):attr('cellpadding','0'):attr('cellspacing','0'):css('width','100%')
			tCell=tTab:tag('tr'):tag('td'):attr('colspan','3')
			:cssText('border-bottom:5px solid '..backgroundColorLight..'; background-color:'..backgroundColor..'; color:inherit; text-align:center')
			:css('font-weight','bold')
			:wikitext(translate("stageinfobox",thistable.header,w_race))

			for key, value in ipairs(thistable.order) do --value is the name of the class
				local v=thistable[value]
				if v['link'] then
					local a1
					a1, jersey_name, jerseyWPID = jersey_infobox( value, race, timeOfRace)
					if a1~='' then v['jersey'] = a1 end
					if v['speed']  then
						if wiki == 'fo' then
							v['speed'] = string.gsub(v['speed'], "%.", ",") 
						else
							local lang = mw.language.getContentLanguage()
							v['speed'] = '('.. lang:formatNum(v['speed'])..translate("unit",5,w_race)..')'
						end
					end
					if v['points'] then
						if v['points'] > 1 then 
							temp=translate("unit",7,w_race)
						else 
						    temp=translate("unit",6,w_race) 
						end 
						v['points'] = v['points']..temp
					end
					local title, k = string.gsub(translate("stageinfobox",v['translation'],w_race), " ", "&nbsp;")
					if k > 0 then title = string.gsub(title, "&nbsp;", "<br>", 1) end --&#32;
				
					--Create an empty column on the left
					tRow=tTab:tag('tr'):css('vertical-align','top')
					tCell=tRow:tag('td')
					:css('font-weight','bold')
					if v['team']~=nil or v['speed'] ~=nil then
						tCell:attr('rowspan','2')
					end
					tCell:cssText("width:1%;background-color:"..backgroundColorLight..";text-align:" .. 
					textalign .. ";padding:0 2px 0 2px;white-space:nowrap; color:inherit;")
				
					if value_order~='annex' and v['translation']~=40 and v['translation']~=41 then -- Cima Coppi, Cima Pantani with a line break
						if v['jersey'] == nil then
							if (value_order=='results') and (value=='winner_fighting' or value=='winner_fighting2' or value=='cima_coppi' or value=='cima_pantanii') then
								tCell:wikitext(translate("stageinfobox",v['translation'],w_race))
							else
								tCell:wikitext(number(v['genre'], key, wiki))
							end
						else
							temp=''
							if jerseyWPID~='' then
								temp="|link="..jerseyWPID
							end
							tCell:wikitext("[[File:"..v['jersey'].."|20px|"..title..temp.."]]")
						end
					else
						if v['jersey'] == nil then 
							tCell:wikitext(title)
						else
							if jerseyWPID=='' then
								if jersey_name ~= '' then 
									temp = "|"..jersey_name
								else
									temp=''
								end
							else 
								temp= "|link="..jerseyWPID
							end
							tCell:wikitext("[[File:"..v['jersey'].."|20px"..temp.."]]" .. title)
						end
					end
					
					tRow:tag('td'):cssText("padding:0 0.5em 0 0.5em;"..v['rank'])
					:wikitext( v['link'])
					tCell=tRow:tag('td'):cssText('text-align:right;font-size:85%;white-space:nowrap')

					if v['time'] then 
						tCell:wikitext(calculateTime(v['time']))
					end
					if v['gap'] then 
						tCell:wikitext('+ '.. calculateTime(v['gap']))
					end
					tCell:wikitext(v['points'])
				end
				
				tCell=tTab:tag('tr'):tag('td'):attr('colspan','2')
				if v['team']~=nil and v['speed'] ~=nil then -- team row
					tTab2=tCell:tag('table'):attr('cellpadding','0'):attr('cellspacing','0'):css('width','100%')
					tRow = tTab2:tag('tr')
					tRow:tag('td'):cssText('width:100%;text-align:" .. textalign .. ";padding-left:2px')
					:wikitext("("..v['team']..")") --add the team
					tRow:tag('td'):cssText('font-size:85%;vertical-align:top;white-space:nowrap')
					:wikitext(v['speed'])
				else
					if v['team']~=nil or v['speed'] ~=nil then
						tCell:cssText("text-align:" .. textalign .. ";padding-left:2px")
						if v['team'] ~= nil then
							tCell:wikitext("("..v['team']..")") --add the team
						end
						tCell:tag('span'):cssText("float:right;font-size:85%;"):wikitext(v['speed'])
					end
				end
			end
		end
	end
	
	infoFillOthersMap(tab, others)
	tab:node(getPreviousNextLine(stageID,true))
	wdDoc(tab, "d:Wikidata:WikiProject Cycling/Documentation/stageinfobox", translate("stageinfobox",39,w_race), stageID)
	return tab
end

--== E) List of teams
function p.listofteams(frame)
	local raceID, lf = get_and_checkID(frame)
	local teams = {} -- values will be {teamLink, teamCat, sortkey, index}
	local WDlink_on = (wiki == "mk" or wiki == "ja")

	local timeOfRace = getTimeOfRace(raceID, true)
	local w_race=isWomenrace(raceID)
		
	local teamCats_lot = { -- {c,d,e} c = singular team type, d = plural team type, e = print order of the team types
-- Part of the numbering is omitted for the convenience of possible subsequent editing.
	-- UCI professional men's teams		
		["Q6154783"]   = {4,5,1},    -- WorldTeam
		["Q20638319"]  = {6,7,2},    -- ProTeam (2005-2014)
		["Q78464255"]  = {6,7,3},    -- ProTeam (2020-)
		["Q382927"]    = {8,9,4},    -- UCI Professional Continental Team (2005-2019)
		["Q1756006"]   = {10,11,5},  -- UCI Continental Team
		["Q20639847"]  = {16,17,6},  -- professional cycling team
		["Q20653563"]  = {20,21,7},  -- Groupe Sportif I
		["Q20653564"]  = {22,23,8},  -- Groupe Sportif II
		["Q20653566"]  = {24,25,9},  -- Groupe Sportif III
	-- UCI professional women's teams		
		["Q80425135"]  = {57,58,11},   -- UCI Women’s WorldTeam
		["Q130604574"]  = {59,60,12},   -- UCI Women’s ProTeam
		["Q119942457"] = {32,33,13}, -- UCI Women's Continental Team (2020-)		
		["Q2466826"]   = {28,29,14}, -- UCI Women’s Team (-2019)
		["Q119948768"] = {55,56,15}, -- UCI Women's Elite-2 Team
	-- other non-road UCI teams	
		["Q2466819"]   = {45,46,21}, -- UCI Track Team
		["Q39885628"]  = {47,48,22}, -- UCI Cyclocross Team
		["Q2466804"]   = {49,50,23}, -- UCI MTB Team
		["Q39885630"]  = {51,52,24}, -- UCI BMX Team
	-- national teams (partially merged)		
		["Q54660600"]  = {12,13,31}, -- national cycling team "any", without specifying additional parameters"
		["Q23726798"]  = {12,13,31}, -- national cycling team Elit
		["Q99658502"]  = {12,13,31}, -- national cycling team "B"
		["Q20738667"]  = {12,13,31}, -- national cycling team U23
		["Q54555994"]  = {12,13,31}, -- national cycling team U19
		["Q26213387"]  = {12,13,31}, -- olympic team 
		["Q46135307"]  = {12,13,31}, -- nation at sport competition in multisport games
		["Q28492441"]  = {39,40,32}, -- national cycling team with sponsor name
		["Q117280678"] = {37,38,33}, -- mixt cycling team
-- Below are two blocks with "non-professional" teams. They differ in the type of output - individually or all together. You can choose any manual setting.
	-- amateur, club and region (not merged). Each type of team is output in a separate block	
		["Q114864716"] = {43,44,41}, -- DCU Elite Team
		["Q20652655"]  = {18,19,42}, -- amateur cycling team
		["Q26849121"]  = {30,31,43}, -- Women's amateur cycling team
		["Q20639848"]  = {14,15,44}, -- club cycling team
		["Q20653570"]  = {53,54,45}, -- region cycling team
	-- amateur, club and region (merged). All types of team are displayed in a common block
--		["Q114864716"] = {41,42,41}, -- DCU Elite Team
--		["Q26849121"]  = {41,42,41}, -- Women's amateur cycling team		
--		["Q20652655"]  = {41,42,41}, -- amateur cycling team
--		["Q20639848"]  = {41,42,41}, -- club cycling team
--		["Q20653570"]  = {41,42,41}, -- region cycling team
	}

	local p1923 = mw.wikibase.getBestStatements(raceID, 'P1923') -- P1923 is participating teams
	local no = 0 -- Index used for stable sorting
	for _, v in pairs(p1923) do
		if v.mainsnak.snaktype == 'value' then
			no = no + 1
			local teamLink, teamCat, countryID = getTeamLinkCat(v.mainsnak.datavalue.value.id, timeOfRace, true)
			local flagImage = countryID and flag(countryID, timeOfRace) or ''
			teams[#teams + 1] = {flagImage .. ' ' .. teamLink, teamCat,
				teamCats_lot[teamCat] and teamCats_lot[teamCat][3] or 999, no}
		end
	end

	table.sort(teams, function(a,b)
		if a[3] < b[3] then return true end -- First sort key: Order from table teamCats_lot
		if a[3] > b[3] then return false end
		return a[4] < b[4] -- Second key is the index to ensure stable sorting
	end)

	local function getHeader(CatID, count)
		local header, sitelink
		if teamCats_lot[CatID] then
			local done=false
			if CatID=="Q2466826" then --name changed after 2020
				local year = timeOfRace and tonumber(string.sub(timeOfRace, 2, 5))
				if year and year>2019 then
					if count == 1 then
						header_label = translate("headoftableIII",32, w_race) -- singular name
					else
						header_label = translate("headoftableIII",33, w_race) -- plural name
					end
					done=true
				end
			end
			
			if done==false then
				if count == 1 then
					header_label = translate("headoftableIII",teamCats_lot[CatID][1], w_race) -- singular name
				else
					header_label = translate("headoftableIII",teamCats_lot[CatID][2], w_race) -- plural name
				end
			end
			if CatID=='Q78464255' then
				sitelink=wikibase.getSitelink('Q382927') --continental
			else
				sitelink=wikibase.getSitelink(CatID)
			end

			if sitelink ~= nil then 
				header = '[['..sitelink..'|'..header_label..']]'
			else
				header= header_label
			end
		end

		local tHeader=  mw.html.create('span'):css('font-size','1.2em'):css('font-weight','bold')
		if not header then
			-- Unknown team category. Get the label for the entity to display if possible
			header = (CatID and getLabelFallback(CatID)) or 'Unknown team category'
			tHeader:css('text-transform','capitalize')
		end
		tHeader:wikitext(header)
		
		-- Set parameter to show team count in front of each category
		local tTag=''
		local showcounter = 2
		if count >= showcounter then
			tTag=mw.html.create('small'):wikitext(' (' .. count ..')')
		end
		return tostring(tHeader)..tostring(tTag)
	end

	local oldOrder = 0
	local oldCatID
	local count = 0
	local list = ''
	local header
	
	local resultTable = mw.html.create('table')
	:cssText("max-width:95%; padding:0.5em; margin-right:1em; border:1px solid var(--border-color-subtle, #c8ccd1)")
	local tCell = resultTable:tag('tr'):tag('td')

	for _, team in ipairs(teams) do
		local order = team[3]
		if order ~= oldOrder then --new cat
			if oldOrder > 0 then
				header = getHeader(oldCatID, count)
				tCell:wikitext(header)
				tCell:node(tOl)
			end
			count = 1
			oldOrder = order
			tOl = mw.html.create('ul') --reinit
		else
			count = count + 1
		end
		oldCatID = team[2]
        tOl:tag('li')
		:cssText("width:20em;display:inline-block;vertical-align:text-top")
		:wikitext(team[1])
	end
	--add last row
	header = getHeader(oldCatID, count)
	tCell:wikitext(header)
	tCell:node(tOl)

	local wd_link = mw.html.create('span'):css('float',floattable):wikitext(wdLink(raceID .. '#P1923'))
	if arwiki_totemplate then wd_link = wdLink(raceID .. '#P1923') end
	local tableFooter1=mw.html.create('tr')
	tCell=tableFooter1:tag('td')
	:addClass('navigation-only')
	:cssText('border-top: 2px '..backgroundColor..' solid; font-size: 80%;')
	tCell:wikitext(tostring(wd_link))
	
	resultTable:node(tableFooter1)
	return resultTable
end

--== F) Classifications
function p.UCIclassification(frame)
	local tempID, lf=get_and_checkID(frame)
	local s = {
		header_function = "headoftableII", -- translations are in function headoftableII
		header_1 = 19, -- translation 10 in function headoftableII is printed in the upper part of the table header
		header_2 = {1, 2, 7}, -- translations 1, 2, 3, 7 in function headoftableII are printed in this order in the lower part of the table header
		item =tempID,
		property = 'P3494', -- property to use for this table
		team_classification = false, -- it is not a team classification table, its a rider classification table
		background = 'color', -- there is a background color for the first row
		display_team=false,
		max_rank_displayed=100000, --unlimited the whole team must be displayed
		lf=lf
		}
	return new_classification(s, frame)
end

function p.pointsclassification(frame)
	local tempID, lf=get_and_checkID(frame)
	local s = {
		header_function = "headoftableII", -- translations are in function headoftableII
		header_1 = 10, -- translation 10 in function headoftableII is printed in the upper part of the table header
		header_2 = {1, 2, 3, 7}, -- translations 1, 2, 3, 7 in function headoftableII are printed in this order in the lower part of the table header
		item = tempID,
		property = 'P3494', -- property to use for this table
		team_classification = false, -- it is not a team classification table, its a rider classification table
		background = 'color', -- there is a background color for the first row
		max_rank_displayed=10,
		lf=lf
		}
	return new_classification(s, frame)
end

function p.teamsclassificationbytime(frame)
	local tempID, lf=get_and_checkID(frame)
	local s = {
		header_function = "headoftableII", -- translations are in function headoftableII
		header_1 = 14, -- translation 10 in function headoftableII is printed in the upper part of the table header
		header_2 = {3, 2, 4}, -- translations 3, 2, 4 in function headoftableII are printed in this order in the lower part of the table header
		item = tempID,
		property = 'P3497', -- property to use for this table
		team_classification = true, -- it is a team classification table, its not a rider classification table
		background = 'strong', -- there is no background color for the first row, but the first row is formated strong
		max_rank_displayed=10,
		lf=lf
	}
	return new_classification(s, frame)
end

function p.teamsclassificationbypoints(frame)
	local tempID, lf=get_and_checkID(frame)
	local s = {
		header_function = "headoftableII", -- translations are in function headoftableII
		header_1 = 15, -- translation 10 in function headoftableII is printed in the upper part of the table header
		header_2 = {3, 2, 7}, -- translations 3, 2, 7 in function headoftableII are printed in this order in the lower part of the table header
		item = tempID,
		property = 'P3496', -- property to use for this table
		team_classification = true, -- it is a team classification table, its not a rider classification table
		background = 'strong', -- there is no background color for the first row, but the first row is formated strong
		max_rank_displayed=10,
		lf=lf
		}
	return new_classification(s, frame)
end

function p.stageclassification(frame)
	local tempID, lf=get_and_checkID(frame)
	local s = {
		header_function = "headoftableII", -- translations are in function headoftableII
		header_1 = 8, -- translation 10 in function headoftableII is printed in the upper part of the table header
		header_2 = {1, 2, 3, 4}, -- translations 1, 2, 3, 4 in function headoftableII are printed in this order in the lower part of the table header
		item = tempID,
		property = 'P2417', -- property to use for this table
		team_classification = false, -- it is not a team classification table, its a rider classification table
		background = false, -- there is no background color for the first row
		display_ref = get_arg(2, frame,true) == 0 and 0 or 1,
		max_rank_displayed=10,
		lf=lf
		}
	return new_classification(s, frame)
end

function p.generalclassification(frame)
	local tempID, lf=get_and_checkID(frame)
	local s = {
		header_function = "headoftableII", -- translations are in function headoftableII
		header_1 = 9, -- translation 10 in function headoftableII is printed in the upper part of the table header
		header_2 = {1, 2, 3, 4}, -- translations 1, 2, 3, 4 in function headoftableII are printed in this order in the lower part of the table header
		item = tempID,
		property = 'P2321', -- property to use for this table
		team_classification = false, -- it is not a team classification table, its a rider classification table
		background = 'color', -- there is a background color for the first row
		display_ref = get_arg(2, frame,true) == 0 and 0 or 1,
		max_rank_displayed=25,
		lf=lf
		}
	return new_classification(s, frame)
end

function p.generalclassificationpoint(frame)
	local tempID, lf=get_and_checkID(frame)
	local s = {	
		header_function = "headoftableII", -- translations are in function headoftableII
		header_1 = 9, -- translation 10 in function headoftableII is printed in the upper part of the table header
		header_2 = {1, 2, 3, 7}, -- translations 1, 2, 3, 7 in function headoftableII are printed in this order in the lower part of the table header
		item = tempID,
		property = 'P2321', -- property to use for this table
		team_classification = false, -- it is not a team classification table, its a rider classification table
		background = 'color', -- there is a background color for the first row
		display_ref = get_arg(2, frame,true) == 0 and 0 or 1,
		max_rank_displayed=25,
		lf=lf
		}
	return new_classification(s, frame)	
end		

function p.generalclassificationforttt(frame)
	local tempID, lf=get_and_checkID(frame)
	local s = {
		header_function = "headoftableII", -- translations are in function headoftableII
		header_1 = 9, -- translation 10 in function headoftableII is printed in the upper part of the table header
		header_2 = {3, 2, 4, 5, 6}, -- translations 3, 2, 4, 5, 6 in function headoftableII are printed in this order in the lower part of the table header
		item = tempID,
		property = 'P2321', -- property to use for this table
		team_classification = true, -- it is a team classification table, its not a rider classification table
		background = false, -- there is no background color for the first row
		display_ref =get_arg(2, frame,true) == 0 and 0 or 1,
		max_rank_displayed=25,
		lf=lf
	}
	return new_classification(s, frame)
end

function p.teamtimetrialclassification(frame)
	local tempID, lf=get_and_checkID(frame)
	local s = {
		header_function = "headoftableII", -- translations are in function headoftableII
		header_1 = 8, -- translation 10 in function headoftableII is printed in the upper part of the table header
		header_2 = {3, 2, 4, 5, 6}, -- translations 3, 2, 4, 5, 6 in function headoftableII are printed in this order in the lower part of the table header
		item = tempID,
		property = 'P2417', -- property to use for this table
		team_classification = true, -- it is a team classification table, its not a rider classification table
		background = false, -- there is no background color for the first row
		display_ref = get_arg(2, frame,true) == 0 and 0 or 1,
		max_rank_displayed=25,
		lf=lf
	}
	return new_classification(s, frame)
end

function p.mountainsclassification(frame)
	local tempID, lf=get_and_checkID(frame)
	local s = {
		header_function = "headoftableII", -- translations are in function headoftableII
		header_1 = 11, -- translation 10 in function headoftableII is printed in the upper part of the table header
		header_2 = {1, 2, 3, 7}, -- translations 1, 2, 3, 7 in function headoftableII are printed in this order in the lower part of the table header
		item =  tempID,
		property = 'P4320', -- property to use for this table
		team_classification = false, -- it is not a team classification table, its a rider classification table
		background = 'color', -- there is a background color for the first row
		max_rank_displayed=10,
		lf=lf
		}
	return new_classification(s, frame)
end

function p.sprintsclassification(frame)
	local tempID, lf=get_and_checkID(frame)
	local s = {
		header_function = "headoftableII", -- translations are in function headoftableII
		header_1 = 12, -- translation 10 in function headoftableII is printed in the upper part of the table header
		header_2 = {1, 2, 3, 7}, -- translations 1, 2, 3, 7 in function headoftableII are printed in this order in the lower part of the table header
		item =  tempID,
		property = 'P4322', -- property to use for this table
		team_classification = false, -- it is not a team classification table, its a rider classification table
		background = 'color', -- there is a background color for the first row
		max_rank_displayed=10,
		lf=lf
		}
	return new_classification(s, frame)
end

function p.intermediatesprintclassification(frame)
	local tempID, lf=get_and_checkID(frame)
	local s = {
		header_function = "headoftableII", -- translations are in function headoftableII
		header_1 = 20, -- translation 10 in function headoftableII is printed in the upper part of the table header
		header_2 = {1, 2, 3, 7}, -- translations 1, 2, 3, 7 in function headoftableII are printed in this order in the lower part of the table header
		item =  tempID,
		property = 'P4958', -- property to use for this table
		team_classification = false, -- it is not a team classification table, its a rider classification table
		background = 'color', -- there is a background color for the first row
		max_rank_displayed=10,
		lf=lf
		}
	return new_classification(s, frame)
end

function p.bestyoungclassificationbypoints(frame)
	local tempID, lf=get_and_checkID(frame)
	local s = {
		header_function = "headoftableII", -- translations are in function headoftableII
		header_1 = 13, -- translation 10 in function headoftableII is printed in the upper part of the table header
		header_2 = {1, 2, 3, 7}, -- translations 1, 2, 3, 7 in function headoftableII are printed in this order in the lower part of the table header
		item =  tempID,
		property = 'P4323', -- property to use for this table
		team_classification = false, -- it is not a team classification table, its a rider classification table
		background = 'color', -- there is a background color for the first row
		max_rank_displayed=10,
		lf=lf
		}
	return new_classification(s, frame)
end

function p.bestyoungclassification(frame)
	local tempID, lf=get_and_checkID(frame)
	local s = {
		header_function = "headoftableII", -- translations are in function headoftableII
		header_1 = 13, -- translation 10 in function headoftableII is printed in the upper part of the table header
		header_2 = {1, 2, 3, 4}, -- translations 1, 2, 3, 7 in function headoftableII are printed in this order in the lower part of the table header
		item =  tempID,
		property = 'P4323', -- property to use for this table
		team_classification = false, -- it is not a team classification table, its a rider classification table
		background = 'color', -- there is a background color for the first row
		max_rank_displayed=10,
		lf=lf
		}
	return new_classification(s, frame)
end

function p.u23classification(frame)
	local tempID, lf=get_and_checkID(frame)
	local s = {
		header_function = "headoftableII", -- translations are in function headoftableII
		header_1 = 18, -- translation 10 in function headoftableII is printed in the upper part of the table header
		header_2 = {1, 2, 3, 4}, -- translations 1, 2, 3, 7 in function headoftableII are printed in this order in the lower part of the table header
		item =  tempID,
		property = 'P4323', -- property to use for this table (same as best young classification)
		team_classification = false, -- it is not a team classification table, its a rider classification table
		background = 'color', -- there is a background color for the first row
		max_rank_displayed=10,
		lf=lf
		}
	return new_classification(s, frame)
end

function p.combinationclassification(frame)
	local tempID, lf=get_and_checkID(frame)
	local s = {
		header_function = "headoftableII", -- translations are in function headoftableII
		header_1 = 16, -- translation 10 in function headoftableII is printed in the upper part of the table header
		header_2 = {1, 2, 3, 7}, -- translations 1, 2, 3, 7 in function headoftableII are printed in this order in the lower part of the table header
		item = tempID,
		property = 'P4324', -- property to use for this table
		team_classification = false, -- it is not a team classification table, its a rider classification table
		background = 'color', -- there is a background color for the first row
		max_rank_displayed=10,
		lf=lf
		}
	return new_classification(s, frame)
end

function p.combativeclassification(frame)
	local tempID, lf=get_and_checkID(frame)
	local s = {
		header_function = "headoftableII", -- translations are in function headoftableII
		header_1 = 17, -- translation 10 in function headoftableII is printed in the upper part of the table header
		header_2 = {1, 2, 3, 7}, -- translations 1, 2, 3, 7 in function headoftableII are printed in this order in the lower part of the table header
		item =  tempID,
		property = 'P4321', -- property to use for this table
		team_classification = false, -- it is not a team classification table, its a rider classification table
		background = 'color', -- there is a background color for the first row
		max_rank_displayed=10,
		lf=lf
		}
	return new_classification(s, frame)
end

function p.custompointsclassification(frame)
	local tempID, lf=get_and_checkID(frame)

	local team_title
	local temp=get_arg(4,frame)
	if temp and string.find(temp,"{{{")==nil then 
		team_title=temp
	end
	
	local s = {
		header_function = "headoftableII", -- translations are in function headoftableII
		header_2 = {1, 2, 3, 7}, -- translations 1, 2, 3, 7 in function headoftableII are printed in this order in the lower part of the table header
		header_1_text=get_arg(3,frame) or '', --with lf does not work
		item =  tempID,
		property = get_arg(2,frame), -- property to use for this table
		team_title=team_title, --for old races where there was no team, only bike brands
		team_classification = false, -- it is not a team classification table, its a rider classification table
		background = 'color', -- there is a background color for the first row
		max_rank_displayed=10,
		lf=lf
		}
	return new_classification(s, frame)
end

function p.customtimeclassification(frame)
	local tempID, lf=get_and_checkID(frame)

	local team_title
	local temp=get_arg(4,frame)
	if temp and string.find(temp,"{{{")==nil then 
		team_title=temp
	end
	
	local s = {
		header_function = "headoftableII", -- translations are in function headoftableII
		header_2 = {1, 2, 3, 4}, -- translations 1, 2, 3, 7 in function headoftableII are printed in this order in the lower part of the table header
		header_1_text=get_arg(3,frame) or '',
		item = tempID,
		property = get_arg(2,frame), -- property to use for this table
		team_title=team_title, --for old races where there was no team, only bike brands
		team_classification = false, -- it is not a team classification table, its a rider classification table
		background = 'color', -- there is a background color for the first row
		max_rank_displayed=10,
		lf=lf
		}
	return new_classification(s, frame)
end


function p.customteamclassificationbypoints(frame)
	local tempID, lf=get_and_checkID(frame)

	local team_title
	local temp=get_arg(4,frame)
	if temp and string.find(temp,"{{{")==nil then 
		team_title=temp
	end
	
	local s = {
		header_function = "headoftableII", -- translations are in function headoftableII
		header_2 = {3, 2, 7}, -- translations 1, 2, 3, 7 in function headoftableII are printed in this order in the lower part of the table header
		header_1_text=get_arg(3,frame) or '', --with lf does not work
		item =  tempID,
		property = get_arg(2,frame), -- property to use for this table
		team_title=team_title, --for old races where there was no team, only bike brands
		team_classification = true, -- it is not a team classification table, its a rider classification table
		background = 'color', -- there is a background color for the first row
		max_rank_displayed=10,
		lf=lf
		}
	return new_classification(s, frame)
end

function p.customteamclassificationbytime(frame)
	local tempID, lf=get_and_checkID(frame)

	local team_title
	local temp=get_arg(4,frame)
	if temp and string.find(temp,"{{{")==nil then 
		team_title=temp
	end
	
	local s = {
		header_function = "headoftableII", -- translations are in function headoftableII
		header_2 = {3, 2, 4}, -- translations 1, 2, 3, 7 in function headoftableII are printed in this order in the lower part of the table header
		header_1_text=get_arg(3,frame) or '', --with lf does not work
		item =  tempID,
		property = get_arg(2,frame), -- property to use for this table
		team_title=team_title, --for old races where there was no team, only bike brands
		team_classification = true, -- it is not a team classification table, its a rider classification table
		background = 'color', -- there is a background color for the first row
		max_rank_displayed=10,
		lf=lf
		}
	return new_classification(s, frame)
end

function new_classification(s, frame)
	local country = getCountryBool(no_country_classification)
	local lf = s.lf
	local raceID = s.item
	local w_race=isWomenrace(raceID)

	--[=[ It is possible to give the classification tables in the article commands to change the standard behaviour. They could look like this:
	{{Cycling race/teamsclassificationbytime|Q18574623|newline=false|country=true}}
	{{Cycling race/teamsclassificationbytime|Q18574623|country= false|newline=false}}
	{{Cycling race/teamsclassificationbypoints|Q18574623|newline =true|country=true}}
	{{Cycling race/teamsclassificationbypoints|Q18574623|newline= true}}
	{{Cycling race/teamsclassificationbypoints|Q18574623|newline = false|country=false}}
	{{Cycling race/teamsclassificationbytime|Q18574623|newline=true|country=true}}

	One additional parameter is "newline" with the values "true" or "false". "newline" says, if there is a line brake after the table. Standard is
	no line break after the tables stageclassification and teamtimetrialclassification.
	The second parameter is "country" with the values "true" or "false". "country" tells the module to print the country column or not.
	Most wikis have as standard to print the country columns, some wikis prefer as standard not to show the country column. A few lines above,
	the command "if wiki == 'da' then country = false end" tells that daWiki do not want to see the country colums as standard. You can add your wiki
	here in, if you do not want to see them as standard. With the new parameter editors are able to tell the module in the article what to do.
	]=]

	local timeOfRace = getTimeOfRace(raceID, true)

	local plus = ''

	if get_arg('country',frame)~=nil then -- switch country column on or off in the article
		if get_arg('country',frame) == 'true' and l10n["country_name_list"] then country = true end
		if get_arg('country',frame) == 'false' then country = false end
	end
	local tableHeader2_size = #s.header_2
	
	local max_rank_displayed=s.max_rank_displayed
	for _, p31 in statements(raceID, 'P31') do
		if data.stages[p31.mainsnak.datavalue.value.id] then	
			max_rank_displayed=10 --limit general ranking to 10 except for not stage
		end
	end
	local temp=get_arg('max_rank_displayed',frame)
	if temp and temp~='' and string.find(temp,"{{{")==nil then
		max_rank_displayed=tonumber(temp)
	end

	if s.header_1_text ==nil then s.header_1_text=translate(s.header_function,s.header_1,w_race) end --for custom title
	local team_translation_index=3
	if s.team_title == nil then s.team_title=translate(s.header_function,team_translation_index,w_race) end --translation for team has index "3"
	
	local tableBody = mw.html.create('table')
		:addClass('sortable')
		:attr('cellpadding', '0')
		:attr('cellspacing', '0')
		:css('border' , '0')

	local wd_link = wdLink( raceID .. '#' .. s.property )
	local wd_span = mw.html.create('span'):css('float','left'):wikitext(wd_link)
	if wiki == "ar" then
		if arwiki_totemplate then wd_span = wd_link
		else wd_span = mw.html.create('span'):css('float','right'):wikitext(wd_link)
		end end

	tableBody:tag('tr'):tag('th')
    :attr('colspan', tostring(tableHeader2_size + 1)):cssText("padding:2px 2px; text-align:center; color:inherit; background-color:"..backgroundColor)
	:wikitext(tostring(wd_span)..s.header_1_text)

	header= tableBody:tag('tr'):cssText("text-align:center;padding:2px 2px;white-space:nowrap")
	for i, k in ipairs(s.header_2) do
		if i ~= 2 or country then
			local header_text
			if k == team_translation_index then --for team
			    header_text=s.team_title
			else
			    header_text=translate(s.header_function,k,w_race)
			end
			local head =header:tag('th'):wikitext(header_text)
			if i == 1 then
				head:attr('colspan','2')
			end
		end
	end

	local t_Body = {} --contains all rows
	local tCell, bg_color, tStyle, temp, temp2
	local claims = mw.wikibase.getAllStatements(raceID, s.property)
	for l, m in pairs(claims) do -- look into all statements
		if m.mainsnak.snaktype == 'value' then
			local riderID = m.mainsnak.datavalue.value.id
			local q = m.qualifiers or {}
			local rank, riderLink, gender, countryID, teamLink
			local flagLink, countryName = '', ''
			local h = {
				jersey = {}, -- lots of jerseyID
				value = {'', '', '', ''} -- points, time, time_gap, speed
			}
			
			if q.P1352 and q.P1352[1].snaktype == 'value' then -- P1352 is ranking
				rank = tonumber(q.P1352[1].datavalue.value.amount)
			else
				rank = ''
			end
			
			if q.P1534 and q.P1534[1].snaktype == 'value' then
				local dnf=q.P1534[1].datavalue.value.id
				if dnf=='Q1210380' then riderDNF =translate("startlist",6,w_race)--"HD","NP","DQ"
					elseif dnf=='Q54881674' or dnf=='Q7113430' then riderDNF =translate("startlist",7,w_race)
					elseif dnf=='Q1210382' then riderDNF =translate("startlist",8,w_race)
					elseif dnf=='Q1229261' then riderDNF =translate("startlist",9,w_race)
					else riderDNF=''
				end
			else 
				riderDNF=''	
			end

			local cancelled=isdisqualified(m,q)

			if wiki == 'es' or wiki == 'fr' or wiki == 'ast' then
				--[[ These wikis need the gender to display the rank correct. Other wikis can skip this. ]]
				gender = getGenderCode(riderID, 'n')
			end

			h.value[1] = qualifieramount(m, 'P1358')
			h.value[2] = qualifieramount(m, 'P2781')
			if q.P2911 and q.P2911[1].snaktype == 'value' then -- P2911 is time gap
				h.value[3] = tonumber(q.P2911[1].datavalue.value.amount)
				plus = '+ '
			end
			h.value[4] = qualifieramount(m, 'P2052')
			if q.P2912 then -- P2912 is distinctive jersey
				for _, v in pairs(q.P2912) do
					if v.snaktype == 'value' then
						table.insert(h.jersey, v.datavalue.value.id)
					end
				end
			end

			if s.team_classification then
				local _
				teamLink, _, countryID = getTeamLinkCat(riderID, timeOfRace, true)
			else
				riderLink = getRiderLink(riderID,timeOfRace)..(getReference(lf,m) or '')
				teamLink = getTeam(riderID, timeOfRace, q)
				countryID = getNationality(riderID, timeOfRace,q)
			end
			if countryID then
				flagLink = flag(countryID, timeOfRace)
				if country then
					countryName = getCountryName(countryID)
				end
			end

			-- find the right background color if a rider has more then one jersey
			-- see Wikidata:WikiProject Cycling/Kit to translate/Jerseys
			bg_color=nil
			if h.jersey[1] then
				for _, jersey in pairs(h.jersey) do
					if data.bg_color_table[jersey] then
						bg_color = data.bg_color_table[jersey]
						break
					end
				end
			end
			
			tStyle=''
			if rank == 1 then
				if s.background then -- values are 'strong' or 'color'
					tStyle = tStyle ..'font-weight:bold;' -- winner is formated bold
					if s.background == 'color' then
						if h.jersey[1] and bg_color then -- background color of winner depending on jersey
							tStyle = tStyle .. 'background-color:' ..bg_color
						end
					end
				end
			end

			local tBody = mw.html.create('tr'):cssText(tStyle) -- a row
			tBody:tag('td'):cssText("text-align:center;padding:2px 0.5em 2px 0.5em;white-space:nowrap;"..cancelled)
			:wikitext(number(gender, rank, wiki))
			tCell= tBody:tag('td'):cssText("text-align:" .. textalign .. ";padding:0 0.2em 0 0.2em;"..cancelled)

			if not s.team_classification then
				if country then
					tCell:wikitext(riderLink .. jersey(h.jersey) )
					tBody:tag('td'):wikitext( flagLink ..' '.. countryName)
				else
					tCell:wikitext(flagLink .. ' ' .. riderLink .. jersey(h.jersey))
				end
				if s.display_team~=false then
					tBody:tag('td'):cssText("text-align:".. textalign ..";padding:0 0.2em 0 0.2em")
					:wikitext(teamLink or '')
				end
			else --team
				if country then
					tCell:wikitext(teamLink .. jersey(h.jersey))
					tBody:tag('td'):wikitext(flagLink .. ' ' .. countryName)
				else
					tCell:wikitext(flagLink .. ' ' .. teamLink .. jersey(h.jersey))
				end
			end

			if s.header_2[4] == 4 then -- for table stageclassification, generalclassification, adds time and time gap
				if riderDNF=='' then
					if rank == 1 and h.value[2] then
						temp=calculateTime(h.value[2])
					elseif rank == 1 and h.value[3]==nil then --avoid a plus with nothing
						temp=''
					else
						temp=plus .. calculateTime(h.value[3])
					end
				else
					temp=riderDNF
				end
				tBody:tag('td'):cssText("text-align:right;padding:0 0.2em 0 0.2em"):wikitext(temp)
			end

			if s.header_2[4] == 7 or (s.header_2[3] == 7 and s.header_2[1] == 1) then -- for table pointsclassification, adds points
				--trick for UCI classification
				if riderDNF=='' then
					if h.value[1] then temp=h.value[1] else temp='' end
					tCell=tBody:tag('td'):cssText("text-align:right;padding:0 0.2em 0 0.2em")
					:wikitext(temp)	
					if type(h.value[1]) == "number" then
						if h.value[1] > 1 then
							temp2=translate("unit",7,w_race)
						else
							temp2=translate("unit",6,w_race)
						end
						tCell:tag('span'):cssText("font-size:80%"):wikitext(temp2)	
					end
				else
					tBody:tag('td'):cssText("text-align:right;padding:0 0.2em 0 0.2em"):wikitext(riderDNF)	
				end
			end

			if s.header_2[3] == 4 then
				if s.property == 'P2417' or s.property == 'P2321' then
					-- for tables teamtimetrialclassification or generaltttclassification, adds time
					tBody:tag('td'):cssText("text-align:right;padding:0 0.2em 0 0.2em")
					:wikitext(calculateTime(h.value[2]))
				end
			end

			if s.property == 'P3497' then -- for table teambytimeclassification, adds time and time gap
				if rank == 1 then 
					temp=calculateTime(h.value[2])
				else
					temp=plus .. calculateTime(h.value[3])
				end
				tBody:tag('td'):cssText("text-align:right;padding:0 0.2em 0 0.2em"):wikitext(temp)
			end

			if s.property == 'P3496' then -- for table teambypointsclassification, adds points
				tCell=tBody:tag('td'):cssText("text-align:right;padding:0 0.2em 0 0.2em")
			    :wikitext(h.value[1])
				if type(h.value[1]) == "number" then
					if h.value[1] > 1 then
						temp2=translate("unit",7,w_race)
					else
						temp2=translate("unit",6,w_race)
					end
					tCell:tag('span'):cssText("font-size:80%"):wikitext(temp2)	
				end
			end

			if s.header_2[4] == 5 then -- for table teamtimetrialclassification, adds time gap
				if l > 1 then temp= plus else temp='' end
				tBody:tag('td'):cssText("text-align:right;padding:0 0.2em 0 0.2em"):wikitext(temp..calculateTime(h.value[3]))	
			end

			if s.header_2[5] == 6 then -- for table teamtimetrialclassification, adds speed
				tCell=tBody:tag('td'):cssText("text-align:right;padding:0 0.2em 0 0.2em")
				if type(h.value[4]) == "number" then 
					tCell:wikitext(mw.ustring.format('%.3f', h.value[4]))
					:tag('span'):cssText("font-size:80%"):wikitext(translate("unit",5,w_race))
				end
			end
			
			if rank~='' and rank<=max_rank_displayed then --else no display
				if riderDNF=='' then
					table.insert(t_Body, {sortkey=(type(rank) == 'number') and rank or 999, body=tostring(tBody)})
				else --disqualified should be higher than not disqualified if the ranking was revided
					table.insert(t_Body, {sortkey=(type(rank) == 'number') and rank-0.1 or 999, body=tostring(tBody)})
				end
			end
		end
	end
	
    tableBody=sortAndConcat(t_Body, tableBody)
	local tableFooter1,tableFooter2
	if s.display_ref == 1 or wiki == "ar" then
		tableFooter1=mw.html.create('tr')
		tCell=tableFooter1:tag('td')
		:addClass('navigation-only')
		:cssText('border-top: 2px '..backgroundColor..' solid; font-size: 80%;')
		tableFooter2=mw.html.create('tr')
		tCell=tableFooter2:tag('td')
		:cssText("text-align:right")
		tCell:tag('small')
		:wikitext(race_reference(raceID,lf))
	end
	
	--general table style and last line
	local tableStyle, tableNewline
	if get_arg('newline',frame) == 'false' then -- parameter newline in WP article is 'false'
		tableStyle = "float:" .. floattable .. "; margin-right:0.5em; border:1px solid var(--border-color-subtle, #c8ccd1)"
		tableNewline = ''
	end
	if get_arg('newline',frame) == 'true' then -- parameter newline in WP article is 'true'
		tableStyle = "border:1px solid var(--border-color-subtle, #c8ccd1)"
		tableNewline = '<br style="clear:left;">'
	end
	if get_arg('newline',frame) == nil then -- no second parameter, compatible to the old code
		if s.property == 'P2417' then --stageclassification
			tableStyle = "float:"..floattable.."; margin-right:0.5em; border:1px solid var(--border-color-subtle, #c8ccd1)"
			tableNewline = ''
		else
			tableStyle = "border:1px solid var(--border-color-subtle, #c8ccd1)"
			tableNewline = '<br style="clear:left;">' -- everything else
		end
	end

	local finalTable= mw.html.create('table'):cssText(tableStyle)
	finalTable:tag('tr'):tag('td')
	:node(tableBody)
	if tableFooter1 then
		finalTable:node(tableFooter1)
		finalTable:node(tableFooter2)
	end

	return tostring(finalTable)..tableNewline
end

--=== G) Infobox ===
function p.infobox(frame) -- normal infobox
	return infobox_main(frame,0)
end

function p.seasoninfobox(frame) -- season infobox
	return infobox_main(frame,1)
end

function p.champinfobox(frame) -- champ infobox
	return infobox_main(frame,2)
end

function infobox_main(frame, selector)
	local WDlink_on = (wiki == "mk" or wiki == "ja")

	-- If true, winners will the team of the cyclist
	local team = true
	local details, others, winners, plural
	
	local entityID, lf = get_and_checkID(frame)
	local w_race=isWomenrace(entityID)
	
	if selector==0 then -- normal infobox
		details = {
			{ name = translate("infobox",2,w_race)}, -- course
			{ name = translate("infobox",3,w_race), name_plural = translate("infobox",4,w_race)}, -- competition
			{ name = translate("infobox",5,w_race)}, -- stages
			{ name = translate("infobox",6,w_race), name_plural = translate("infobox",7,w_race)}, -- date
			{ name = translate("infobox",8,w_race)}, -- distance
			{ name = translate("infobox",9,w_race), name_plural = translate("infobox",10,w_race)}, -- country
			{ name = translate("infobox",11,w_race)}, -- start place
			{ name = translate("infobox",12,w_race)}, -- endplace
			{ name = translate("infobox",13,w_race)}, -- teams
			{ name = translate("infobox",14,w_race)}, -- participants at start
			{ name = translate("infobox",15,w_race)}, -- participants at end
			{ name = translate("infobox",16,w_race)}, -- speed
			{ name = translate("infobox",43,w_race)}, -- elevation
			{ name = translate("infobox",17,w_race)}, -- cost
			{ name = translate("infobox",32,w_race), special = true}, -- special 1
			{ name = translate("infobox",33,w_race), special = true}, -- special 2
			{ name = translate("teaminfobox",13,w_race)}, -- official web site
		}
	elseif selector==1 then  -- season infobox
		details = {
			{ name = translate("infobox",46,w_race)}, -- edition (1)
			{ name = translate("infobox",3,w_race), name_plural = translate("infobox",4,w_race)}, -- competition (2)
			{ name = translate("infobox",6,w_race), name_plural = translate("infobox",7,w_race)}, -- date (3)
			{ name = translate("infobox",45,w_race), name_plural=translate("infobox",71,w_race)}, -- rasing (4)		
			{ name = translate("infobox",47,w_race), name_plural = translate("infobox",48,w_race)}, -- location (country) (5)
			{ name = translate("infobox",49,w_race), name_plural = translate("infobox",50,w_race)}, -- organizer (6)
			{ name = translate("infobox",63,w_race), name_plural = translate("infobox",63,w_race)}, -- team class (7)	
			{ name = translate("infobox",32,w_race), special = true}, -- special 1
			{ name = translate("infobox",33,w_race), special = true}, -- special 2
			{ name = translate("teaminfobox",13,w_race)}, -- official web site
		}
	else  -- champ infobox
		 details = {
			{ name = translate("infobox",46,w_race)}, -- edition (1)
			{ name = translate("infobox",6,w_race), name_plural = translate("infobox",7,w_race)}, -- date (2)
			{ name = translate("infobox",9,w_race), name_plural = translate("infobox",10,w_race)}, -- country (3)	
			{ name = translate("infobox",67,w_race), name_plural = translate("infobox",68,w_race)}, -- location (city) (4)
			{ name = translate("infobox",61,w_race), name_plural = translate("infobox",62,w_race)}, -- arena / stadion (5)
			{ name = translate("infobox",60,w_race)}, -- medals (6)
			{ name = translate("infobox",13,w_race)}, -- team (7)			
			{ name = translate("infobox",49,w_race), name_plural = translate("infobox",50,w_race)}, -- organizer (8)
			{ name = translate("infobox",32,w_race), special = true}, -- special 1
			{ name = translate("infobox",33,w_race), special = true}, -- special 2
			{ name = translate("teaminfobox",13,w_race)}, -- official web site
		}
	end
	others = get_others_dic()

	if selector==0 then -- normal infobox
		 winners = {
			{ name = translate("infobox",19,w_race), QID = 'Q20882667' }, -- first
			{ name = translate("infobox",20,w_race), QID = 'Q20882668' }, -- second
			{ name = translate("infobox",21,w_race), QID = 'Q20882669' }, -- third
			{ name = translate("infobox",22,w_race), QID = 'Q20883007' }, -- points
			{ name = translate("infobox",23,w_race), QID = 'Q20883212' }, -- mountains
			{ name = translate("infobox",24,w_race), QID = 'Q20883328' }, -- sprints
			{ name = translate("infobox",25,w_race), QID = 'Q20883139' }, -- youth
			{ name = translate("infobox",26,w_race), QID = 'Q101246973' }, -- supercombativity			
			{ name = translate("infobox",26,w_race), QID = 'Q20893983' }, -- combativity
			{ name = translate("infobox",35,w_race), QID = 'Q27067359' }, -- volantes
			{ name = translate("infobox",36,w_race), QID = 'Q27067170' }, -- regularity
			{ name = translate("infobox",27,w_race), QID = 'Q20893979' }, -- combination
			{ name = translate("infobox",38,w_race), QID = 'Q27907715' }, -- breakaway
			{ name = translate("infobox",39,w_race), QID = 'Q27907747' }, -- azzurri
			{ name = translate("infobox",40,w_race), QID = 'Q28092831' }, -- rookie
			{ name = translate("infobox",28,w_race), QID = 'Q20882921' }, -- teams
			{ name = translate("infobox",37,w_race), QID = 'Q27104269' }, -- teamspoints
			{ name = translate("infobox",41,w_race), QID ='Q61976850' },-- amateur
			{ name = translate("infobox",42,w_race), QID ='Q61976872' } --nationality
		}
	elseif selector==1 then -- season infobox
		 winners = {
			{ name = translate("infobox",52,w_race), QID = 'Q20882667' }, -- individual (first)
			{ name = translate("infobox",53,w_race), QID = 'Q20883139' }, -- youth
			{ name = translate("infobox",54,w_race), QID = 'Q27104269' }, -- team (teamspoints)
			{ name = translate("infobox",55,w_race), QID = 'Q98959152' }, -- team GS-I
			{ name = translate("infobox",56,w_race), QID = 'Q98959153' }, -- team GS-II
			{ name = translate("infobox",57,w_race), QID = 'Q98959155' }, -- team GS-III
			{ name = translate("infobox",58,w_race), QID = 'Q72068715' }, -- country
			{ name = translate("infobox",59,w_race), QID = 'Q72068724' }  -- country U23
		}
	end -- Champ infobox has no winners
    
	getLocalContent(details, lf.args)
	getLocalContent(others, lf.args)
	
	if selector==0 or selector==1 then
		getLocalContent(winners, lf.args)
	end

	local timeOfRace, class
	local icon = (firstValue(entityID, 'P641','id') == "Q3609") and -- P641 is 'sport', Q3609 is 'road bicycle racing'
		picto_road or ''

	local name =  getLabelFallback(entityID) or ''
	infoGetOthers(others, entityID)	

	if not details[1].content then -- course
		-- For FR Wiki and Wikidata, exception that permit to display 1er, 2e... for the edition number ;
		-- for RU  -й is written after the value of P393
		local nr = firstValue(entityID, 'P393') -- P393 is 'edition number'
		if nr then
			if wiki == 'fr' then nr = (nr == 1) and "1<sup>re</sup> " or (nr .. "<sup>e</sup> ")
			elseif wiki == "nl" then nr = nr .. "e "
			elseif wiki == "ru" then nr = nr .. "-й "
			elseif wiki == "eo" then nr = nr .. "-a "
			elseif wiki == "hu" then nr = nr .. ". "
			else nr = nr .. ". "
			end
		end
		local is_a

		local classID = firstValue(entityID, 'P279', 'id')
		--fallback
		if classID then 
			class = classLinkFn(classID)
		else
			for _, p31 in statements(entityID, 'P31') do -- P31 is 'instance of'
				local instanceOf = p31.mainsnak.datavalue.value.id
				if instanceOf ~= "Q27020041" and data.class_dic[instanceOf] then
					class = classLinkFn(instanceOf)
					break
				end
			end
		end
		
		local season = firstValue(entityID, 'P3450', 'id') -- P3450 is 'sports season of league or competition'
		if season then
			is_a = raceLink(season)
		else
			--normally there should be only a p31
			for _, p31 in statements(entityID, 'P31') do -- P31 is 'instance of'
				local instanceOf = p31.mainsnak.datavalue.value.id
				if instanceOf ~= 'Q27968055' and instanceOf ~= 'Q27020041' then -- Q27020041 is 'sports season'
					is_a = raceLink(instanceOf)
					break
				end
			end
		end

		if nr and is_a then
			details[1].content = nr .. ' ' .. is_a
		end
	end

	if selector==0 or selector==1 then
		if not details[2].content then -- competition
			-- Class of a cycling race. Class is: 1.UWT, 2.UWT, 1.HC, ... add new classes, no problem
			-- Competition of the cycling race : UCI World Tour 2016, UCI Europe Tour 2016...
			local tours = {}
			for _, p361 in statements(entityID, 'P361') do -- P361 is 'part of'
				tours[#tours + 1] = raceLink(p361.mainsnak.datavalue.value.id)
			end
			if tours[1] then
				if #tours > 1 then
					details[2].name = details[2].name_plural
				end
				if class then
					tours[1] = tours[1] .. ' ' .. class
				end
				details[2].content = table.concat(tours, '<br/>')
			end
		end
	end
	
	if selector==0 then
		if not details[3].content then -- stages
			local stages = #wikibase.getAllStatements(entityID, 'P527') -- P527 is 'has part'
			if stages > 0 then
				details[3].content = stages
			end
		end
	end

	local index_date, index_official_site
	if selector==0 then
		index_date=4
		index_official_site=17
	elseif selector==1 then
		index_date=3
		index_official_site=10
	else 
		index_date=2
		index_official_site=11
	end

--	if selector==0 or selector==1 then
		if not details[index_date].content then -- date
			details[index_date].content, timeOfRace, plural = get_formatted_date(entityID, 'infobox')
			if plural then
				details[index_date].name = details[index_date].name_plural
			end
		end
--	end
	
	--from this point the functions differ fundamentally
	if selector==0 then
		local kmdistance
		if not details[5].content then details[5].content, kmdistance = getDistance(entityID, true) end -- distance
	
		infoGetCountry(details,6, entityID, timeOfRace)
		infoGetStartEnd(details,7, entityID, timeOfRace)
	
		if not details[9].content then -- teams
			local teams = #wikibase.getBestStatements(entityID, 'P1923') -- P1923 is 'participating teams'
			if teams > 0 then
				details[9].content = teams
			end
		end
	
		infoGetParticipants(details,10, entityID)
		if not details[10].content or not details[11].content then
			local Allp710= wikibase.getAllStatements(entityID, 'P710')
			if Allp710 and #Allp710~=0 then
				if not details[10].content then details[10].content=#Allp710 end
				if not details[11].content then
					local maxrank=1
					for _, p710 in pairs(Allp710) do -- look into all statements
						local q = p710.qualifiers
						if q and q.P1352 and q.P1352[1].snaktype == 'value' then -- P1352 is ranking
							local riderRank = tonumber(q.P1352[1].datavalue.value.amount)
							if riderRank > maxrank then maxrank = riderRank end
						end
					end
					if maxrank~=1 then details[11].content=maxrank end
				end
			end
		end
	
		if not details[12].content then details[12].content = getSpeed(entityID, true, kmdistance, 'P2321') end --speed
		if not details[13].content then 
			local elevation=getElevation(entityID) 
			if  elevation then details[13].content =elevation else details[13].content = nil end
		end --Elevation
		
		if not details[14].content then -- cost
			local cost = firstValue(entityID, 'P2130') -- P2130 is cost
			if cost then
				details[14].content = dispmoney(cost.amount, cost.unit)
			end
		end

	elseif selector==1 then
		if not details[4].content then -- racing
			local stages = #wikibase.getAllStatements(entityID, 'P527') -- P527 is 'has part'
			if stages > 0 then
				details[4].content = stages
				if stages > 1 then
					details[4].name = details[4].name_plural
				end
			end
		end
		if not details[5].content then -- location
			infoGetPlace(details,5, entityID, timeOfRace) --in GAN version, the separator is , not <br />
		end
		if not details[6].content then -- organizer sitelink
			listWPlink(details, 6, entityID,'P664',true) --org
		end
		if not details[7].content then -- organizer sitelink
			listWPlink(details, 7, entityID,'P2670',true) --team ????
		end
	else --champ
		infoGetCountry(details,3, entityID, timeOfRace)
		if not details[4].content then -- location
			infoGetPlace(details,4, entityID, timeOfRace) --in GAN version, the separator is , not <br />
		end
		if not details[5].content then -- arena / stadion
			listWPlink(details, 5, entityID,'P115',true) 
		end	
		if not details[6].content then -- racing
			local stages = #wikibase.getAllStatements(entityID, 'P527') -- P527 is 'has part'
			if stages > 0 then
				details[6].content = stages
			end
		end
		if not details[7].content then -- teams
			local teams = #wikibase.getBestStatements(entityID, 'P1923') -- P1923 is 'participating teams'
			if teams > 0 then
				details[7].content = teams
			end
		end
		if not details[8].content then -- organizer sitelink
			listWPlink(details, 8, entityID,'P664',true) --org
		end
		
	end

	if not details[index_official_site].content then
		details[index_official_site].content = officialSite(entityID)
	end

	tab = infoInitTab("300px", name, icon)

	if selector==0 then      -- normal infobox
		infoFillOthersDetails(tab, others, details,translate("infobox",1,w_race))
	elseif selector==1 then  -- season infobox
		infoFillOthersDetails(tab, others, details,translate("infobox",69,w_race))
	else                     -- champ infobox
		infoFillOthersDetails(tab, others, details,translate("infobox",70,w_race))
	end
	
	if selector==0 or selector==1 then --no winners for champ
		local winRows=''
		local win = {}
		for _, v in pairs(winners) do
			if not v.content then
				win[v.QID] = ''
			end
		end
		winner(lf,entityID, win, timeOfRace, false, WDlink_on, team, true)
		for _, v in pairs(winners) do
			if not v.content then
				if win[v.QID] ~= '' then
					v.content = win[v.QID]
				end
			end
			if v.content then
				tRow= mw.html.create('tr') :css('vertical-align','top')
				tRow:tag('td'):css('font-weight','bold'):wikitext(v.name)
				tRow:tag('td'):wikitext(v.content)
				winRows=winRows..tostring(tRow) --not elegant
			end
		end
		if winRows~= '' then
			tab:tag('tr'):tag('td'):attr('colspan','2')
			:cssText('border-bottom:5px solid var(--background-color-base, #fff); background-color:'..backgroundColor..'; color:inherit; text-align:center')
			:css('font-weight','bold')
			:wikitext(translate("infobox",18,w_race))
			tab:wikitext(winRows)
		end
	end

	if others[3].content then -- map
		tab:tag('tr'):tag('td'):attr('colspan','2'):css('text-align','center')
		:wikitext("[[File:".. others[3].content .. "|center|300px]]")
		if others[5].content then -- caption
			tab:tag('tr'):tag('td'):attr('colspan','2'):css('text-align','center'):css('font-size','80%')
			:wikitext(others[5].content)
		end
	end
	
	tab:node(getPreviousNextLine(entityID))
	wdDoc(tab, "d:Wikidata:WikiProject Cycling/Documentation/infobox", translate("infobox",34,w_race), entityID)
	return tab
end

--=== H) race infobox
function p.raceinfobox(frame)
	local lang = contentLanguage
	local WDlink_on = (wiki == "mk" or wiki == "ja")
	
	local tRace = {race={
			raceId,
			raceDate,
			future,
			}, 
		  vainqueur= {},
		  }

	local entityID, lf = get_and_checkID(frame)
	local w_race= isWomenrace(entityID)
	
	local details = {
		{ name = translate("raceinfobox",4,w_race)}, -- sport
		{ name = translate("raceinfobox",5,w_race)}, -- creation date
		{ name = translate("raceinfobox",6,w_race)}, -- disparition date
		{ name = translate("raceinfobox",7,w_race)}, -- number of editions
		{ name = translate("raceinfobox",8,w_race)}, -- periodicity
		{ name = translate("raceinfobox",9,w_race)}, -- type , name_plural = translate("infobox",10)
		{ name = translate("raceinfobox",33,w_race), name_plural = translate("raceinfobox",34,w_race)},													--country
		{ name = translate("raceinfobox",10,w_race), name_plural = translate("raceinfobox",11,w_race)}, -- place
		{ name = translate("raceinfobox",12,w_race), name_plural = translate("raceinfobox",13,w_race)}, --org
		{ name = translate("raceinfobox",27,w_race), name_plural = translate("raceinfobox",28,w_race)}, --race director
		{ name = translate("raceinfobox",15,w_race), name_plural = translate("raceinfobox",16,w_race)}, -- Cat
		{ name = translate("raceinfobox",17,w_race)}, -- circuit
		{ name = translate("raceinfobox",14,w_race)}, -- official web site
	}
	local others = get_others_dic()

	local name =  getLabelFallback(entityID) or ''
	infoGetOthers(others, entityID)	
	getLocalContent(details, lf.args)
	getLocalContent(others, lf.args)
	
	local timeOfRace, class

    local listOfNames=getFormerNames(entityID, 'P1448')
	
	local sport_id=firstValue(entityID, 'P641', 'id')
	local icon = (sport_id == "Q3609") and -- P641 is 'sport', Q3609 is 'road bicycle racing'
		picto_road or ''

	--1st ist sport
	if not details[1].content and sport_id then
		details[1].content = WPlinkpure(sport_id)
	end
	
	--creation
	local creation=firstValue(entityID, 'P571', 'time')
	if not details[2].content and creation then
		details[2].content = funcDate(creation, "onlyyear" )
	end

	--disparition
	local disparition=firstValue(entityID, 'P576', 'time')
	if not details[3].content and disparition then
		details[3].content =  funcDate(disparition,"onlyyear")
	end
	
	--populate tRace
	listOfWinners(entityID, tRace,nil,lf)
	
	--number of editions
	if not details[4].content and tRace.numberOfEditions and tRace.lastEditionYear then
		details[4].content = tostring(tRace.numberOfEditions).." (" .. translate("raceinfobox",31,w_race) .. " "..tostring(tRace.lastEditionYear)..")"
	end
	--periodicity
	if not details[5].content then
		details[5].content = getPeriodicity(entityID, tRace)
	end
	--type
	if not details[6].content then
		details[6].content = getType(entityID)
	end
	timeOfRace=nil --could be from last edition
	if not details[7].content then
		infoGetCountry(details,7, entityID, timeOfRace)
	end
	if not details[8].content then
		infoGetPlace(details,8, entityID, timeOfRace)
	end
	
	if not details[9].content then
		listWPlinkChrono(details, 9, entityID, {'P664'}, true, initialYear) --organiser
	end
	
	if not details[10].content then
		listWPlinkChrono(details, 10, entityID, {'P488'}, 'rider', initialYear)	 --race dir
	end
	
	--Class and circuit	
	
	local classContent, circuitLink, numberClass= getClass(entityID)
	if not details[11].content then
		details[11].content = classContent
		if numberClass >1 then
	 		details[11].name = details[11].name_plural
		end
 	end
 	
 	if not details[12].content then
		details[12].content = circuitLink
 	end
 	--Official web site
	if not details[13].content then
		details[13].content = officialSite(entityID)
	end
	--Build the table
	tab = infoInitTab("300px", name, icon)
	--former names
	wiki_listOfNamesAtBottom={'ru'}
	
	local listOfNamesAtBottom = false
	for _, value in pairs(wiki_listOfNamesAtBottom) do -- 
		if value == wiki then listOfNamesAtBottom = true end
	end
	--picture at the top
	infoFillOthersDetails(tab, others, nil,translate("raceinfobox",19,w_race),"260px")
	if not listOfNamesAtBottom then
		if listOfNames and #listOfNames>1 then
			tab:node(addATitle(translate("raceinfobox",18,w_race)))  
			for _, v in pairs(listOfNames) do
				tab:node(addARow(v[2],v[3])) --period, name
			end
		end
	end
    
	infoFillOthersDetails(tab, nil, details,translate("raceinfobox",19,w_race),"260px")

	if listOfNamesAtBottom then
		if listOfNames and #listOfNames>0 then -- except for the ru-wiki, no one uses the display of official names at the bottom anyway 
			tab:node(addATitle(translate("raceinfobox",18,w_race)))  
			for _, v in pairs(listOfNames) do
				tab:node(addARow(v[2],v[3])) --period, name
			end
		end
	end

	if (tRace.lastWinner and tRace.lastWinner~='') or 
	(tRace.maxWinner and tRace.maxWinner~='') then
		tab:node(addATitle(translate("raceinfobox",20,w_race)))
		if (tRace.lastWinner and tRace.lastWinner~='') then
			tab:node(addARow(translate("raceinfobox",21,w_race),tRace.lastWinner))
		end
		if (tRace.maxWinner and tRace.maxWinner~='') then
			tab:node(addARow(translate("raceinfobox",22,w_race),tRace.maxWinner))
		end
	end

	if tRace.nextLink or tRace.lastLink then
		tab:node(addATitle(translate("raceinfobox",23,w_race)))
		local outTable 

		if tRace.lastLink then
		    outTable = mw.html.create('tr')
			local tCell=outTable:tag('td'):attr('colspan','2'):css('text-align','center')
			local lastText="[[File:Crystal Clear app kworldclock.png|left|37px]]"..
			translate("raceinfobox",24,w_race)..
			":<br>'''"..
			tRace.lastLink.."'''"
			tCell:wikitext(lastText)
			tab:node(outTable)
		end	
		
		if tRace.nextLink then
			outTable = mw.html.create('tr')
			local tCell=outTable:tag('td'):attr('colspan','2'):css('text-align','center')
		    local nextText = "[[File:Crystal Clear app kworldclock.png|left|37px]]"..
		    translate("raceinfobox",25,w_race)..
		    ":<br>'''"..
		    tRace.nextLink.."'''"
			tCell:cssText("text-align:center"):wikitext(nextText)
			tab:node(outTable)
		end
	end
	wdDoc(tab, "d:Wikidata:WikiProject Cycling/Documentation/raceinfobox", translate("raceinfobox",26,w_race), entityID)
	return tab
end

--=== I) Team roster
function p.lastteamroster(frame)
	local teamID, lf = get_and_checkID(frame)
	
	local tRace = {race={
		raceId,
		raceDate,
		future,
		}, 
	  vainqueur= {},
	}
	
	listOfWinners(teamID, tRace,true,lf,"P527")
	
	if get_arg(2,frame) ~= nil then
		if mw.ustring.find(mw.ustring.lower(get_arg(2,frame)), "sort") or wiki == "lv" or wiki == "mk" or wiki == "ru" then 
			sort = true 
		else 
			sort = false 
		end
	end	

	local s = {
		sort=sort,
		seasonID=tRace.lastID,
		lf=lf,
		year=tRace.lastEditionYear
	}	

	if tRace.lastID then
		return teamroster_main(s)
	end
end

function p.teamroster(frame)
	local seasonID, lf = get_and_checkID(frame)
	local sort
	--[[
	The word 'sort' is used to sort the riders after the surname. It could look like this in the Wikipedia article
	{{Cycling race/teamroster|Q21769847
	| sort
	}}
	A rider called 'Laurens De Vreese' is sorted after 'De Vreese Laurens'. If you want to sort after 'Vreese Laurens De'
	change that in the code. In lv mkWiki and ruWiki sorting is standard, there is no need to switch sorting on in the article
	]]
	if get_arg(2,frame) ~= nil then
		if mw.ustring.find(mw.ustring.lower(get_arg(2,frame)), "sort") or wiki == "lv" or wiki == "mk" or wiki == "ru" then 
			sort = true 
		else 
			sort = false 
		end
	end	
	
	local s = {
		sort=sort,
		seasonID=seasonID,
		lf=lf
	}
	
	return teamroster_main(s)
end

function teamroster_main(s)
	local flags, pays = {}, {}
	local riderName, riderBirthday,riderTeam, timeTeam, correctlanguage,riderStart, riderEnd
	local riderPosition, riderReason, riderRef, errortext
	local riderReasonTable, riderTablecorrect, riderTablenotcorrect, riderTable = {}, {}, {}, {}
	local labelMissing = false
	local teamID, stagiaire

	local slavicWikis = {mk = true, ru = true}
	local wikiIsSlavic = slavicWikis[wiki]
	local WDlink_on = wiki == "mk" or wiki == "ja" or wiki == "ru" or wiki == "he"
	local tableEndText = ''

	local w_race=isWomenrace(s.seasonID)
	local temp = firstValue(s.seasonID, 'P5138', 'id')
	if temp then teamID = temp end

	local startOfSeason = getTimeOfRace(s.seasonID, true)
	
	if not s.year then	
		label=getLabelFallback(s.seasonID)
		local second_occurrence
		local first_occurrence=string.find(label, "%d%d%d%d")
		if first_occurrence~=nil then
			second_occurrence=string.find(label, "%d%d%d%d",first_occurrence+1)
			if second_occurrence~=nil then
				s.year=string.match(label, "%d%d%d%d",first_occurrence+1) --case Tartu2024
			else
				s.year=string.match(label, "%d%d%d%d")
			end
		end
	end

	for _, p527 in statements(s.seasonID, 'P527') do
		--re-init
		riderName, riderBirthday, correctlanguage=nil, nil, nil
		riderTeam, timeTeam, riderReason, riderRef=nil, nil, nil, nil
		riderStart, riderEnd=nil, nil

		local riderID = p527.mainsnak.datavalue.value.id
		riderName, correctlanguage =getRiderLink(riderID, startOfSeason) --label
		if WDlink_on==true then riderName=riderName..wdLink(riderID) end
		local timeOfRace = startOfSeason
		_, startOfSeasonYear, startOfSeasonMonth, startOfSeasonDay, _=parseDate(startOfSeason, '2040', '12', '31', '','')

		riderBirthday=firstValue(riderID, 'P569','time')

		if not wikiIsSlavic then correctlanguage=true end  --actually we never take a cyrillic name if no latin is found
		local sortkey = findSortKey(riderID, correctlanguage,  wikiIsSlavic)

		for _, q in qualifiers(p527, 'P580') do
			local startdate = q.value['time']
			timeOfRace = startdate
			riderStart = funcDate(trans(startdate,'01', '01') or '', 'small')
		end
		for _, q in qualifiers(p527, 'P582') do
			local enddate=q.value['time']
			riderEnd = funcDate(trans(enddate,'12', '31') or '', 'small')
		end
		riderPosition=getPosition(riderPosition,p527)
		riderReason, riderRef=getReason(riderReason,riderRef,p527, timeOfRace,enddate,s.lf)

		local beginYear, beginMonth, beginDay, endYear, endMonth, endDay, beginDate, endDate, endDatefound, endDatetemp
		local changedTime = '+0000-00-00'

		if teamID == nil then
			local p54 = getStatementForTime(riderID, 'P54', timeOfRace)
			if p54 then teamID = p54.mainsnak.datavalue.value.id end
		else
			for _, v in statements(riderID, 'P54') do -- look into all P54 teams
				stagiaire=nil 
				errortext=''
				local thisteamID = v.mainsnak.datavalue.value.id
				if thisteamID == teamID then
					endDatefound=true
					beginDate, endDate = getStartEndfromQuali(v.qualifiers)
					beginDate, beginYear, beginMonth, beginDay, errortext = parseDate(beginDate, '2040', '01', '01', errortext, ' missing qualifiers by rider')

					if not endDate then endDatefound=false end
					endDate, endYear, endMonth, endDay, _ = parseDate(endDate, beginYear, '12', '31', errortext,'')
					riderReason, riderRef=getReason(riderReason,riderRef,v,timeOfRace,endDate,s.lf)

					if (beginYear == startOfSeasonYear or endYear == startOfSeasonYear) and ((beginYear == startOfSeasonYear and (beginMonth ~= '01' or beginDay ~= '01')) or (endYear == startOfSeasonYear and (endMonth ~= '12' or endDay ~= '31'))) then
						-- riders who start after 1 January or end earlier then 31 December in the season
						riderStart = funcDate(beginDate, 'small')
						if endDatefound then 
							riderEnd = funcDate(endDate, 'small')
						else
							riderEnd = funcDate('+'..beginYear..'-12-31T00:00:00Z', 'small')
						end
						riderPosition=getPosition(riderPosition,v)
					end
				else
					for _, q in qualifiers(v, 'P39') do
						stagiaire =q.value.id
					end
					if not stagiaire then
						endDatefound=true
						beginDate, endDatetemp=getStartEndfromQuali(v.qualifiers)
						if not endDatetemp then endDatefound=false end
						beginDate, beginYear, beginMonth, beginDay, errortext = parseDate(beginDate, '2040', '01', '01', errortext, ' missing qualifiers by rider')
					    endDate, endYear, endMonth, endDay, _ = parseDate(endDatetemp, beginYear, '12', '31', errortext, '')

						if beginYear < startOfSeasonYear or (beginYear == startOfSeasonYear and beginMonth < startOfSeasonMonth) or 
						(beginYear == startOfSeasonYear and beginMonth == startOfSeasonMonth and beginDay < startOfSeasonDay) then -- start time < season time
							if endDatefound then
								if (endDate or '') >= changedTime then -- find maximum end time
									-- Case Pierre-Roger Latour: Chambéry CF (2012 - 2014), time season at 2013
									-- Task: changedTime should be after start time, but before startOfSeason
									if endYear > startOfSeasonYear then 
										changedTime = '+'..startOfSeasonYear..'-12-31T00:00:00Z' 
									else 
										changedTime = endDate or ''
									end
								end
							end
						end
						if changedTime ~= '+0000-00-00' then
							riderTeam = getTeam(riderID, changedTime, nil)
							local _, _, endYear, _, _ = string.find(changedTime, "(%d+)-(%d+)-(%d+)")
							timeTeam = ' ('..endYear..')'
							if wiki == "ar" then timeTeam = endYear end
						end
					end
				end
			end
		end
		--get the country
		local countryID = getNationality(riderID, timeOfRace,q)
		if countryID then
			pays = getCountryName(countryID)
			flags = flag(countryID, timeOfRace)
		end
		--save
		local tRider={
				sortkey=sortkey, 
				riderName=riderName, 
				riderBirthday=riderBirthday, 
				riderTeam=riderTeam, 
				timeTeam=timeTeam,
				riderStart=riderStart, 
				riderEnd=riderEnd, 
				riderPosition=riderPosition, 
				riderReason=riderReason, 
				riderRef=riderRef, 
				errortext=errortext, 
				pays=pays,
				flags=flags
				}
		
		if correctlanguage == true then
			table.insert(riderTablecorrect,tRider )
		else
			table.insert(riderTablenotcorrect, tRider)
		end
	end

	-- sorting names
	if sort == true then
		if #riderTablecorrect~=0 then
			table.sort(riderTablecorrect, function(a,b) return a["sortkey"]<b["sortkey"] end)
		end
		if #riderTablenotcorrect~=0 then
			table.sort(riderTablenotcorrect, function(a,b) return a["sortkey"]<b["sortkey"] end)
		end
	end

	--merge
	for _, v in pairs (riderTablecorrect) do
		table.insert(riderTable, v)
	end
	for _, v in pairs (riderTablenotcorrect) do
		table.insert(riderTable, v)
	end
	local wd_link = mw.html.create('span'):css('float','left'):wikitext(wdLink(s.seasonID..'#P527'))
	if arwiki_totemplate then wd_link = wdLink(s.seasonID .. '#P527') end
	local outTable = mw.html.create('table')
	                        :addClass('sortable')
	                        :attr('cellpadding', '2')
	                        :attr('cellspacing', '0')
	                        :css('border' , '1px solid var(--border-color-subtle, #c8ccd1)')
	                        :css('padding', '3px')
	local th_colspan = 4
	if wiki == "ar" then th_colspan = 5 end
	local tRow=outTable:tag('tr'):css('line-height','1.8em')
	    :css('background-color',backgroundColor)
	    :css('color', 'inherit')
	    :tag('th'):attr('colspan', th_colspan):cssText('text-align:center;white-space:nowrap')
		:wikitext(tostring(wd_link))
	if s.year then	
	    tRow:wikitext(translate("getSquadTableColumn",7,w_race).." "..s.year)
	else
		tRow:wikitext(translate("getSquadTableColumn",7,w_race))
	end
	local header = outTable:tag('tr')
	header:tag('th'):cssText('text-align:center;padding:2px 20px 2px 2px;white-space:nowrap'):wikitext(translate("getSquadTableColumn",1,w_race))
	local textalign = 'center'
	if wiki=='ar' then textalign = 'right' end
	header:tag('th'):cssText('text-align:'..textalign..';padding:2px 20px 2px 2px;white-space:nowrap'):wikitext(translate("getSquadTableColumn",2,w_race))
	if l10n["country_name_list"] and wiki ~= 'lv' and wiki ~= 'ru' and wiki ~= 'da' then
	    header:tag('th'):cssText('text-align:center;padding:2px 20px 2px 2px;white-space:nowrap'):wikitext(translate("getSquadTableColumn",6,w_race))
	end
	if wiki == "ar" then
		header:tag('th'):attr('colspan', 2):cssText('text-align:center;padding:2px 20px 2px 2px;white-space:nowrap'):wikitext(translate("getSquadTableColumn",3,w_race))
	else
		header:tag('th'):cssText('text-align:center;padding:2px 20px 2px 2px;white-space:nowrap'):wikitext(translate("getSquadTableColumn",3,w_race))
	end
	local temp
	local iii = 1
	for i, v in pairs (riderTable) do
		local tRow=outTable:tag('tr'):css('line-height','1.8em')
		local tCell= tRow:tag('td'):cssText("padding:0 1em 0 0;white-space:nowrap")

		if not l10n["country_name_list"] or wiki == 'lv' or wiki == 'ar' or wiki == 'ru' or wiki == 'da' then temp=v['flags']..' ' else temp='' end
		tCell:wikitext(temp..v['riderName']):attr('data-sort-value',v['sortkey'])

		if v['riderStart']~=nil or v['riderEnd']~=nil then
			tCell:tag('span'):cssText("font-size:80%; color:#686868")
			local note=''
			if v['riderReason'] ~= nil then
				note = ', [[#tr_'..i..s.seasonID..'|'..translate("getSquadTableColumn",4,w_race)..']]'
				if wiki == "ar" then note = '، [[#tr_'..i..s.seasonID..'|'..translate("getSquadTableColumn",4,w_race)..']]' end
			end
			tCell:wikitext(' ('..(v['riderStart'] or '')..'–'..(v['riderEnd'] or '')
				.. (v['riderPosition'] or '')..note..')')
		elseif v['riderReason'] then
			tCell:tag('span'):cssText("font-size:80%; color:#686868")
			:wikitext('([[#tr_'..i..s.seasonID..'|'..translate("getSquadTableColumn",4,w_race)..']]'.. ')')
		end
		tCell=tRow:tag('td'):cssText("text-align:right;white-space:nowrap")
		if wiki == 'lv' then
			local _, _, beginYear, beginMonth, beginDay = string.find(startOfSeason,"(%d+)-(%d+)-0*(%d+)")
			local _, _, endYear, endMonth, endDay = string.find(v['riderBirthday'] or '',"(%d+)-(%d+)-0*(%d+)")
			tCell:wikitext(s.lf:expandTemplate{ title = 'Template:Birth date and age2', args = { beginYear, beginMonth, beginDay, endYear, endMonth, endDay } })
		else
			tCell:wikitext(funcDate(v['riderBirthday'] or '', 'long'))
			if l10n["country_name_list"] and wiki ~= 'ar' and wiki ~= 'ru' and wiki ~= 'da' then
				tRow:tag('td'):wikitext(v['flags'].. ' '..v['pays'])
			end
		end

		if wiki =='he' then
			local isRtl = (mw.ustring.find(v['riderTeam'], '|.*[א-ת]') or (not mw.ustring.find(v['riderTeam'], '|') and mw.ustring.find(riderTeam, '[א-ת]')))
			if isRtl then
				tCell=tRow:tag('td'):cssText("padding:0 0.5em; text-align:right")
			else
				labelMissing = true -- FIXME: labelMissing is not functional in most languages. once we have infra support for it, move it there
				tCell=tRow:tag('td'):cssText("padding:0 0.5em; text-align:left")
			end
		elseif wiki == "ar" then
            tCell=tRow:tag('td'):cssText("padding:0 0.5em")
        else 
		    tCell=tRow:tag('td'):cssText("padding:0 0.5em; text-align:left")
		end
		if v['riderTeam'] then 
			if wiki == "ar" then
				tCell:wikitext( v['riderTeam'] )
				tCell=tRow:tag('td'):cssText("padding:0 0.5em")
				tCell:wikitext( v['timeTeam']..v['errortext'] )
			else
				tCell:wikitext(v['riderTeam'].. v['timeTeam']..v['errortext'])
			end
		end
		--tableEndText is not a table
		if v['riderReason'] ~= nil or v['errortext'] ~= '' then
			local temp=(v['riderReason'] or '')..(v['errortext'] or '')
			if iii == 1 then
				tableEndText = tableEndText.. translate("getSquadTableColumn",5,w_race)..': '.. v['riderName'].. temp
			else
				tableEndText = tableEndText.. '<span style="color:white">'.. translate("getSquadTableColumn",5,w_race)..': </span>'.. riderName.. temp
			end
			iii = iii
			if riderRef ~= nil then tableEndText = tableEndText..
				s.lf:extensionTag{name='ref', content=v['riderRef'], args = {name='tr_'..iii..s.seasonID}} end
			tableEndText = tableEndText.. '<br>'
		end
	end
	if labelMissing then outTable:wikitext(getMissingLabelTrackingCategory()) end
	
	local ref=race_reference(s.seasonID,s.lf)
	if ref=='' then --fallback
		local UCIlink
		if wiki=="fr" then
			UCIlink="https://www.uci.org/fr/route/%C3%A9quipe"
		else
			UCIlink="https://www.uci.org/road/teams"
		end
		ref=translate("race_reference", 1,w_race).."["..UCIlink..' UCI]'
	end
	
	outTable:tag('tr'):tag('td'):addClass("navigation-only")
	:attr('data-sort-value','zz')
	:attr('colspan',th_colspan)
	:cssText("border-top: 2px "..backgroundColor.." solid; font-size: 80%;")
	:tag('tr')
	:tag('td'):attr('colspan',th_colspan)
	:attr('data-sort-value','zzz')
	:cssText("text-align:right")
	:tag('small'):wikitext(ref)
	
	return tostring(outTable)..tableEndText
end

--== J) List of winners ==
function p.listofwinners(frame)
	local raceID, lf =get_and_checkID(frame)
	local winnersProperty = {'Q20882667','Q20882668','Q20882669'}

	local s = {
		countryflag=true,
		raceID=raceID,
		beginyear=get_arg(2,frame,true),			
		endyear=get_arg(3,frame,true),
		shapka=get_arg(4,frame,true),
		display_team=istrue(get_arg(5,frame)), -- false= display of a rider without a team	
		winnersProperty=winnersProperty,
		custom=false,
		lf=lf
	}

	return listofwinners_main(s)
end

function p.listofwinnersyoung(frame)
	local raceID, lf =get_and_checkID(frame)
	local winnersProperty = {'Q20883139','Q72099969','Q72099972'}
	local s = {
		countryflag=true,
		raceID=raceID,
		beginyear=get_arg(2,frame,true),			
		endyear=get_arg(3,frame,true),
		shapka=get_arg(4,frame,true),
		display_team=istrue(get_arg(5,frame)), -- false= display of a rider without a team	
		winnersProperty=winnersProperty,
		custom=false,
		lf=lf
		}
	return listofwinners_main(s)
end

function p.listofwinnersChamp(frame)
	local raceID, lf =get_and_checkID(frame)
	local winnersProperty = {'Q20882667','Q20882668','Q20882669'}
	local s = {
		countryflag=false,
		raceID=raceID,
		beginyear=get_arg(2,frame,true),			
		endyear=get_arg(3,frame,true),
		shapka=get_arg(4,frame,true),
		winnersProperty=winnersProperty,
		display_team = false,
		custom=false,
		lf=lf
		}
	return listofwinners_main(s)
end

--listofwinnerssecondpart and so on can be coded with p.listofwinners
function p.listofwinnersnowiki(frame)
	local raceID, lf =get_and_checkID(frame)
	local winnersProperty = {'Q20882667','Q20882668','Q20882669'}
	local s = {
		countryflag=true,
		raceID=raceID,
		beginyear=get_arg(2,frame,true),			
		endyear=get_arg(3,frame,true),
		shapka=get_arg(4,frame,true),
		display_team=istrue(get_arg(5,frame)), -- false= display of a rider without a team
		winnersProperty=winnersProperty,
		custom=false,
		lf=lf
	}
	return frame:extensionTag{ name = 'nowiki', content = listofwinners_main(s)}
end

function p.listofwinnersteamofpoint(frame)
	local raceID, lf =get_and_checkID(frame)
	local winnersProperty = {'Q27104269','Q72065970','Q72065977'}
	local s = {
		countryflag=true,
		raceID=raceID,
		beginyear=get_arg(2,frame,true),			
		endyear=get_arg(3,frame,true),
		shapka=get_arg(4,frame,true),
		display_team=istrue(get_arg(5,frame)), -- false= display of a rider without a team
		winnersProperty=winnersProperty,
		custom=false,
		lf=lf
		}
	return listofwinners_main(s)
end

function p.listofwinnersGSI(frame)
	local raceID, lf =get_and_checkID(frame)
	local winnersProperty = {'Q98959152','Q98959192','Q98959196'}
	local s = {
		countryflag=true,
		raceID=raceID,
		beginyear=get_arg(2,frame,true),			
		endyear=get_arg(3,frame,true),
		shapka=get_arg(4,frame,true),
		display_team=istrue(get_arg(5,frame)), -- false= display of a rider without a team	
		winnersProperty=winnersProperty,
		custom=false,
		lf=lf
		}
	return listofwinners_main(s)
end

function p.listofwinnersGSII(frame)
	local raceID, lf =get_and_checkID(frame)
	local winnersProperty = {'Q98959153','Q98959194','Q98959197'}
	local s = {
		countryflag=true,
		raceID=raceID,
		beginyear=get_arg(2,frame,true),			
		endyear=get_arg(3,frame,true),
		shapka=get_arg(4,frame,true),
		display_team=istrue(get_arg(5,frame)), -- false= display of a rider without a team
		winnersProperty=winnersProperty,
		custom=false,
		lf=lf
		}
	return listofwinners_main(s)
end

function p.listofwinnersGSIII(frame)
	local raceID, lf =get_and_checkID(frame)
	local winnersProperty = {'Q98959155','Q98959195','Q98959198'}
	local s = {
		countryflag=true,
		raceID=raceID,
		beginyear=get_arg(2,frame,true),			
		endyear=get_arg(3,frame,true),
		shapka=get_arg(4,frame,true),
		display_team=istrue(get_arg(5,frame)), -- false= display of a rider without a team
		winnersProperty=winnersProperty,
		custom=false,
		lf=lf
		}
	return listofwinners_main(s)
end

function p.listofwinnerscountry(frame)
	local raceID, lf =get_and_checkID(frame)
	local winnersProperty = {'Q72068715','Q72068718','Q72068721'}
	local s = {
		countryflag=true,
		raceID=raceID,
		beginyear=get_arg(2,frame,true),			
		endyear=get_arg(3,frame,true),
		shapka=get_arg(4,frame,true),
		display_team=istrue(get_arg(5,frame)), -- false= display of a rider without a team		
		winnersProperty=winnersProperty,
		custom=false,
		lf=lf
		}
	return listofwinners_main(s)
end

function p.listofwinnerscountryU23(frame)
	local raceID, lf =get_and_checkID(frame)
	local winnersProperty = {'Q72068724','Q72068725','Q72068729'}
	local s = {
		countryflag=true,
		raceID=raceID,
		beginyear=get_arg(2,frame,true),			
		endyear=get_arg(3,frame,true),
		shapka=get_arg(4,frame,true),
		display_team=istrue(get_arg(5,frame)), -- false= display of a rider without a team
		winnersProperty=winnersProperty,
		custom=false,
		lf=lf
		}
	return listofwinners_main(s)
end

function p.listofwinnerscustom(frame)
	local raceID, lf =get_and_checkID(frame)
	local winnersProperty ={}
	
	if istrue(get_arg('general',frame)) then table.insert( winnersProperty,'Q20882667') end
	if istrue(get_arg('podium',frame)) then 
		table.insert( winnersProperty,'Q20882668') 
		table.insert( winnersProperty,'Q20882669') 
	end
	if istrue(get_arg('points',frame)) then table.insert( winnersProperty, 'Q20883007' ) end
	if istrue(get_arg('mountain',frame)) then table.insert( winnersProperty, 'Q20883212' ) end
	if istrue(get_arg('sprints',frame)) then table.insert( winnersProperty, 'Q20883328' ) end
	if istrue(get_arg('youth',frame)) then table.insert( winnersProperty, 'Q20883139' ) end
	if istrue(get_arg('combativity',frame)) then table.insert( winnersProperty, 'Q101246973' ) table.insert( winnersProperty, 'Q20893983' ) end
	if istrue(get_arg('volante',frame)) then table.insert( winnersProperty, 'Q27067359' ) end
	if istrue(get_arg('regularity',frame)) then table.insert( winnersProperty, 'Q27067170' ) end
	if istrue(get_arg('combination',frame)) then table.insert( winnersProperty, 'Q20893979' ) end
	if istrue(get_arg('breakaway',frame)) then table.insert( winnersProperty, 'Q27907715' ) end
	if istrue(get_arg('azzurri',frame)) then table.insert( winnersProperty, 'Q27907747' ) end
	if istrue(get_arg('rookie',frame)) then table.insert( winnersProperty, 'Q28092831' )	end 
	if istrue(get_arg('teams',frame)) then table.insert( winnersProperty, 'Q20882921' )	end
	if istrue(get_arg('teamspoints',frame)) then table.insert( winnersProperty, 'Q27104269' ) end	
	if istrue(get_arg('amateur',frame)) then table.insert( winnersProperty, 'Q61976850' ) end	
	if istrue(get_arg('nationality',frame)) then table.insert( winnersProperty, 'Q61976872' ) end	
	if istrue(get_arg('country',frame)) then table.insert( winnersProperty, 'Q72068715' ) end	
	if istrue(get_arg('countryU23',frame)) then table.insert( winnersProperty, 'Q72068724' ) end
	
	local s = {
		countryflag=true,
		raceID=raceID,
		beginyear=get_arg(2,frame,true),			
		endyear=get_arg(3,frame,true),
		shapka=get_arg(4,frame,true),
		display_team = false,
		winnersProperty=winnersProperty,
		custom=true,
		lf=lf
		}
	return listofwinners_main(s)
end

function listofwinners_main(s)
	local lf=s.lf
	local raceID=s.raceID
	local rows = {}
	local WDlink_on = (wiki == "mk") or (wiki == "ja") or (wiki == "ru")
	local WPcontent = {
		row ={},
		code = {}
	}
	local beginyear=s.beginyear or 0
	local endyear=s.endyear or 0
	local shapka=s.shapka or 0
	local titletable
	
	local w_race=isWomenrace(raceID)
	
	if s.custom then
		titletable={
		[ 'Q20882667' ]=translate("listofwinners",2, w_race), -- winner
		[ 'Q20882668' ]=translate("listofwinners",3, w_race), -- second		
		[ 'Q20882669' ]=translate("listofwinners",4, w_race), -- third		
		[ 'Q20883007' ]=translate("listofwinners",5, w_race), -- points  
		[ 'Q20883212' ]=translate("listofwinners",6, w_race), -- mountains
		[ 'Q20883328' ]=translate("listofwinners",7, w_race), -- sprints
		[ 'Q20883139' ]=translate("listofwinners",8, w_race), -- youth
		[ 'Q101246973' ]=translate("listofwinners",9, w_race), -- supercombativity		
		[ 'Q20893983' ]=translate("listofwinners",9, w_race), -- combativity
		[ 'Q20893979' ]=translate("listofwinners",10, w_race), -- combination
		[ 'Q20882921' ]=translate("listofwinners",11, w_race), -- teams
		[ 'Q27067359' ]=translate("listofwinners",12, w_race), -- volantes
		[ 'Q27067170' ]=translate("listofwinners",13, w_race), -- regularity
		[ 'Q27104269' ]=translate("listofwinners",14, w_race), -- teamspoints
		[ 'Q27907715' ]=translate("listofwinners",15, w_race), -- breakaway
		[ 'Q27907747' ]=translate("listofwinners",16, w_race), -- azzurri
		[ 'Q28092831' ]=translate("listofwinners",17, w_race), -- rookie
		[ 'Q61976850' ]=translate("listofwinners",18, w_race), -- amateur
		[ 'Q61976872' ]=translate("listofwinners",19, w_race), -- nationality
		[ 'Q72068715' ]=translate("listofwinners",23, w_race), -- winner country
		[ 'Q72068724' ]=translate("listofwinners",24, w_race), -- winner countryU23
	}
	else --main
	     titletable={
-- winner:
		[ 'Q20882667' ]=translate("listofwinners",2, w_race), -- winner
		[ 'Q20883007' ]=translate("listofwinners",2, w_race), -- points  
		[ 'Q20883212' ]=translate("listofwinners",2, w_race), -- mountains
		[ 'Q20883328' ]=translate("listofwinners",2, w_race), -- sprints
		[ 'Q20883139' ]=translate("listofwinners",2, w_race), -- youth (time or point)
		[ 'Q101246973' ]=translate("listofwinners",2, w_race), -- supercombativity		
		[ 'Q20893983' ]=translate("listofwinners",2, w_race), -- combativity
		[ 'Q20893979' ]=translate("listofwinners",2, w_race), -- combination
		[ 'Q20882921' ]=translate("listofwinners",2, w_race), -- team (time)
		[ 'Q27067359' ]=translate("listofwinners",2, w_race), -- volantes
		[ 'Q27067170' ]=translate("listofwinners",2, w_race), -- regularity
		[ 'Q27104269' ]=translate("listofwinners",2, w_race), -- teampoints
		[ 'Q27907715' ]=translate("listofwinners",2, w_race), -- breakaway
		[ 'Q27907747' ]=translate("listofwinners",2, w_race), -- azzurri
		[ 'Q28092831' ]=translate("listofwinners",2, w_race), -- rookie
		[ 'Q61976850' ]=translate("listofwinners",2, w_race), -- amateur
		[ 'Q61976872' ]=translate("listofwinners",2, w_race), -- nationality
		[ 'Q72068715' ]=translate("listofwinners",2, w_race), -- winner country
		[ 'Q72068724' ]=translate("listofwinners",2, w_race), -- winner countryU23
		[ 'Q98959152' ]=translate("listofwinners",2, w_race), -- winner team GS-I
		[ 'Q98959153' ]=translate("listofwinners",2, w_race), -- winner team GS-II
		[ 'Q98959155' ]=translate("listofwinners",2, w_race), -- winner team GS-III		
-- 2 place:
		[ 'Q20882668' ]=translate("listofwinners",3, w_race), -- second		
		[ 'Q72065970' ]=translate("listofwinners",3, w_race), -- second teampoints
		[ 'Q72099969' ]=translate("listofwinners",3, w_race), -- youth (time or point)		
		[ 'Q72068718' ]=translate("listofwinners",3, w_race), -- second country
		[ 'Q72068725' ]=translate("listofwinners",3, w_race), -- second countryU23
		[ 'Q98959192' ]=translate("listofwinners",3, w_race), -- second team GS-I
		[ 'Q98959194' ]=translate("listofwinners",3, w_race), -- second team GS-II
		[ 'Q98959195' ]=translate("listofwinners",3, w_race), -- second team GS-III		
-- 3 place:
		[ 'Q20882669' ]=translate("listofwinners",4, w_race), -- third	
		[ 'Q72065977' ]=translate("listofwinners",4, w_race), -- third teampoints	
		[ 'Q72099972' ]=translate("listofwinners",4, w_race), -- youth (time or point)		
		[ 'Q72068721' ]=translate("listofwinners",4, w_race), -- third country
		[ 'Q72068729' ]=translate("listofwinners",4, w_race), -- third countryU23
		[ 'Q98959196' ]=translate("listofwinners",4, w_race), -- third team GS-I
		[ 'Q98959197' ]=translate("listofwinners",4, w_race), -- third team GS-II
		[ 'Q98959198' ]=translate("listofwinners",4, w_race), -- third team GS-III		
	}
	end

--[=[
It is possible to give the table listofwinners in the article commands. It could look like this:
{{Cycling race/listofwinners|Q18574623
| above row 1: '''[[aaa bbb ccc]]''' xxx
}}
"above row x" inserts a new row above row x into the table. Content is what is behind the ":".
]=]
	if get_arg(2,lf) then
		for num, _ in pairs(lf.args) do
			if num > 1 and mw.ustring.find(mw.ustring.lower(get_arg(num,lf)), 'row') then
				local _, _, kebeginYear, val = mw.ustring.find(get_arg(num,lf), "([^:]+)%s*:%s*(%C+)")
				local _, _, key01, kebeginYear1, kebeginYear2 = mw.ustring.find(kebeginYear, "(%a+)%s*(%a+)%s*(%d+)")
				kebeginYear2 = tonumber(kebeginYear2) kebeginYear1 = mw.ustring.lower(key01..kebeginYear1)
				if kebeginYear1 == 'aboverow' then WPcontent.row[kebeginYear2] = val WPcontent.code[kebeginYear2] = 0  end --0 is above
				if kebeginYear1 == 'belowrow' then WPcontent.row[kebeginYear2] = val WPcontent.code[kebeginYear2] = 1  end --0 is above	
			end
		end
	end
	
	local firstyeartodisplay=2100
	local parts = mw.wikibase.getAllStatements(raceID, 'P527') -- P527 is 'has part'
	for _, part in ipairs(parts) do
		if part.rank ~= 'deprecated' and part.mainsnak.snaktype == 'value' then
			local partID = part.mainsnak.datavalue.value.id
			local timeOfRace=getTimeOfRace(partID,true,true) --original P585 and P580 inverted here
			local year = timeOfRace and string.sub(timeOfRace, 2, 5) or '?'
			local month = timeOfRace and string.sub(timeOfRace, 7, 8) or '01'	
			if year == "?" then mw.log("no year at " .. partID ) end
			if endyear==0 or (tonumber(year) or 0)<=endyear then
					if (tonumber(year) or 0) >= beginyear then
						local thereisawinner=false
						
						local sitelink = mw.wikibase.getSitelink(partID)
						if sitelink then
							sitelink = '[[' .. sitelink .. '|' .. year .. ']]'
						else
							sitelink = year
						end
						if WDlink_on then
							sitelink = sitelink .. ' ' .. wdLink(partID)
						end
						local winners = {}
						for _, property in ipairs(s.winnersProperty) do winners[property]='' end
						local tCell
						local tCellstr=''
						
		 				local temp=firstValue(partID, 'P1346','id')
						if temp and temp=='Q30108381' or temp=='Q54806642' or temp=='Q23023872' then --race cancelled
							local cancelledlabel = getLabelFallback(temp)
							tCell=mw.html.create('td'):attr('colspan','4')
							:cssText('text-align:center; font-style: italic')
							:wikitext(cancelledlabel)
							tCellstr=tostring(tCell)
						else
							winner(lf,partID, winners, timeOfRace, not s.countryflag, WDlink_on,s.display_team,true)
							for _, property in ipairs(s.winnersProperty) do
								tCell=mw.html.create('td'):wikitext(winners[property])
								if winners[property]~='' then 
									thereisawinner=true 
									if tonumber(year)<firstyeartodisplay then firstyeartodisplay=tonumber(year) end
								end
								tCellstr= tCellstr..tostring(tCell)
							end
						end
						if firstyeartodisplay<=tonumber(year) then
						    rows[#rows+1]={year..month, sitelink, tCellstr}
						end
					end
				end
			end
		end
	table.sort(rows, function(a, b) return a[1] < b[1] end) -- Sort by year
	
	local clear = "left"
	if wiki == "ar" then clear = "right" end
	
	--do not use hw.html here otherwise the begin and end year won't work
	local table_first = "<table cellpadding='4' cellspacing='0' style='"..standardtablecss.."'>"

	local tTitleRow=mw.html.create('tr')
	:css('text-align','center')
	:css('background-color',backgroundColor)
	:css('color', 'inherit')
	local tCell=tTitleRow:tag('th')
	local wd_link = mw.html.create('span'):css('float','left'):wikitext(wdLink(raceID .. "#P527"))
	if arwiki_totemplate then wd_link = wdLink(tostring(raceID) .. "#P527") end
	if WDlink_on == false then
		tCell:wikitext(tostring(wd_link))
	end
	tCell:wikitext(translate("listofwinners",1,w_race)) --year
	for _, pp in ipairs(s.winnersProperty) do
		tTitleRow:tag('th'):wikitext(titletable[pp])
	end
	
	local table_center=''
	local nb_year_inrow=1
	local lastyear
	
	for i, row in ipairs(rows) do
		sitelink=row[2]

		local tRowWD=mw.html.create('tr')
		local tCell=tRowWD:tag('td'):css('text-align','left')
		
		if lastyear and mw.ustring.sub(row[1],1,4)==lastyear then
				nb_year_inrow=nb_year_inrow+1
				tCell:wikitext(sitelink..' ('..tostring(nb_year_inrow)..')') 
		else
			tCell:wikitext(sitelink)
			nb_year_inrow=1
		end
		lastyear=mw.ustring.sub(row[1],1,4)
		tRowWD:node(row[3]) --add the end of the row
		
		if WPcontent.row[i] then
			tRow=mw.html.create('tr'):tag('td'):attr('colspan','4')
			:css('text-align','center')
			tRow:wikitext(WPcontent.row[i])

			if WPcontent.code[i]==0 then --above
				table_center=table_center..tostring(tRow)
				table_center=table_center..tostring(tRowWD)
			else --below
				table_center=table_center..tostring(tRowWD)
				table_center=table_center..tostring(tRow)
			end
		else
			table_center=table_center..tostring(tRowWD)
		end
	end
	--firstpart with header no foot
	if shapka == 1 then -- standard header
		return table_center .. "</table>"	
	elseif shapka == 2 then	-- you need to add a title and you can add text at the beginning
		return table_center 
	else -- you need to add a title and you can add anything and anywhere
		return table_first .. tostring(tTitleRow) .. table_center .. "</table>"
	end
end

--== K) List of stages
function check_basque_place(sPoint, sPointID)
	local eu=false
	--check if it is a town
	local town=false
	for _, p31 in statements(sPointID, 'P31') do
		if p31.mainsnak.datavalue.value.id == "Q2074737" or p31.mainsnak.datavalue.value.id == "Q484170" then --Spanish and French towns
			town=true
		end
	end
	
	if not town then --if it not a town look for parent
		for _, p131 in statements(sPointID, 'P131') do
			if data.BasqueTown[p131.mainsnak.datavalue.value.id] then
				eu=true
			end
		end
	else
		if data.BasqueTown[sPointID] then
			eu=true
		end
	end
	if eu then
		sPoint = flag("Q47588", timeOfRace).." "..sPoint
	end
	return sPoint, eu
end

function p.listofstages(frame)
	local WDlink_on = wiki == "mk" or wiki == "ja"
	local WPcontent = {}
	local raceID, lf = get_and_checkID(frame)
	local thereiselevation=false
	local result, tableBody
	local w_race=isWomenrace(raceID)
--[=[ It is possible to give the table listofstages in the article commands which overwrites data from Wikidata.
It could look like this:
{{Cycling race/listofstages|Q18574623
| RoW 1: locaTION Ab : [[1a1b]]
| after row 1 : date : 99 août
| after row 1 : icon : [[File:Stage rest day.svg|vbght frthzt fdgtr]]
| after row 1: text : rest day at [[aaa bbb ccc]]
| row 4:  location A : [[4a4a]]abc
| row 3 : winner a : <sup>tzhgt</sup>
| row 4 : winner b : kjuzhgt<br />bbjje
| row 4 : icon : [[File:Mediummountainstage.svg|xcvbbgf fgtr]]
| row 4 : distance : <s>141.8</s> 122<ref>test</ref>
}}
The first paramer is "row x" or "after row x". "after row" adds a new row after row x into the table to print e.g. a rest day.
The second parameters are "location [a/b/ab]", "date", "icon", "text", "winner [a/b]" and "distance".
"a" and "b" means the first and the second location or winner. "ab" could be used if start location and
end location are the same. The file data for the icon looks this way: [[File:Stage rest day.svg|any text]]
]=]
	if get_arg(2,lf) then
		local WProw, WPnew_row, WPcourse, WPtext, WPdate, WPwinner, WPicon, WPdistance
			= 'row', 'afterrow', 'location', 'text', 'date', 'winner', 'icon', 'distance'
		local _, kebeginYear, key2, val
		local key01, kebeginYear1, kebeginYear2
		local key21, key22
		for num, var in pairs(lf.args) do
			if num > 1 and mw.ustring.find(mw.ustring.lower(var), WProw) then
				_, _, kebeginYear, key2, val = mw.ustring.find(var, "([^:]+)%s*:?%s*([^:]*)%s*:%s*(%C+)")
				_, _, key01, kebeginYear1, kebeginYear2 = mw.ustring.find(kebeginYear, "(%a+)%s*(%a+)%s*(%d+)")
				kebeginYear2 = tonumber(kebeginYear2)
				kebeginYear1 = mw.ustring.lower(key01 .. kebeginYear1)
				key2 = mw.ustring.lower(mw.text.trim(key2))
				_, _, key21, key22 = mw.ustring.find(key2, "(%a+)%s*(%a*)")

				if not WPcontent[kebeginYear2] then WPcontent[kebeginYear2] = {} end
				if kebeginYear1 == WProw and key21 == WPcourse then WPcontent[kebeginYear2][key22] = val end
				if kebeginYear1 == WPnew_row and key2 == WPdate then
					WPcontent[kebeginYear2]['date'] = val
					WPcontent[kebeginYear2]['text'] = WPcontent[kebeginYear2]['text'] or ''
					WPcontent[kebeginYear2]['icon (new row)'] = WPcontent[kebeginYear2]['icon (new row)'] or ''
				end
				if kebeginYear1 == WPnew_row and key2 == WPtext then
					WPcontent[kebeginYear2]['text'] = val
					WPcontent[kebeginYear2]['date'] = WPcontent[kebeginYear2]['date'] or ''
					WPcontent[kebeginYear2]['icon (new row)'] = WPcontent[kebeginYear2]['icon (new row)'] or ''
				end
				if kebeginYear1 == WPnew_row and key2 == WPicon then
					val = string.gsub(val, "|", "|border|right|20px|", 1)
					WPcontent[kebeginYear2]['icon (new row)'] = val
					WPcontent[kebeginYear2]['date'] = WPcontent[kebeginYear2]['date'] or ''
					WPcontent[kebeginYear2]['text'] = WPcontent[kebeginYear2]['text'] or ''
				end
				if kebeginYear1 == WProw and key21 == WPwinner and key22 == 'a' then WPcontent[kebeginYear2]['stage winner'] = val end
				if kebeginYear1 == WProw and key21 == WPwinner and key22 == 'b' then WPcontent[kebeginYear2]['general winner'] = val end
				if kebeginYear1 == WProw and key21 == WPicon then
					val = string.gsub(val, "|", "|border|right|20px|", 1)
					WPcontent[kebeginYear2]['icon'] = val end
				if kebeginYear1 == WProw and key21 == WPdistance then WPcontent[kebeginYear2]['distance'] = val end
			end
		end
	end
	local countries = wikibase.getAllStatements(raceID, 'P17')
	local onecountry, firstcountryID
	if countries and #countries>1 then
		onecountry=false
		if countries[1] then
			firstcountryID=countries[1].mainsnak.datavalue.value.id
		end
	else
		onecountry=true
	end

	local rows = {}
	local stages = mw.wikibase.getBestStatements(raceID, 'P527') -- P527 is 'has part'
	for _, v in pairs(stages) do
		if v.mainsnak.snaktype == 'value' then
			local stageID = v.mainsnak.datavalue.value.id
			local p = mw.wikibase.getBestStatements(stageID, 'P1545') -- P1545 is 'series ordinal'
			local sOrdinal = p[1] and p[1].mainsnak.snaktype == 'value' and p[1].mainsnak.datavalue.value
				or ''
			local _, _, sNumber, sLetter = string.find(sOrdinal, '(%d+)(.*)')
			if not sNumber then sNumber = '' end
			if not sLetter then sLetter = '' end
			local WDLink = WDlink_on and wdLink(stageID) or ''
			local sitelink = mw.wikibase.getSitelink(stageID)
			local timeOfRace =getTimeOfRace(stageID)
			
			local sPointID = firstValue(stageID, 'P1427', 'id')
			local sPoint = (sPointID and getPlaceLink(sPointID, timeOfRace)) or ''
			local eu=false
			if wiki=="eu" and sPointID then
				sPoint, eu=check_basque_place(sPoint, sPointID)
			end

			if sPointID and not onecountry and not eu then
				local startcountryID=getCountryID(sPointID, timeOfRace)
				if startcountryID and firstcountryID ~= startcountryID then
					sPoint = flag(startcountryID, timeOfRace).." "..sPoint
				end
			end

			local dPointID = firstValue(stageID, 'P1444', 'id')
			local dPoint = (dPointID and getPlaceLink(dPointID, timeOfRace)) or ''

			eu=false
			if wiki=="eu" and dPointID then
				dPoint, eu=check_basque_place(dPoint, dPointID)
			end

			if dPointID and not onecountry and not eu then
				local dcountryID=getCountryID(dPointID, timeOfRace)
				if dcountryID and firstcountryID ~= dcountryID then
					dPoint = flag(dcountryID, timeOfRace).." "..dPoint
				end
			end

			local sDistance = getDistance(stageID, false) or ''
			local sElevation = getElevation(stageID) 
			if sElevation then thereiselevation=true end
			
			local winners = {
				Q20882747 = '', -- Q20882747 is 'stage winner'
				Q20882763 = '', -- Q20882763 is 'overall leader at the end of the stage'
				Q20882667 = '', -- Q20882667 is 'overall winner' not supposed to be used
			}
			winner(lf,stageID, winners, timeOfRace, false, WDlink_on)

			-- find the type of stage
			local sType = typeofstagelogo(stageID)
			local label, section_title
			if sOrdinal == "0" then
				label, section_title = translate("func_prologue",1), "#" .. translate("func_prologue",1)
			else
				label, section_title = stageLink(sOrdinal, sNumber, sLetter)
			end
			-- if there is a Wikipedia article of that stage show it or show the section
			local sLink = sitelink and ("[[" .. sitelink .. "|" .. label .. "]]") or
				("[[" .. section_title .. "|" .. label .. "]]")

			local sDate = funcDate(timeOfRace, 'small')
			local tempoverall
			if  winners['Q20882763']~='' then tempoverall=winners['Q20882763'] else	tempoverall=winners['Q20882667'] end
			rows[#rows + 1] = {
				rank=tonumber(sNumber) or 0, 
				sortkey=sLetter,  -- Sort keys
				sLink=sLink,
				sDate=sDate, 
				WDLink=WDLink, 
				sPoint=sPoint, 
				dPoint=dPoint, 
				sType=sType, 
				sDistance=sDistance, 
				sElevation=sElevation, 
				sSWin=winners['Q20882747'], 
				sGWin=tempoverall -- Content
			}
		end
	end

	table.sort(rows, function(a, b)
		if a["rank"] ~= b["rank"] then return a["rank"] < b["rank"] end
		return a["sortkey"] < b["sortkey"]
	end)
	local Id = ((not WDlink_on and wdLink(string.gsub(raceID, '%s', '') .. "#P527")) or "")
	
	tab=mw.html.create('table')
	:attr('cellpadding','4' )
	:attr('cellspacing','0')
	:cssText(standardtablecss)

	local tRow=tab:tag('tr'):css('background-color',backgroundColor)
	:css('text-align','center'):css('color', 'inherit')
	tRow:tag('th'):css('white-space','nowrap')
	:wikitext(Id..translate("headoftable",1,w_race))
	tRow:tag('th'):wikitext(translate("headoftable",2,w_race))
	tRow:tag('th'):wikitext(translate("headoftable",3,w_race))
	tRow:tag('th'):css('color',backgroundColor):wikitext("type")
	tRow:tag('th'):wikitext(translate("headoftable",4,w_race))
	if thereiselevation then 
		tRow:tag('th'):wikitext(translate("headoftable",7,w_race))
	end
	tRow:tag('th'):wikitext(translate("headoftable",5,w_race))
	tRow:tag('th'):wikitext(translate("headoftable",6,w_race))
	local header = tostring(tRow)
	for num, row in pairs(rows) do
		local sPoint=row["sPoint"]
		local dPoint=row["dPoint"]
		local sType=row["sType"]
		local sDistance=row["sDistance"]
		
		local WPc = WPcontent[num]
		if WPc then
			if WPc['a'] then sPoint = WPc['a'] end
			if WPc['b'] then dPoint = WPc['b'] end
			if WPc['ab'] then sPoint, dPoint = WPc['ab'], '' end
			if WPc['icon'] then sType = WPc['icon'] end
			if WPc['distance'] then sDistance = WPc['distance'] end
		end

		local tRow = tab:tag('tr')
		local tCell= tRow:tag('td'):cssText('text-align:center; white-space:nowrap'):wikitext(row["sLink"])
		tCell:tag('span'):css('white-space','nowrap'):wikitext("&nbsp;".. row["WDLink"])
		tRow:tag('td'):css('white-space','nowrap'):cssText("text-align:right; padding-right:0px")
		:wikitext(row["sDate"])
		tCell=tRow:tag('td'):cssText("padding-right:0px"):wikitext( sPoint)
		if dPoint ~= '' then
			tCell:wikitext(" – " .. dPoint)
		end
		tRow:tag('td'):cssText("padding-right:0px"):wikitext(sType)
		tRow:tag('td'):css('text-align','center'):wikitext( sDistance)
		if thereiselevation then
			tRow:tag('td'):css('text-align','center'):wikitext(row["sElevation"])
		end

		if WPc and WPc['stage winner'] then
			tRow:tag('td'):css('text-align',textalign):wikitext( WPc['stage winner'])
		else
			tRow:tag('td'):wikitext(row["sSWin"])
		end
		if WPc and WPc['general winner'] then
			tRow:tag('td'):css('text-align',textalign):wikitext( WPc['general winner'])
		else
			tRow:tag('td'):wikitext(row["sGWin"])
		end
		if WPc and (WPc['date'] or WPc['text'] or WPc['icon (new row)']) then
			tRow = tab:tag('tr')
			tRow:tag('td') --empty

			if WPc['icon (new row)'] == '' then
				tRow:tag('td'):cssText('text-align:right; padding:3px 0px 10px 0px;white-space:nowrap')
				:wikitext(WPc['date'])
				tRow:tag('td'):cssText("text-align:" .. textalign .. "; padding:3px 4px 10px")
				:wikitext(WPc['text'])
			else
				tRow:tag('td'):cssText('text-align:right; padding-right:0px')
				:wikitext(WPc['date'])
				tRow:tag('td'):cssText("text-align:" .. textalign)
				:wikitext(WPc['text'])
			end
			tRow:tag('td'):css('padding-top','10px'):wikitext(WPc['icon (new row)'])
			tRow:tag('td'):attr('colspan','3')
		end
	end
	if arwiki_totemplate then
		tab = change_listofstages(tab, raceID, header, Id)
	end
	return tab
end

function p.stagetitle(frame)
	local stageID = get_and_checkID(frame)
	-- from to 
	local sPointID = firstValue(stageID, 'P1427', 'id')
	local sPoint = sPointID and getPlaceLink(sPointID) or ''

	local dPointID = firstValue(stageID, 'P1444', 'id')
	local dPoint = (dPointID and getPlaceLink(dPointID)) or ''

	local sDistance = getDistance(stageID, true) or ''
	local sType = typeofstagelogo(stageID) -- find the type of stage
	
	tab=mw.html.create('table')
	tab:tag('th'):wikitext(sPoint.." - "..dPoint)
	tab:tag('td'):wikitext(sType)
	tab:tag('td'):css('font-weight','bold'):wikitext("("..sDistance..")")
	return tab
end

local function champtitle(h) --!h is h.jersey
	local road, ITT, result
	local hcountry, hnotcountry = {},{}
	local w_race=nil --to be defined if needed
	
	--the jersey for a stage race and the jersey from national championship should be differentiated
	--to avoid to look every time, below is a list of all national championships

	if type(h) == 'table' and h[1] then
		for _, v in ipairs(h) do
			roadtemp=false
			ITTtemp=false
			if data.womenNcRoadtable[v] or data.menNcRoadtable[v] then
				 road = true
				 roadtemp=true
			elseif data.womenNcITTtable[v] or data.menNcITTtable[v] then
				 ITT = true
				 ITTtemp=true
	    	else
		    	local raceLabel = mw.wikibase.getLabelByLang(v,"fr")
				if raceLabel then
					local testMenRoadrace, testMenITT, testWomenRoadrace, testWomenITT
					local raceLabelmod = string.gsub(raceLabel, '-', 'x')
					testMenRoadrace = string.find( raceLabel, 'Course en ligne masculine aux' ) 
					testMenITT = string.find( raceLabelmod, 'Contrexlaxmontre masculin aux' ) 
					testWomenRoadrace = string.find( raceLabel, 'Course en ligne féminine aux' ) 
					testWomenITT = string.find( raceLabelmod, 'Contrexlaxmontre féminin aux' ) 
					if testWomenRoadrace or testMenRoadrace then road = true roadtemp=true end
					if testWomenITT or testMenITT then ITT = true ITTtemp=true end
				end
			end
			if roadtemp or ITTtemp then
				table.insert(hcountry,v)
			else
				table.insert(hnotcountry,v)	
			end
		end
	end
	if road and ITT then
		local image = {}
		for ii, v in ipairs(hcountry) do
			local p18 = mw.wikibase.getBestStatements(v, 'P18')
			if p18[1] and p18[1].mainsnak.snaktype == 'value' then
				local temp = p18[1].mainsnak.datavalue.value
				local alreadythere = 0
				for _, vv in ipairs(image) do
					if vv==temp then alreadythere = 1 end
				end
				if alreadythere==0 then
					table.insert(image,temp)
				else hcountry[ii] = nil
				end
			end
		end
		--avoid double display of jersey
		result = "<small>("..translate("startlist",10,w_race).." "..translate("startlist",12,w_race).." "..translate("startlist",11,w_race)..")</small>"
	elseif road then
		result = "<small>("..translate("startlist",10,w_race)..")</small>"
	elseif ITT then
		result = "<small>("..translate("startlist",11,w_race)..")</small>"
	else
		result = ""
	end
	return jersey(hcountry)..result..jersey(hnotcountry)
end

-- L) List of stages classification
local function winnerjersey(raceID, winners)
	local jerseytable, bgcolortable={}, {}
	local p1346 = wikibase.getAllStatements(raceID, 'P1346') -- P1346 is 'winner'
	for _, winner in pairs(p1346) do
		local wOf, thisjersey, bg_color
		local q = winner.qualifiers
		if q then
			if q.P2501 and q.P2501[1].snaktype == 'value' then
				wOf = q.P2501[1].datavalue.value.id -- P642 is 'of'
			elseif q.P642 and q.P642[1].snaktype == 'value' then --fallback
				wOf = q.P642[1].datavalue.value.id -- P642 is 'of'
			end
			if q.P2912 and q.P2912[1].snaktype == 'value' then
				thisjersey=q.P2912[1].datavalue.value.id
				if data.bg_color_table[thisjersey] then
					bg_color = data.bg_color_table[thisjersey]
				end
			end
		end
		if winners[wOf] and thisjersey then
			jerseytable={}
			table.insert(jerseytable,thisjersey)
			winners[wOf] = jersey(jerseytable)
			bgcolortable[wOf] = bg_color
		end
	end
	return winners, bgcolortable
end

function p.listofstagesclassification(frame)
	-- WDlink_on is used to decide if a Wikidata logo will be shown
	local WDlink_on = wiki == "mk" or wiki == "ja"
	local displaytypeofstage = true
	local stageinfotable = {}
	local raceID, lf = get_and_checkID(frame)
	local w_race=isWomenrace(raceID)
	local sType

	--link for Grand Tour
	local GTid={['Q33881']=true,['Q33861']=true,['Q33937']=true,['Q1526999']=true}
	local thisGT

	for _, p31 in statements(raceID, 'P31') do
		if GTid[p31.mainsnak.datavalue.value.id]==true then thisGT=p31.mainsnak.datavalue.value.id break end
	end

	local Sitelink,overallname, pointsname, mountainname, youngname, teamname, combativityname, supercombativityname, combinedname
	if thisGT then
		if thisGT=='Q33881' then -- Tour de France
			Sitelink = wikibase.getSitelink('Q2267539') -- General
			if Sitelink then overallname="[["..Sitelink .."|"..translate("headoftableII",9,w_race).."]]" end
			Sitelink = wikibase.getSitelink('Q175399') -- Point
			if Sitelink then pointsname="[["..Sitelink .."|"..translate("infobox",22,w_race).."]]" end
			Sitelink = wikibase.getSitelink('Q927157') -- Mountains
			if Sitelink then mountainname="[["..Sitelink .."|"..translate("infobox",23,w_race).."]]" end
			Sitelink = wikibase.getSitelink('Q2254180') -- Young
			if Sitelink then youngname="[["..Sitelink .."|"..translate("infobox",25,w_race).."]]" end
			Sitelink = wikibase.getSitelink('Q1436680') -- Team by time
			if Sitelink then teamname="[["..Sitelink .."|"..translate("infobox",28,w_race).."]]" end
			Sitelink = wikibase.getSitelink('Q2094179') -- Combativity award
			if Sitelink then combativityname="[["..Sitelink .."|"..translate("infobox",26,w_race).."]]" end
			Sitelink = wikibase.getSitelink('Q2094179') -- Combativity award
			if Sitelink then supercombativityname="[["..Sitelink .."|"..translate("infobox",26,w_race).."]]" end
			Sitelink = wikibase.getSitelink('Q1835362') -- Combination 
			if Sitelink then combinedname="[["..Sitelink .."|"..translate("infobox",27,w_race).."]]" end

		elseif thisGT=='Q33861' then -- Giro d'Italia
			Sitelink = wikibase.getSitelink('Q1164275') -- General
			if Sitelink then overallname="[["..Sitelink .."|"..translate("headoftableII",9,w_race).."]]" end
			Sitelink = wikibase.getSitelink('Q641083') -- Point
			if Sitelink then pointsname="[["..Sitelink .."|"..translate("infobox",22,w_race).."]]" end
			Sitelink = wikibase.getSitelink('Q641060') -- Mountains
			if Sitelink then mountainname="[["..Sitelink .."|"..translate("infobox",23,w_race).."]]" end
			Sitelink = wikibase.getSitelink('Q641662') -- Young
			if Sitelink then youngname="[["..Sitelink .."|"..translate("infobox",25,w_race).."]]" end

		elseif thisGT=='Q33937' then -- Vuelta a España
			Sitelink = wikibase.getSitelink('Q2532554') -- General
			if Sitelink then overallname="[["..Sitelink .."|"..translate("headoftableII",9,w_race).."]]" end
			Sitelink = wikibase.getSitelink('Q2241695') -- Point
			if Sitelink then pointsname="[["..Sitelink .."|"..translate("infobox",22,w_race).."]]" end
			Sitelink = wikibase.getSitelink('Q1118296') -- Mountains
			if Sitelink then mountainname="[["..Sitelink .."|"..translate("infobox",23,w_race).."]]" end
			Sitelink = wikibase.getSitelink('Q60233927') -- Young
			if Sitelink then youngname="[["..Sitelink .."|"..translate("infobox",25,w_race).."]]" end					
			Sitelink = wikibase.getSitelink('Q2141595') -- Team by time
			if Sitelink then teamname="[["..Sitelink .."|"..translate("infobox",28,w_race).."]]" end
			Sitelink = wikibase.getSitelink('Q20882672') -- Combativity award
			if Sitelink then combativityname="[["..Sitelink .."|"..translate("infobox",26,w_race).."]]" end
			Sitelink = wikibase.getSitelink('Q2330008') -- Combination 
			if Sitelink then combinedname="[["..Sitelink .."|"..translate("infobox",27,w_race).."]]" end

		else -- Giro d'Italia Women
			Sitelink = wikibase.getSitelink('Q3679692') -- General
			if Sitelink then overallname="[["..Sitelink .."|"..translate("headoftableII",9,w_race).."]]" end
			Sitelink = wikibase.getSitelink('Q3679673') -- Point
			if Sitelink then pointsname="[["..Sitelink .."|"..translate("infobox",22,w_race).."]]" end
			Sitelink = wikibase.getSitelink('Q3679712') -- Mountains
			if Sitelink then mountainname="[["..Sitelink .."|"..translate("infobox",23,w_race).."]]" end
			Sitelink = wikibase.getSitelink('Q3679695') -- Young
			if Sitelink then youngname="[["..Sitelink .."|"..translate("infobox",25,w_race).."]]" end
		end
	end

	local winners = {
		{ name = translate("infobox",19,w_race), QID = 'Q20882747'}, -- stage
		{ name = overallname or translate("headoftableII",9,w_race), QID = 'Q20882763' }, -- overall
		{ name = pointsname or translate("infobox",22,w_race), QID = 'Q20883008' }, -- points
		{ name = mountainname or translate("infobox",23,w_race), QID = 'Q20883213' }, -- mountains
		{ name = translate("infobox",24,w_race), QID= 'Q20883329' }, -- sprints
		{ name = youngname or translate("infobox",25,w_race), QID='Q20883140' }, -- youth
		{ name = combativityname or translate("infobox",26,w_race), QID= 'Q21686770' }, -- combativity
		{ name = supercombativityname or translate("infobox",26,w_race), QID= 'Q20893984' }, -- combativity
		{ name = translate("infobox",35,w_race), QID= 'Q27104688' }, -- volantes
		{ name = translate("infobox",36,w_race), QID= 'Q27104684' }, -- regularity
		{ name = combinedname or translate("infobox",27,w_race), QID='Q20965880' }, -- combination
		{ name = translate("infobox",38,w_race), QID='Q27907714' }, -- breakaway
		{ name = translate("infobox",39,w_race), QID='Q27907748' }, -- azzurri
		{ name = translate("infobox",40,w_race), QID='Q28096780'}, -- rookie
		{ name = teamname or translate("infobox",28,w_race), QID='Q20882922' }, -- teams
		{ name = translate("infobox",37,w_race), QID ='Q27104271' }, -- teamspoints
		{ name = translate("infobox",41,w_race), QID ='Q61976847' },-- amateur
		{ name = translate("infobox",42,w_race), QID ='Q61976871' } --nationality
	}

	local winnersgen = {
		{ QID = 'Q20882667' }, -- overall
		{ QID = 'Q20883007' }, -- points
		{ QID = 'Q20883212' }, -- mountains
		{ QID = 'Q20883328' }, -- sprints
		{ QID = 'Q20883139' }, -- youth
		{ QID = 'Q101246973' }, -- supercombativity		
		{ QID = 'Q20893983' }, -- combativity
		{ QID = 'Q27067359' }, -- volantes
		{ QID = 'Q27067170' }, -- regularity
		{ QID = 'Q20893979' }, -- combination
		{ QID = 'Q27907715' }, -- breakaway
		{ QID = 'Q27907747' }, -- azzurri
		{ QID = 'Q28092831' }, -- rookie
		{ QID = 'Q20882921' },  -- teams
		{ QID = 'Q27104269' }, -- teamspoints
		{ QID = 'Q61976850' },  -- amateur
		{ QID = 'Q61976872' } --nationality
	}

	local generaltoleader = {
		['Q20882747']= nil,
		['Q20882667']= 'Q20882763', -- overall
		['Q20883007']= 'Q20883008', -- points
		['Q20883212']= 'Q20883213', -- mountains
		['Q20883328']= 'Q20883329', -- sprints
		['Q20883139']= 'Q20883140', -- youth
		['Q20893983']= 'Q20893984', -- combativity
		['Q101246973']= 'Q21686770', -- supercombativity			
		['Q27067359']= 'Q27104688', -- volantes
		['Q27067170']= 'Q27104684', -- regularity
		['Q20893979']= 'Q20965880', -- combination
		['Q27907715']= 'Q27907714', -- breakaway
		['Q27907747']= 'Q27907748', -- azzurri
		['Q28092831']= 'Q28096780', -- rookie
		['Q20882921']= 'Q20882922', -- teams
		['Q27104269']= 'Q27104271', -- teamspoints
		['Q61976850']= 'Q61976847', -- amateur
		['Q61976872']= 'Q61976871'  --nationality
	}

	--read stages
	local stages = mw.wikibase.getBestStatements(raceID, 'P527') -- P527 is 'has part'
	local columntable, jerseytable, bgcolortable={}, {}, {}
	for ii, v in ipairs(winners) do
		if v.QID then
			local t = {key=ii, name=v.name, jersey='', bg_color='', used=false}
			for jj = 1, #stages+1 do
				t[jj] = { {}, {}, {} }  -- leader, first stage, number of stages consecutive (for rowspan)
			end
			columntable[v.QID] = t
		end
	end
	--to have the columns in the same order as defined, otherwise they would be sorted according to the order in wikidata
	--make "Q123", "Q456" --> 1, 2
	local function itercolumns(columntable)
		local keys = {}
		for k, v in pairs(columntable) do
			keys[v.key] = k --v.key is just the order of the columns
		end
		local upto = 1
		return function ()
			while keys[upto] do
				upto = upto + 1
				return columntable[keys[upto-1]]
			end
		end
	end

	local timeOfRace
	for ii, v in pairs(stages) do
		if v.mainsnak.snaktype == 'value' then
			local somewinner = false --show the stage
			local stageID = v.mainsnak.datavalue.value.id
			local sitelink = mw.wikibase.getSitelink(stageID)
			if displaytypeofstage==true then
				sType = typeofstagelogo(stageID)
			end
			local p = mw.wikibase.getBestStatements(stageID, 'P1545') -- P1545 is 'series ordinal'
			local sOrdinal = p[1] and p[1].mainsnak.snaktype == 'value' and p[1].mainsnak.datavalue.value
				or ''
			local _, _, sNumber, sLetter = string.find(sOrdinal, '(%d+)(.*)')
			sNumber=sNumber or ''
			sLetter=sLetter or ''

			local label, section_title
			if sOrdinal == "0" then
				label, section_title = translate("func_prologue",1), "#" .. translate("func_prologue",1)
			else
				label, section_title = stageLink(sOrdinal, sNumber, sLetter)
			end
			-- If there is a Wikipedia article of that stage show it or show the section.
			local sLink = sitelink and ("[[" .. sitelink .. "|" .. label .. "]]") or
				("[[" .. section_title .. "|" .. label .. "]]")

			timeOfRace =getTimeOfRace(stageID)

			local win= {}
			for _, v in pairs(winners) do
				win[v.QID] = ''
				if ii==1 then jerseytable[v.QID]='' end
			end
			winner(lf,stageID, win, timeOfRace, false, WDlink_on, false, false) --fill win table
			if ii<=2 then --only two first stages
				jerseytable, bgcolortable=winnerjersey(stageID, jerseytable)
			end
			for _, v in pairs(winners) do
				if v.QID and win[v.QID] ~= '' then
					--column info
					somewinner=true
					columntable[v.QID][ii]["leader"]=win[v.QID]
					if ii==1 then --first stage
						columntable[v.QID][ii]["start"]=1  --start at row 1
						columntable[v.QID][ii]["rowspan"]=1  --1 consecutive stage
					elseif columntable[v.QID][ii-1]["leader"]==win[v.QID] then --same winner as past stage ,make previous longer and delete this one
						local initialstage=columntable[v.QID][ii-1]["start"]
						columntable[v.QID][ii]["start"]=initialstage --need because of the row above
						columntable[v.QID][initialstage]["rowspan"]=columntable[v.QID][initialstage]["rowspan"]+1 --one more consecutive stage
						columntable[v.QID][ii]["rowspan"]=0
					else --new winner
						columntable[v.QID][ii]["start"]=ii --start at this row/stage
						columntable[v.QID][ii]["rowspan"]=1  --1 consecutive stage
					end
					columntable[v.QID].used=true
					if ii<=2 then --read the jersey in the two first stages of a race
						if columntable[v.QID].jersey == '' or columntable[v.QID].jersey==nil then
							columntable[v.QID].jersey=jerseytable[v.QID]
							columntable[v.QID].bg_color=bgcolortable[v.QID]
						end
					end
				end
			end
			table.insert(stageinfotable,{sLink=sLink, sType=sType, somewinner=somewinner})
		end
	end

	--read parent
	local win= {}
	for _, v in pairs(winnersgen) do
		if v.QID then
			win[v.QID] = ''
			jerseytable[v.QID]=''
		end
	end
	local thiskey
	somewinner = false
	jerseytable, bgcolortable=winnerjersey(raceID, jerseytable)
	winner(lf,raceID, win, timeOfRace, false, WDlink_on, false, false)
	for _, v in pairs(winnersgen) do
		if win[v.QID] and win[v.QID] ~= '' then
			somewinner=true
			thiskey=generaltoleader[v.QID]
			--fill the final classification
			columntable[thiskey][#stages+1]["leader"]=win[v.QID]
			columntable[thiskey][#stages+1]["start"]=#stages+1
			columntable[thiskey][#stages+1]["rowspan"]=1
			--#stages is the last stage
			if (type(columntable[thiskey][#stages]["leader"])~="string"  --combativity is not extrapolated
			    and thiskey~='Q20893984') then --check nil actually, but it is a table..
			    
				columntable[thiskey][#stages]["leader"]= win[v.QID] --extrapolate the winner
				if (type(columntable[thiskey][#stages-1]["leader"])=="string" and 
				    win[v.QID]==columntable[thiskey][#stages-1]["leader"]) then --if there is a leader at forelast stage
				
					local initialstage=columntable[thiskey][#stages-1]["start"]
					columntable[thiskey][#stages]["start"]=initialstage --needed because of row above
					columntable[thiskey][initialstage]["rowspan"]=columntable[thiskey][initialstage]["rowspan"]+1
					columntable[thiskey][#stages]["rowspan"]=0
				else
					columntable[thiskey][#stages]["start"]=#stages
					columntable[thiskey][#stages]["rowspan"]=1
				end
			end
			if jerseytable[v.QID] and jerseytable[v.QID]~='' then
				columntable[thiskey].jersey=jerseytable[v.QID]
				columntable[thiskey].bg_color=bgcolortable[v.QID]
			end
		end
	end
	table.insert(stageinfotable,{sLink=translate("listofstagesclassification",2,w_race), sType=nil, somewinner=somewinner}) 

	--build the table
	local	tab=mw.html.create('table')
	:attr('cellpadding','4' )
	:attr('cellspacing','0')
	:cssText(standardtablecss)
	local tRow=tab:tag('tr'):css('background-color',backgroundColor)
	:css('text-align','center'):css('color', 'inherit')
	tRow:tag('th'):css('white-space','nowrap')
	:wikitext(((not WDlink_on and wdLink(string.gsub(raceID, '%s', '') .. "#P527")) or "")..
	translate("headoftable",1,w_race))
	
	if displaytypeofstage==true then tRow:tag('th') end

	for v in itercolumns(columntable) do
		if v.used == true then
			if v.jersey == '' then v.jersey = "_" end
			tRow:tag('th'):wikitext(v.name.."<br />"..v.jersey)
		end
	end

	local style
	--then fill the table
	for ii, v in pairs(stageinfotable) do --one stage=one row
		--stages link
		tRow=tab:tag('tr')
		local tCell=tRow:tag('td')
		if ii==#stageinfotable then 
			tCell:attr('colspan','2'):cssText('font-weight:bold; border-top: 2px black solid;')
		end
		tCell:wikitext(v.sLink)
		
		if displaytypeofstage == true then
			tCell=tRow:tag('td')
			if ii==#stageinfotable then --general row
				tCell:cssText('font-weight:bold; border-top: 2px black solid;')
			end
			if v.sType then
				tCell:wikitext(v.sType) --picture type of stage
			end
		end

		--add winners
		for y in itercolumns(columntable) do
			if y.used==true and not (ii==#stageinfotable and columntable['Q20882747']==y) then --only display used QID
				if type(y[ii]["leader"])=="string" and type(y[ii]["rowspan"])=="number" then --actually check nil but it is a table
					style=""
					if y[ii]["rowspan"]~=0 and (columntable['Q20882747']==y)==false then
						if ii~=1 and ii~=#stageinfotable then style=style.." border-top:1px gray solid;" end
						if y.bg_color then style=style.." background-color:"..y.bg_color..";" end
						if ii==#stageinfotable then style=style.."font-weight:bold; border-top: 2px black solid;" end
						tRow:tag('td'):attr('rowspan',tostring(y[ii]["rowspan"])):cssText(style):wikitext(y[ii]["leader"])
					elseif (columntable['Q20882747']==y) then --no rowspan for stages
						tRow:tag('td'):wikitext(y[ii]["leader"])
					end
				else
					tCell=tRow:tag('td')
					if ii~=#stageinfotable and v.somewinner==true then
						tCell:wikitext(translate("listofstagesclassification",1,w_race)) --not attributed 
					elseif ii~=#stageinfotable then
						 --empty
					elseif v.somewinner==true then  --general row
						tCell:cssText('border-top: 2px black solid')
						:wikitext(translate("listofstagesclassification",1,w_race)) --not attributed 
					else
						tCell:cssText('border-top: 2px black solid') --empty
					end
				end
			end
		end
	end
	return tab
end

--M) Start list
function p.startlist(frame)
	local tempID, lf=get_and_checkID(frame)
	local w_race=isWomenrace(tempID)
	local s = {
		header_function = "startlist",
		header_1 = 1, -- translation 1 in function victories is printed in the upper part of the table header
		header_2 = {2, 3,4,5},
		item=tempID,
		title="Start list",
		data_sort_type={'unsortable', 'unsortable', 'unsortable'},
		property ='P710',
		no_roll_startlist=no_roll_startlist,
		w_race=w_race,
		lf=lf
	}

	local resultTable, tag = tableB(s)
	return startlist_main(s, resultTable, tag)  
end

function p.startlisttable(frame)
	local tempID, lf=get_and_checkID(frame)
	local w_race=isWomenrace(tempID)

	local s = {
		header_function = "startlisttable",
		header_1 = 1, -- translation 1 in function victories is printed in the upper part of the table header
		header_2 = {2, 3,4,5},-- translations 2, 3, 4, 5, 6 in function victories are printed in this order
		item=tempID,
		title="Start list", -- in the lower part of the table header. The second value 3 in {4, 3} tells where the icon will go.
		no_country ={'fr'},
		data_sort_type={'', '', ''},
		property ='P710',
		no_roll_startlist=no_roll_startlist,
		w_race=w_race,
		lf=lf
	}
	return startlisttable_main(s, tableA(s))
end

local function startlist_sub(p710, timeOfRace,  WDlink_on, istable,w_race)
	--Return a table containing a row for the selected rider and their associated team, link, etc
	local h = {}
	local tBody = '' --row in our case
	local riderID, riderTeamLink, riderTeamID, riderDossard, riderLink, riderRank
	local q, gender, riderTeamCode, riderDNF, DSQ, catID, countryID, national_team_boolean

	riderID = p710.mainsnak.datavalue.value.id
	q= p710.qualifiers
	riderLink= getRiderLink(riderID, timeOfRace)
	if WDlink_on then riderLink=riderLink..wdLink(riderID) end
	if q and q.P1618 and q.P1618[1].snaktype == 'value' then
		riderDossard = q.P1618[1].datavalue.value or ''
	else
		riderDossard = ''
	end
	riderDNF='' riderRank = '' DSQ=''
	if q and q.P1352 and q.P1352[1].snaktype == 'value' then -- P1352 is ranking
		riderRank = tonumber(q.P1352[1].datavalue.value.amount)
		--look for DSQ--
		DSQ=isdisqualified(p710, q)
	else
		--look for DNF...
		if q and q.P1534 and q.P1534[1].snaktype == 'value' then
			local dnf=q.P1534[1].datavalue.value.id
			if dnf=='Q1210380' then riderDNF =translate("startlist",6,w_race)--"HD","NP","DQ"
			elseif dnf=='Q54881674' or dnf=='Q7113430' then riderDNF =translate("startlist",7,w_race)
			elseif dnf=='Q1210382' then riderDNF =translate("startlist",8,w_race)
			elseif dnf=='Q1229261' then riderDNF =translate("startlist",9,w_race)
			else riderDNF=''
			end
			if q.P1545 and q.P1545[1].snaktype == 'value' then
				local stageofdnf=q.P1545[1].datavalue.value
				if stageofdnf and string.len(stageofdnf)>1 then
					riderDNF='<small>'..riderDNF.."-"..stageofdnf..'</small>'
				else
					riderDNF=riderDNF.."-"..stageofdnf
				end
			end
		end
	end

	h = {
		jersey = {}, -- lots of jerseyID
		value = {'', '', '', ''} -- points, time, time_gap, speed
	}

	if q and q.P2912 then -- P2912 is distinctive jersey
		for _, v in pairs(q.P2912) do
			if v.snaktype == 'value' then
				table.insert(h.jersey, v.datavalue.value.id)
			end
		end
	end

	if wiki == 'es' or wiki == 'fr' or wiki == 'ast' then
		--[[ These wikis need the gender to display the rank correct. Other wikis can skip this. ]]
		gender = getGenderCode(riderID, 'n')
	end
	local countryID = getNationality(riderID, timeOfRace,q)
	local uciCode=''
	local jerseytemp=''
	if countryID then
		if wiki ~= "ar" then 
			uciCode=uciCodeCountry(countryID)
		end
		riderLink = flag(countryID, timeOfRace) ..' '.. riderLink 
	end

	if h.jersey[1] then
		jerseytemp=champtitle(h.jersey) -- champtitle manages also the jersey
	end
	
	riderTeamLink, riderTeamID, catID, countryID = getTeam(riderID, timeOfRace, q)
	riderTeamID=seasonToTeamID(riderTeamID)
	riderTeamCode= getTeamCode(riderID, timeOfRace, q)
	
	--Custom display for national selection
	if data.natTeamCats[catID] and countryID then
		if riderTeamCode and wikibase.getSitelink(countryID) then --for the refugee case
			riderTeamCode='[['..wikibase.getSitelink(countryID)..'|'..riderTeamCode..']]'
		end
		riderTeamLink=flag(countryID, timeOfRace)..' '..riderTeamLink
	else --for non national selection display "ridername (FRA)""
		riderLink =riderLink..uciCode
	end
	riderLink =riderLink..jerseytemp

	local sortkey = riderDossard == "" and 0 or tonumber(riderDossard)

	tBody =   mw.html.create('tr'):cssText("line-height: 1.8em; padding: 5px;")
	tBody:tag('td'):cssText("text-align:right;padding:0 0.5em"):wikitext(riderDossard)
	tBody:tag('td'):cssText('text-align:'..textalign.. ';padding:0 0.5em;'..DSQ):wikitext(riderLink)

	local td_css = "text-align:left;padding:0 0.5em"
	if wiki == "ar" then td_css = "text-align:right;padding:0 0.5em" end
	if istable then
		tBody:tag('td'):cssText(td_css):wikitext(riderTeamLink or "")
	end
	tBody:tag('td'):cssText('text-align:'..textalign.. ';padding:0 0.5em;'..DSQ):wikitext(number(gender,riderRank,wiki)..riderDNF)

	--table.insert(resultTable, )
	return {sortkey=sortkey, riderTeamLink=riderTeamLink,riderTeamID=riderTeamID,riderTeamCode=riderTeamCode, body=tBody}
end

function startlist_main(s, resultTable, tag)
	local ridertable, DStable, subtable	 = {}, {}, {}
	local DSID, DSLink, DSteamID, DSteam
	local WDlink_on = (wiki == "mk" or wiki == "ja" or wiki == "ru")

	local timeOfRace=getTimeOfRace(s.item)
	local w_race=isWomenrace(s.item)

	for _,p286 in statements(s.item, 'P286') do--look for DS
		DSID = p286.mainsnak.datavalue.value.id
		DSLink= getRiderLink(DSID, timeOfRace)
		DSteamID=nil
		q= p286.qualifiers
		
		if q.P6087 and q.P6087[1].snaktype == 'value' then --coach of sports team
			DSteamID=q.P6087[1].datavalue.value.id
		elseif q.P642 and q.P642[1].snaktype == 'value' then --fallback
			DSteamID=q.P642[1].datavalue.value.id
		end
		if DSteamID then DSteamID=seasonToTeamID(DSteamID) end
		table.insert(DStable, {DSLink=DSLink, DSteamID=DSteamID})
	end

	for _, p710 in statements(s.item, 'P710') do -- P710 is participants
		table.insert(ridertable, startlist_sub(p710, timeOfRace, WDlink_on, false,w_race))
	end
	table.sort(ridertable, function(a, b)  --sort by team and then by bib and then by team
		if a['sortkey'] ~= b['sortkey'] then --sort by bib
            return a['sortkey'] < b['sortkey']
		else
        	return (a['riderTeamCode'] or 'a') < (b['riderTeamCode'] or 'a') --order does not matter for nil
    	end
    end) 
	local thisTableRow, thisTeamTable, thisDS, insideTable, test
	local tSubtitle, tTitle
	
	if wiki == "ar" then
		tSubtitle=mw.html.create('tr')
		tSubtitle:tag('td'):attr('width','30px')
		:css("align:right;text-align:right")
		:wikitext(translate("startlist",2,w_race))
		tSubtitle:tag('td'):attr('width','200px')
		:css("align:right;text-align:right")
		:wikitext(translate("startlist",3,w_race))
		tSubtitle:tag('td'):attr('width','85px')
		:css("align:right;text-align:right")
		:wikitext(translate("startlist",4,w_race))
	else
		tSubtitle=mw.html.create('tr')
		tSubtitle:tag('td'):attr('width','30px'):wikitext(translate("startlist",2,w_race))
		tSubtitle:tag('td'):attr('width','250px'):wikitext(translate("startlist",3,w_race))
		tSubtitle:tag('td'):attr('width','35px'):wikitext(translate("startlist",4,w_race))
	end

	--look for transition between teams
	local numberofteam=0
	local tDS

	if #ridertable==0 then--empty table
		return nil
	else
		for ii=1,#ridertable  do
			--new team
			if not (ii~=1 and ridertable[ii].riderTeamID==ridertable[ii-1].riderTeamID) or ii==1 then --ridertable[ii].riderTeamID and 
				if thisDS and ii~=1 then
					tDS=insideTable:tag('tr')
					tDS:tag('td'):attr('colspan','3'):attr('align','center')
					:wikitext(translate("startlist",5,w_race).." "..thisDS)
					thisDS=nil
				end
				
				numberofteam=numberofteam+1
				if math.fmod(numberofteam, 3 )==1 then
					if ii~=1 then
						tag:node(thisTableRow) --a row with 3 tables inside, save and re-init
					end
					thisTableRow=mw.html.create('tr') 
				end
				thisTeamTable= thisTableRow:tag('td'):cssText("width:33%;"):attr('valign','top')
				insideTable=thisTeamTable:tag('table') --reinit
				:attr('cellpadding','4') --solid var(--border-color-subtle, #c8ccd1)
				:attr('background-color','var(--background-color-base, #fff)')
				:attr('color', 'inherit')
				:attr('margin', '0 0 0.5em 0')
				:attr('padding','5px')
				:attr('float','left')
				:attr('text-align',textalign)
				:attr('line-height','1.8em')
				:attr('clear',floattable)

				tTitle =  mw.html.create('tr')
				:css("background-color",backgroundColor)
				:css('color', 'inherit')
				:attr('align','center')
				local tCell=tTitle:tag('th'):attr('colspan','3')
				tCell:tag('big'):wikitext((ridertable[ii].riderTeamLink or translate("startlist",13,w_race)).."<br/>"..(ridertable[ii].riderTeamCode or "___"))
				
				insideTable:node(tTitle)
				insideTable:node(tSubtitle)
				
				tDS=nil
				--look for the DS of this team
				for _,v in pairs(DStable) do
					if v.DSteamID==ridertable[ii].riderTeamID then
						if not thisDS then
							thisDS=v.DSLink
						else
							thisDS=thisDS..", "..v.DSLink
						end
					end
				end
			end
			--add the rider, also for old team
			insideTable:node(ridertable[ii].body)
		end
		--last DS
		if thisDS then
			tDS=insideTable:tag('tr')
			tDS:tag('td'):attr('colspan','3'):attr('align','center')
			:wikitext(translate("startlist",5,w_race).." "..thisDS)
		end
		tag:node(thisTableRow)

		return resultTable
	end
end

local KeytoRiderRankingCode={
		["women"]=	2, 
		['WWT']=	3, 
		['WWC']=	4,	
		["UWT"]=	5,
		["europe"]=	6, 
		["asia"]=	7,
		["oceania"]=8,
		["america"]=9,
		["africa"]=	10, 
		["WR"]=	 11, 
		["WC"]=		12, 
		["UPT"]=	13, --WC is world calendar here
		["UCImen"]=	14, 
		["WCmen"]=	15, --UCImen = UCI ranking 1984-2004, WC= World cup men
		["Pernod"]=	16, 
		["Desgrange"]=17,
	}

function startlisttable_main(s, resultTable)
	local t_Body = {}
	local WDlink_on = (wiki == "mk" or wiki == "ja" or wiki == "ru")

	local timeOfRace=getTimeOfRace(s.item)

	for _, p710 in statements(s.item, 'P710') do -- P710 is participants
		table.insert(t_Body, startlist_sub(p710, timeOfRace, WDlink_on, true))
	end

	return sortAndConcat(t_Body, resultTable)
end

-- N) Rider ranking
local function checkminmaxyear(minmaxyear,thisyear)
	if minmaxyear.minimum ==0 or thisyear<minmaxyear.minimum then
		minmaxyear.minimum=thisyear
	end
	if minmaxyear.maximum==0 or thisyear>minmaxyear.maximum then
		minmaxyear.maximum=thisyear
	end
   return minmaxyear
end

function p.riderranking(frame)
	local tempID, lf=get_and_checkID(frame)
	local s = {
		item = tempID,
		lf=lf
	}
	return riderranking_main(s)
end

local function checkWorldTourTeam(itemID,year)
	local thisdate='+'..tostring(year).."-07-01T00:00:00Z"
	local catID
	
	for _, s in statements(itemID, 'P54') do
		p54 =checktime(s, s.qualifiers, thisdate) --present Team
		if p54 then
			teamId= p54.mainsnak.datavalue.value.id
			_, catID=getTeamLinkCat(teamId, thisdate)
			if catID=="Q6154783" or catID=="Q20638319" then
				return true
			end
		end
	end
	return false
end

local function ranking_legend()
	local UCIlink, legend
	if wiki=="fr" then
		UCIlink="https://www.uci.org/fr/route/classements" --see also https://dataride.uci.org/iframe/Rankings/10/
		legend= "  Légende : nc = non classé"
	else
		UCIlink="https://www.uci.org/road/rankings" 
		legend=""
	end
	return UCIlink, legend
end

local function riderranking_sub(w_race)
	local listofcalendar=data.listofmencalendar
	if w_race then
		listofcalendar=data.listofwomencalendar
	end

	local UCIQtoYear={}
	for k,v in pairs(data.UCIYearToQ) do
		UCIQtoYear[k]={}
		for kk, vv in pairs(v) do
			UCIQtoYear[k][vv]=kk  --calendar/Q = year
		end
	end
	return listofcalendar, UCIQtoYear
end

function riderranking_main(s)
	local lf=s.lf
	local thisCompetition, rank, thisyear, sitelink, q, gender, DSQ
    local calendarlistpresent={}

	local gender=getGenderCode(s.item, 'm')
	local w_race=false
	if gender=="f" then w_race=true end

	local minmaxyear= {	minimum = 0, maximum = 0 }
	local listofcalendar, UCIQtoYear=riderranking_sub(w_race)

	local resultTable={}
	for ii=1900,2100,1 do
		resultTable[tostring(ii)]={}
		for _, calendar  in pairs(listofcalendar) do
			resultTable[tostring(ii)][calendar]={}
		end
	end

	--build the table
	for _, p1344 in statements(s.item, 'P1344') do
		thisCompetition = p1344.mainsnak.datavalue.value.id
		for _, calendar  in pairs(listofcalendar) do
			if UCIQtoYear[calendar][thisCompetition] then
				thisyear=UCIQtoYear[calendar][thisCompetition]
				minmaxyear=checkminmaxyear(minmaxyear,thisyear)
				q = p1344.qualifiers
				if q and q.P1352 and q.P1352[1].snaktype == 'value' then --rank
					resultTable[thisyear][calendar]["rank"] = tostring(tonumber(q.P1352[1].datavalue.value.amount)) --without the tonumber, there can be +1 instead of 1
					resultTable[thisyear][calendar]["DSQ"] = isdisqualified(p1344, q) or ""
					calendarlistpresent[calendar]=true
					sitelink=mw.wikibase.getSitelink(thisCompetition)
					resultTable[thisyear][calendar]["sitelink"]=sitelink
				end
			end
		end
	end

	--display result
	if minmaxyear.minimum~=0 then
		local finalTable =mw.html.create('table'):attr('cellspacing','0')
		:attr("align","center"):cssText("text-align:center; border: 1px solid #999;  line-height: 1.8em;")
		
		local wdLin = wdLink(string.gsub(s.item, '%s', '') .. "#P1344")
		local tRow= finalTable:tag('tr'):tag('th')
		:css("background-color",backgroundColor)
		:css('color', 'inherit')
		:wikitext(wdLin..' '..translate("riderranking",1,w_race)) --year

		for ii=minmaxyear.minimum,minmaxyear.maximum,1 do
			tRow:tag('th'):attr("width","50px")
			:css('background-color',backgroundColor)
			:css('color', 'inherit')
			:css("text-align","center")
			:css("padding","1px 1px")
			:wikitext(tostring(ii))
		end

		for _, calendar  in pairs(listofcalendar) do
			if calendarlistpresent[calendar] then
				sitelink=mw.wikibase.getSitelink(data.UCImaster[calendar])
				local tRow=finalTable:tag('tr')
				local tCell = tRow:tag('th'):cssText("text-align:" .. textalign .. ";") -- left
				local calendar_name=translate("riderranking",data.KeytoRiderRankingCode[calendar],w_race)
				if sitelink then
					tCell:wikitext('[['..sitelink..'|'..calendar_name..']]')
				else
					tCell:wikitext(calendar_name)
				end
				
				for yy=minmaxyear.minimum,minmaxyear.maximum,1 do
					thisyear=tostring(yy)
					color="white"
					local impossible=false
					--we need to check the impossibility here, as it is impossible even if nothing is in P1344
					if data.continental_calendar[calendar] then
						--between 2005 and 2015 WorldTour team member cannot score by continental calendars.
						if tonumber(thisyear)>=2005 and tonumber(thisyear)<=2015 then
							if checkWorldTourTeam(s.item,thisyear) then
								impossible=true
							end
						--between 2016 and 2018 no contradiction
						--after 2019, it depends on the nationality
						elseif tonumber(thisyear)>=2019 then
							local countryID=getNationality(s.item,'+'..tostring(year).."-07-01T00:00:00Z")
							if data.continental_calendar[calendar] and not data.continental_calendar[calendar][countryID] then
								impossible=true
							end
						end
					elseif calendar=="UWT" then
						--non member of World Tour team cannot point in the WT
						if tonumber(thisyear)>=2005 and tonumber(thisyear)<=2015 then
							if not checkWorldTourTeam(s.item,thisyear) then
								impossible=true
							end
						end
					end

					if resultTable[	thisyear][calendar]["rank"] or impossible then
						if impossible then
							tRow:tag('td'):css('background-color',backgroundColorLight):css('color', 'inherit')
						else
							if resultTable[thisyear][calendar]["rank"]=="1" then
								color="gold"
							elseif (2<=tonumber(resultTable[thisyear][calendar]["rank"])) and (tonumber(resultTable[thisyear][calendar]["rank"])<=3) then
								color="YellowGreen"
							elseif (4<=tonumber(resultTable[thisyear][calendar]["rank"])) and (tonumber(resultTable[thisyear][calendar]["rank"])<=10) then
								color="silver"
							end

							tCell=tRow:tag('td'):attr("bgcolor",color):cssText(resultTable[thisyear][calendar]["DSQ"])
							local rank=tonumber(resultTable[thisyear][calendar]["rank"])
							rank=number(gender,rank,wiki)
							if resultTable[thisyear][calendar]["sitelink"] then
								tCell:wikitext('[['..resultTable[thisyear][calendar]["sitelink"]..'|'..rank..']]')
							else
								tCell:wikitext(rank)
							end
						end
					--this ranking exist for this year, but the rider is not ranked
					elseif yy>=data.UCIcalendarstartend[calendar].b and
						(data.UCIcalendarstartend[calendar].e==0 or yy<=data.UCIcalendarstartend[calendar].e) then 
						if wiki=="fr" then
							tRow:tag('td'):wikitext(' nc ')
						else
							tRow:tag('td'):wikitext(' - ')
						end
					--this ranking does not exist for this year
					else 
						tRow:tag('td'):css('background-color',backgroundColorLight):css('color', 'inherit')
					end
				end
			end
		end
	
		local tableyearsize=minmaxyear.maximum-minmaxyear.minimum+2
		local UCIlink, legend=ranking_legend()
		
		finalTable:tag('tr'):tag('td'):addClass("navigation-only")
		:attr('colspan',tostring(tableyearsize))
		:cssText("border-top: 2px "..backgroundColor.." solid; font-size: 80%;")
		
		tCell=finalTable:tag('tr'):tag('td'):attr('colspan',tostring(tableyearsize))
		:tag('small')
		
		tCell:tag('span'):css("float","left")
		:wikitext(legend)
		tCell:tag('span'):css("float","right")
		:wikitext(translate("race_reference", 1,w_race).."["..UCIlink..' UCI]')

		return  finalTable
	end
end	

function p.teamranking(frame)
	local tempID, lf=get_and_checkID(frame)
	local calendar_key=get_arg(2,frame)
	if not calendar_key or calendar_key == "" then return "" end
	
	local w_race=false
	if calendar_key=="women" or calendar_key=="WWT" or calendar_key=="WWC" then
		w_race=true
	end

	local s = {
		header_function = "riderranking", 
	    header_1 = data.KeytoRiderRankingCode[calendar_key] or 1, 
		header_2 = {1, 18, 19},
		property="P527",
		data_sort_type = {'unsortable', 'unsortable', 'unsortable'}, 
		item = tempID,
		calendar_key=calendar_key,
		lf=lf,
		w_race=w_race
	}
	return teamranking_main(s,tableA(s))
end

local function get_teamranking(seasonID, w_race, UCIQtoYear,listofcalendar, tTable,gender)
	--fill resultTable
	local done, thisyear, q, done, rider, riderLink, countryID, rank, thisdate, teamrank
	
	for _, p1344 in statements(seasonID, 'P1344') do
		thisCompetition = p1344.mainsnak.datavalue.value.id

		for _, calendar  in pairs(listofcalendar) do
			if UCIQtoYear[calendar][thisCompetition] then
				thisyear=UCIQtoYear[calendar][thisCompetition]
				thisdate='+'..tostring(thisyear).."-07-01T00:00:00Z"
				rank=nil
				
				if tTable[calendar] then
					tTable[calendar][thisyear]={}
				else
					error("tTable badly initialized")
				end
				q = p1344.qualifiers
				done=false
				--get team rank
				local suffix=""
				if calendar== "UCImen" then --case of GSI  (Q20653563), GSII (Q20653564) and GSIII (Q20653566)
					propertyOf_id=nil
					if q and q.P279 and q.P279[1].snaktype == 'value' then
						propertyOf_id=q.P279[1].datavalue.value.id
					elseif q and q.P642 and q.P642[1].snaktype == 'value' then
						propertyOf_id=q.P642[1].datavalue.value.id
					end
					if propertyOf_id=="Q20653564" then
						suffix=" (GSII)"
					elseif propertyOf_id=="Q20653566" then
						suffix=" (GSIII)"
					end
				end

				if q and q.P1352 and q.P1352[1].snaktype == 'value' then --rank
					teamrank= tonumber(q.P1352[1].datavalue.value.amount) 
					tTable[calendar][thisyear]["teamrank"]=number(gender,teamrank,wiki)..suffix
					done=true
				end
				--get best rider rank
				if q and q.P1545 and q.P1545[1].snaktype == 'value' then --participant
					rank = tostring(tonumber(q.P1545[1].datavalue.value))
					done=true
				end
				--get best rider
				if q and q.P710 and q.P710[1].snaktype == 'value' then --participant
					rider = q.P710[1].datavalue.value.id
					riderLink = getRiderLink(rider, thisdate)
					countryID = getNationality(rider, thisdate)
					if countryID then
						riderLink = flag(countryID, thisdate) .. ' ' .. riderLink
					end
					if rank then
						rank=number(gender,tonumber(rank),wiki)
						riderLink=riderLink.." ("..rank..")"
					end
					tTable[calendar][thisyear]["rider"]=riderLink
					done=true
				end				

				sitelink=mw.wikibase.getSitelink(thisCompetition)
				tTable[calendar][thisyear]["sitelink"]=sitelink
			end	
		end
	end
	return tTable
end

function teamranking_main(s, resultTable)
	local lf=s.lf
	local t_Body = {}
	
	local gender="m"
	if s.w_race then gender="f" end

	--init, reverse UCIQtoYear
	local UCIQtoYear={}
	UCIQtoYear[s.calendar_key]={}
	if data.UCIYearToQ[s.calendar_key] then
		local v=data.UCIYearToQ[s.calendar_key]
		for kk, vv in pairs(v) do
			UCIQtoYear[s.calendar_key][vv]=kk
		end
	end

	local tTable={}
	tTable[s.calendar_key]={}
	for ii, p527 in statements(s.item, "P527") do
		tTable=get_teamranking(p527.mainsnak.datavalue.value.id, w_race, 
			                        UCIQtoYear,{s.calendar_key}, tTable,gender)
	end
	
	local t=tTable[s.calendar_key]
	if t then
		for thisyear, v in pairs(t) do
			local tRow = mw.html.create('tr'):cssText( "line-height: 1.8em; padding: 0.5em;")
			local tCell=tRow:tag('td'):css("text-align",textalign)
			
			if v["sitelink"] then
				tCell:wikitext('[['..v["sitelink"]..'|'..thisyear..']]')
			else
				tCell:wikitext(thisyear)
			end
			
			if v["teamrank"] then
				tRow:tag('td'):wikitext(v["teamrank"]):css("text-align","center")
			else
				tRow:tag('td'):wikitext(" - "):css("text-align","center")
			end
			if v["rider"] then
				tRow:tag('td'):wikitext(v["rider"])
			else
				tRow:tag('td'):wikitext(" - ")
			end
			table.insert(t_Body, {sortkey=thisyear, body=tRow})
		end
	end
	resultTable=sortAndConcat(t_Body, resultTable)
	local UCIlink, _=ranking_legend()
	
	local tRow=resultTable:tag('tr')
	tRow:tag('td'):addClass("navigation-only")
	:attr('colspan',tostring(3))
	:cssText("border-top: 2px "..backgroundColor.." solid; font-size: 80%;")
	tRow=resultTable:tag('tr')
	local tCell=tRow:tag('td'):attr('colspan',tostring(3)):tag('small')
	tCell:tag('span'):css("float","right")
	:wikitext(translate("race_reference", 1,w_race).."["..UCIlink..' UCI]')
	
	return resultTable
end


local function toboolean(str)
	if str=="true" then
		return true
	elseif str=="false" then
		return false
	else
		return str
	end
end

--=== O) Rider infobox
local function convertDate(date1, beginOrEnd, initialYear, finalYear)
	if not date1 then
		if beginOrEnd==0 then --begin
			y1=tostring(initialYear)
			m1="01"
			d1="01"
		else
			y1=tostring(finalYear)
			m1="12"
			d1="31"
		end
	else
		_, _, y1,m1,d1 = string.find(date1, "(%d+)-(%d+)-(%d+)")
		if m1 ==nil or m1=="00" then
			if beginOrEnd==0 then --begin
				m1="01"
				d1="01"
			else--end
				m1="12"
				d1="31"
			end
		end
	end
	return '+'..y1.."-"..m1.."-"..d1.."T00:00:00Z"
end

local function listofTeam(itemID, initialYear, finalYear, PID) 
	--first we have to read P54 of the rider
	--alternative P6087 for managed team
	local riderteam={}
	local stagiaire
	--initially initialYear is the birthyear of the rider
	--end year is now +10 years, or the death date
	--let's reduce the range (note: it may be slightly over-engineered, maybe it can be deleted and just assume 10 years in the future is sufficient)
	local today=os.date("*t")
	local t1=tonumber(today['year'])
	local t2=math.min(finalYear, tonumber(today['year']))  
	local t_initialYear=t1
	local t_finalYear=t2

	for ii, p54 in statements(itemID, PID) do --itemID loaded in presentTeam
		local q = p54.qualifiers
		if q then
			local sTime, eTime=getStartEndfromQuali(q)
			--min/max 
			if sTime then
				y=tonumber(string.sub(sTime, 2, 5))
				if y < t_initialYear then
					t_initialYear=y
				end
				if y>t_finalYear then
					t_finalYear=y
				end
			end
			if eTime then
				y=tonumber(string.sub(eTime, 2, 5))
				if y < t_initialYear then
					t_initialYear=y
				end
				if y>t_finalYear then
					t_finalYear=y
				end
			end	
		end
	end
	
	if t_initialYear~=t1 then initialYear=t_initialYear end
	if t_finalYear~=t2 then finalYear=t_finalYear end

	for ii, p54 in statements(itemID, PID) do --itemID loaded in presentTeam
		if p54 then
			teamId=p54.mainsnak.datavalue.value.id
		else
			teamId=nil
		end
		local q = p54.qualifiers
		if q then
			local sTime, eTime=getStartEndfromQuali(q)
			sTime=convertDate(sTime, 0, initialYear, finalYear)
			eTime=convertDate(eTime, 1, initialYear, finalYear)
			if q.P39 and q.P39[1] and	q.P39[1].snaktype == 'value' then
				stagiaire = q.P39[1].datavalue.value
			else
				stagiaire = nil
			end
			dis=checkDis(q)
			table.insert(riderteam,{teamId=teamId, startTime=sTime, endTime=eTime, stagiaire=stagiaire, dis=dis})
		end
	end
	return riderteam, initialYear, finalYear
end

--format the date for display of the team
local function riderFormatDate(thisDate) 
	if thisDate=='' then
		return ''
	else
		local month=math.ceil(thisDate['month']/2)
		if month==12 or month==1 then
			return thisDate['year']
		else
			local date1='+'..thisDate['year'].."-"..month.."-".."01".."T00:00:00Z"
		--	local newobj = Complexedate.splitDate(date1)  
			if month == 0 or month==nil then
				return thisDate['year']
			else
				return month..'.'..thisDate['year']
			end
		end
	end
end

local function getTeamInfo(teamId,mm,yy,dd,managedTeam)
	--get the nature and name of the team for the date mm,yy
	mm=tostring(mm)
	yy=tostring(yy)
	dd=tostring(dd)
	if mw.ustring.len(mm)==1 then mm='0'..mm end
	if mw.ustring.len(dd)==1 then dd='0'..dd end
	
	thistime='+'..yy.."-"..mm.."-"..dd.."T00:00:00Z"
	local sitelink, teamNature=getTeamLinkCat(teamId, thistime, false) 
	local cat, boolean

	if managedTeam then
	   cat=data.nationalcat
	else
	   cat=data.amateurcat
	end

	if cat[teamNature] then --club
		boolean=true--amateur / national selection 
	else
		boolean=false--pro  / not national selection
	end
	return boolean, sitelink
end

--for managed team, the table should be splat, as we can be national trainer and team trainer at the same time
local function analyzeManagedTeam(teamRider, initialYear,finalYear)
	local natTeamOut, managedTeamOut={},{}
	local dis="road"
	local managedTeam=true
	
	for i=1,24 do --init table
		natTeamOut[i]={}
		managedTeamOut[i]={}
		for j=initialYear,finalYear do
			natTeamOut[i][j]={ amateurTeam, link, stagiaire=nil}
			managedTeamOut[i][j]={amateurTeam,link, stagiaire=nil}
		end
	end

	local teamId, natTeam, sitelink
	local sYear, sMonth,eYear, eMonth, sDay, eDay

	if teamRider==nil then return nil end
	
	for _, v in pairs(teamRider) do --for each team where was the rider
		if v['dis']==dis then 
			--exception managed at the reading
			_, _, sYear,sMonth,sDay = string.find(v['startTime'], "(%d+)-(%d+)-(%d+)")
			_, _, eYear,eMonth,eDay = string.find(v['endTime'], "(%d+)-(%d+)-(%d+)")
	
			sYear=tonumber(sYear)
			sMonth=tonumber(sMonth)
			eYear=tonumber(eYear)
			eMonth=tonumber(eMonth)
	
			if sYear<=eYear then --test of congruence
				for yy=sYear,eYear do 
					for mm=1,12 do
						local mmindex=(mm-1)*2+1
						--avoid reading info where the team is not the one of the rider
						getinfo=true
						if (yy==sYear and mm<sMonth) or (yy==eYear and mm>eMonth) then
							getinfo=false
						end
	
						if getinfo then
							if (yy==sYear) and (mm==sMonth) and (sDay~='01' and sDay~='00' and sDay~=nil)then 
								natTeam, sitelink=getTeamInfo(v['teamId'],mm,yy,sDay, managedTeam)
								if natTeam then
									natTeamOut[mmindex+1][yy]['amateurTeam']=true
									natTeamOut[mmindex+1][yy]['link']=sitelink
								else
									managedTeamOut[mmindex+1][yy]['amateurTeam']=false
									managedTeamOut[mmindex+1][yy]['link']=sitelink
								end	
							else
								natTeam, sitelink=getTeamInfo(v['teamId'],mm,yy,'01', managedTeam)
								if natTeam then
									natTeamOut[mmindex][yy]['amateurTeam']=true
									natTeamOut[mmindex][yy]['link']=sitelink
									if natTeamOut[mmindex+1][yy]['amateurTeam']==nil or v['stagiaire'] then --to avoid problem with team name change during the month
										natTeam, sitelink=getTeamInfo(v['teamId'],mm,yy,'28',managedTeam)
										natTeamOut[mmindex+1][yy]['amateurTeam']=true --a nat team stays a nat team
										natTeamOut[mmindex+1][yy]['link']=sitelink
									end
								else
									managedTeamOut[mmindex][yy]['amateurTeam']=false
									managedTeamOut[mmindex][yy]['link']=sitelink
									if managedTeamOut[mmindex+1][yy]['amateurTeam']==nil or v['stagiaire'] then --to avoid problem with team name change during the month
										natTeam, sitelink=getTeamInfo(v['teamId'],mm,yy,'28',managedTeam)
										managedTeamOut[mmindex+1][yy]['amateurTeam']=false --a nat team stays a nat team
										managedTeamOut[mmindex+1][yy]['link']=sitelink
									end
								end
							end
						end
					end
				end
			end
		end
	end
	return natTeamOut, managedTeamOut --a filled matrix with the link and nature of the teams
end

local function analyzeTeam(teamRider, initialYear,finalYear, dis)
	local teamOut={}
	local managedTeam=false
	
	for i=1,24 do --init table
		teamOut[i]={}
		for j=initialYear,finalYear do
			teamOut[i][j]={ amateurTeam, link, stagiaire}
		end
	end

	local teamId, amateurTeam, sitelink
	local sYear, sMonth,eYear, eMonth, sDay, eDay

	if teamRider==nil then return nil end
	
	for _, v in pairs(teamRider) do --for each team where was the rider
		if v['dis']==dis then 
			--exception managed at the reading
			_, _, sYear,sMonth,sDay = string.find(v['startTime'], "(%d+)-(%d+)-(%d+)")
			_, _, eYear,eMonth,eDay = string.find(v['endTime'], "(%d+)-(%d+)-(%d+)")
	
			sYear=tonumber(sYear)
			sMonth=tonumber(sMonth)
			eYear=tonumber(eYear)
			eMonth=tonumber(eMonth)
	
			if sYear<=eYear then --test of congruence
				for yy=sYear,eYear do 
					for mm=1,12 do
						local mmindex=(mm-1)*2+1
						--avoid reading info where the team is not the one of the rider
						getinfo=true
						if (yy==sYear and mm<sMonth) or (yy==eYear and mm>eMonth) then
							getinfo=false
						end
	
						if getinfo then
							if (yy==sYear) and (mm==sMonth) and (sDay~='01' and sDay~='00' and sDay~=nil)then 
								amateurTeam, sitelink=getTeamInfo(v['teamId'],mm,yy,sDay, managedTeam)
								teamOut[mmindex+1][yy]['amateurTeam']=amateurTeam
								teamOut[mmindex+1][yy]['link']=sitelink
								teamOut[mmindex+1][yy]['stagiaire']=v['stagiaire']
							else
								amateurTeam, sitelink=getTeamInfo(v['teamId'],mm,yy,'01', managedTeam)
								teamOut[mmindex][yy]['amateurTeam']=amateurTeam
								teamOut[mmindex][yy]['link']=sitelink
								teamOut[mmindex][yy]['stagiaire']=v['stagiaire']
								if teamOut[mmindex+1][yy]['amateurTeam']==nil or v['stagiaire'] then --to avoid problem with team name change during the month
									amateurTeam, sitelink=getTeamInfo(v['teamId'],mm,yy,'28',managedTeam)
									teamOut[mmindex+1][yy]['amateurTeam']=amateurTeam
									teamOut[mmindex+1][yy]['link']=sitelink
									teamOut[mmindex+1][yy]['stagiaire']=v['stagiaire']
								end
							end
						end
					end
				end
			end
		end
	end
	return teamOut --a filled matrix with the link and nature of the teams
end

local function insertTeam(teamAmateur,teamPro,sDate,eDate,v)
	local sDate2=riderFormatDate(sDate)
	local eDate2=riderFormatDate(eDate)
	local ins = {link=v['link'], sDate=sDate2,eDate=eDate2,stagiaire=v['stagiaire']}
	 
	if v['amateurTeam'] then
		table.insert(teamAmateur,ins)
	else
		table.insert(teamPro,ins)
	end
	return teamAmateur,teamPro
end

local function synthetizeTable(analyzedTeam, initialYear,finalYear)
	local teamPro, teamAmateur, tempTeam, tempsDate, tempeDate={}, {},{},{},{}
	local empty=true
	local active=false
    --bring together successive month with identical content
	for yy=initialYear,finalYear do
		for mm=1,24 do
			local v=analyzedTeam[mm][yy]
			if v['amateurTeam']~=nil then
				if empty then --first line
					active=true
					empty=false
					tempTeam=v
					tempsDate['month']=mm
					tempsDate['year']=yy
				else
					if tempTeam['amateurTeam']==v['amateurTeam'] and tempTeam['link']==v['link']
					and tempTeam['stagiaire']==v['stagiaire'] then --no change
						if yy==finalYear and mm==24 then--present team
							teamAmateur,teamPro=insertTeam(teamAmateur,teamPro,tempsDate,'',tempTeam)
						end
					else--change
						--save the old
						if active then --if active false then it was already saved
							if mm==1 then
								tempeDate['year']=yy-1
								tempeDate['month']=24
							else
								tempeDate['year']=yy
								tempeDate['month']=mm-1
							end
							teamAmateur,teamPro=insertTeam(teamAmateur,teamPro,tempsDate,tempeDate,tempTeam)
						end
						--save the new
						active=true
						tempTeam=v
						tempsDate['month']=mm
						tempsDate['year']=yy
					end --change
				end--first line
			elseif active then --there was a team and now there is an empty period
				active=false
				--save the old
				if mm==1 then
					tempeDate['year']=yy-1
					tempeDate['month']=24
				else
					tempeDate['year']=yy
					tempeDate['month']=mm-1
				end
				teamAmateur,teamPro=insertTeam(teamAmateur,teamPro,tempsDate,tempeDate,tempTeam)
				tempTeam['link']=nil --avoid problem if the rider comes back in the same team
			end  
		end-- for mm
	end--for yy
	return teamAmateur,teamPro
end

local function listOfManagedTeamTable(itemID, initialYear,finalYear)
	local managedTeamRider, initialYear, finalYear = listofTeam(itemID, initialYear,finalYear,'P6087')--raw list of team
	if not managedTeamRider then
		return nil, nil
	end
	
	local natTeamOut, managedTeamOut=analyzeManagedTeam(managedTeamRider, initialYear,finalYear) --table with links and nature of teams
	local nationalTeam,_=synthetizeTable(natTeamOut, initialYear,finalYear)
	local _,managedTeam=synthetizeTable(managedTeamOut, initialYear,finalYear)
	
	return nationalTeam,managedTeam
end

local function listOfTeamTable(itemID, initialYear,finalYear)
	local teamRider, initialYear, finalYear = listofTeam(itemID, initialYear,finalYear,'P54')--raw list of team
	if not teamRider then
		return nil, nil
	end
	local analyzedTeam1=analyzeTeam(teamRider, initialYear,finalYear, "road") --table with links and nature of teams
	local teamAmateur,teamPro=synthetizeTable(analyzedTeam1, initialYear,finalYear) --table formated, global
	local analyzedTeam2=analyzeTeam(teamRider, initialYear,finalYear, "mountainBike")
    local _, teamMountainBike=synthetizeTable(analyzedTeam2, initialYear,finalYear)
    local analyzedTeam3=analyzeTeam(teamRider, initialYear,finalYear, "cycloCross")
	local _, teamCycloCross=synthetizeTable(analyzedTeam3, initialYear,finalYear)
	local analyzedTeam4=analyzeTeam(teamRider, initialYear,finalYear, "track")
	local _, teamTrack=synthetizeTable(analyzedTeam4, initialYear,finalYear)	
	
	return teamAmateur,teamPro, teamMountainBike, teamCycloCross, teamTrack
end	

local function getBirthDeathDate(entityID, display_age)
	local birthDate=firstValue(entityID, 'P569', 'time')
	local deathDate=firstValue(entityID, 'P570', 'time')
	local temp2, temp3, birth, death, initialYear, finalYear, age
	
	local gender=getGenderCode(entityID, 'm')
	local w_race=false
	if gender=="f" then w_race=true end

	if birthDate then
		local birthDateFormatted= funcDate(birthDate, 'long')
		age, initialYear, finalYear=calculateAge(birthDate)
		local birthPlace = firstValue(entityID, 'P19', 'id')
		local birthPlaceLink=''
		if birthPlace then birthPlaceLink=getPlaceLink(birthPlace, birthDate) end

	    local plural, gen_singular, gen_plural = plural(age)
	    local ans
	    if gen_singular then
	    	ans=translate("riderinfobox",48,w_race)
	    elseif gen_plural then
	    	ans=translate("riderinfobox",49,w_race)
	    else
	    	ans=translate("riderinfobox",50,w_race)
	    end

		if not deathDate and display_age~=false then
			temp2=' ('..tostring(age)..' '..ans..')<br/>'
		else
			temp2='<br/>'
		end
    	birth=birthDateFormatted..temp2..birthPlaceLink
	else
	    birth=nil
	end
	
	if deathDate then
		local deathDateFormatted= funcDate(deathDate, 'long')
		local deathPlace= firstValue(entityID, 'P20', 'id')
		local deathPlaceLink=''
		if deathPlace then deathPlaceLink=getPlaceLink(deathPlace, deathDate) end
		
		if birthDate then
		    local age=calculateAge(birthDate, deathDate)
		    local plural, gen_singular, gen_plural = plural(age)
		    local ans
		    if gen_singular then
		    	ans=translate("riderinfobox",48,w_race)
		    elseif gen_plural then
		    	ans=translate("riderinfobox",49,w_race)
		    else
		    	ans=translate("riderinfobox",50,w_race)
		    end
		    if display_age==false then
		    	temp2='<br/>'
		    else
				temp2=' ('..tostring(age)..' '..ans..')<br/>'
			end
		else
			temp2='<br/>'
		end

		death=deathDateFormatted..temp2..deathPlaceLink
	else
	    death=nil
	end

	return birth, death, initialYear, finalYear
end

local function presentTeam(itemID)
	local tToday=os.date("*t")  
	if mw.ustring.len(tToday["month"])==1 then tToday["month"]='0'..tToday["month"] end
	if mw.ustring.len(tToday["day"])==1 then tToday["day"]='0'..tToday["day"] end	
	local today='+'..tToday["year"].."-"..tToday["month"].."-"..tToday["day"].."T00:00:00Z"
	local plural=false
    local teamId, result, teamLink, teamLinkRoad, row

	for _, s in statements(itemID, 'P54') do
		p54 =checktime(s, s.qualifiers, today) --present Team
		if p54 then
			teamId= p54.mainsnak.datavalue.value.id
			teamLink=getTeamLinkCat(teamId, today)
		    dis=checkDis(p54.qualifiers)
		    row=nil
		    if dis=='road' then
		    	teamLinkRoad=teamLink
		    elseif dis=='mountainBike' then
		    	row=teamLink..' ('..translate("riderinfobox",56,w_race)..')'
		    elseif dis=='cycloCross' then
		    	row=teamLink..' ('..translate("riderinfobox",57,w_race)..')'
		    else 
		    	row=teamLink..' ('..translate("riderinfobox",58,w_race)..')'
		    end
		    if row then
			    if not result then
			    	result = row
			    else
			    	result= result..'<br/>'..row
			    	plural = true
			    end
		    end
		end
	end
	if teamLinkRoad and result then --put road first
		result = teamLinkRoad..' (route)<br/>'..result
		plural= true
	elseif teamLinkRoad then
		result = teamLinkRoad
	end
	return result, plural
end

local function getSomeNames(details,entityID, PID, index, display_language)
	local rows={}
	if not details[index].content then
		local listOfNames=getFormerNames(entityID, PID)
		if listOfNames then
			for _, v in pairs(listOfNames) do
				rows[#rows + 1]=v[3]
				if v[2] and v[2]~='' then
					rows[#rows]=rows[#rows]..' <small>('..v[2]..')</small>'
				end
				if display_language then
					rows[#rows]=rows[#rows]..' <b><small>('..v[4]..')</small></b>'
				end
			end
			if #rows>0 then
				details[index].content = table.concat(rows, '<br/>') 
			end
		end
	end
end

--for wikidata input
local function teamTable(tab, teamAmateur, title_singular, title_plural)
	if teamAmateur and #teamAmateur>0 then
		if #teamAmateur==1 then
			tab:node(addATitle(title_singular)) 
		else
			tab:node(addATitle(title_plural)) 
		end
		for _, v in pairs(teamAmateur) do 
			local nametemp=v['link']
			if v['sDate']==v['eDate'] then
				periodtemp=v['sDate']
			else
				periodtemp=v['sDate']..'-'..v['eDate']
			end
			if v['stagiaire'] then
				local stagiaire = string.gsub(getLabelFallback('Q2328847',lang_priority), "%b()", "")
				nametemp=nametemp..' ('..stagiaire..')'
			end
			tab:node(addARow(periodtemp or '',nametemp)) --period, name
		end
	end
end

--for local data
local function localTeamTable(tab, names, periods, title_singular, title_plural)
	if names then
		names =  mw.text.split(names, '<br />')
		periods = mw.text.split(periods or '', '<br />')
	
		if #names==1 then
			tab:node(addATitle(title_singular)) 
		else
			tab:node(addATitle(title_plural)) 
		end
		for i, name in pairs(names) do
			tab:node(addARow(periods[i] or '', name))
		end
	end
end	

function p.riderinfobox(frame)
	local WDlink_on = (wiki == "mk" or wiki == "ja")
	local entityID, lf = get_and_checkID(frame)

	local gender=getGenderCode(entityID, 'm')
	local w_race=false
	if gender=="f" then w_race=true end

	local details = {
		{ name = translate("riderinfobox",1,w_race), name_plural =translate("riderinfobox",2,w_race)}, -- birth name
		{ name = translate("riderinfobox",3,w_race), name_plural =translate("riderinfobox",4,w_race)}, -- nick name
		{ name = translate("riderinfobox",5,w_race), name_plural =translate("riderinfobox",6,w_race)}, -- official name
		{ name = translate("riderinfobox",7,w_race), name_plural =translate("riderinfobox",8,w_race)}, -- official name
		{ name = translate("riderinfobox",9,w_race) }, -- birth translate("riderinfobox",9)
		{ name = translate("riderinfobox",10,w_race)}, -- death
		{ name = translate("riderinfobox",11,w_race), name_plural =translate("riderinfobox",12,w_race)}, -- country
		{ name = translate("riderinfobox",13,w_race), name_plural =translate("riderinfobox",14,w_race)}, -- present team
		{ name = translate("riderinfobox",15,w_race), name_plural =translate("riderinfobox",16,w_race)}, -- speciality
		{ name = translate("riderinfobox",17,w_race) }, -- lateralisation
		{ name = translate("riderinfobox",18,w_race) }, -- blood group
		{ name = translate("riderinfobox",19,w_race) },  -- height
		{ name = translate("riderinfobox",20,w_race) }, -- weight
		{ name = translate("riderinfobox",21,w_race), name_plural =translate("riderinfobox",22,w_race)}, -- awards
	}
	
	local teams = {
		{ name = translate("riderinfobox",23,w_race), name_plural =translate("riderinfobox",24,w_race)}, -- directed teams
		{ name = translate("riderinfobox",25,w_race)}, -- directed years
		{ name =  translate("riderinfobox",26,w_race), name_plural =translate("riderinfobox",27,w_race)}, -- amateur names  
		{ name = translate("riderinfobox",28,w_race)}, -- amateur periods
		{ name = translate("riderinfobox",29,w_race), name_plural =translate("riderinfobox",30,w_race)}, -- nonUCI names
		{ name = translate("riderinfobox",31,w_race)}, -- nonUCI periods
		{ name = translate("riderinfobox",32,w_race), name_plural =translate("riderinfobox",33,w_race)}, -- pro names
		{ name = translate("riderinfobox",34,w_race)}, -- pro periods
		{ name = translate("riderinfobox",35,w_race), name_plural =translate("riderinfobox",36,w_race)}, -- UCI names
		{ name = translate("riderinfobox",37,w_race)}, -- UCI periods
		{ name = translate("riderinfobox",52,w_race), name_plural =translate("riderinfobox",53,w_race)}, -- national selections
		{ name = translate("riderinfobox",54,w_race)}, -- national selection years
		}

    --separated to have a title
	local subtitle = {
		{ name = translate("riderinfobox",51,w_race)}, -- insertion of a sub-title
	}
	
    --separated to have a title
	local victories = {
		{ name = translate("riderinfobox",38,w_race)}, -- main victories
	}
	
	--separated to have a title
	local medals = {
		{ name = translate("riderinfobox",47,w_race)}, -- main victories
	}
	local others = get_others_dic()

	local name =  getLabelFallback(entityID) or ''

	local display_birthnameastitle=false
	for _, value in pairs(display_birthnameastitle_in_riderinfobox) do -- get data if country should be printed in this wiki
		if value == wiki then display_birthnameastitle=true end
	end
	getLocalContent(subtitle, lf.args)
	
	if not subtitle[1].content and display_birthnameastitle then
		local p1477 = mw.wikibase.getBestStatements(entityID, "P1477") 
		if p1477[1] and p1477[1].mainsnak.snaktype == 'value' then
			subtitle[1].content = p1477[1].mainsnak.datavalue.value.text..' <b><small>('..
			p1477[1].mainsnak.datavalue.value.language..')</small></b>'
		end
		if not subtitle[1].content then
		    local p1559 = mw.wikibase.getBestStatements(entityID, "P1559") -- P580 is start time
			if p1559[1] and p1559[1].mainsnak.snaktype == 'value' then
				subtitle[1].content = p1559[1].mainsnak.datavalue.value.text..' <b><small>('..
			    p1559[1].mainsnak.datavalue.value.language..')</small></b>'
			end
		end
	end

	infoGetOthers(others, entityID)	

	getLocalContent(details, lf.args)
	getLocalContent(teams, lf.args)
	getLocalContent(others, lf.args)
    getLocalContent(victories, lf.args)
    getLocalContent(medals, lf.args)

	local listOfBirthNames, listOfNickNames, listOfOfficialNames, listOfShortNames
	
	local icon = picto_road

	local display_language=false
	for _, value in pairs(display_language_in_riderinfobox) do -- get data if country should be printed in this wiki
		if value == wiki then display_language=true end
	end
	
	local display_age=true
	for _, value in pairs(display_noage_in_riderinfobox) do -- get data if country should be printed in this wiki
		if value == wiki then display_age=false end
	end
	
	local display_nickname=true
	for _, value in pairs(display_nonickname_in_riderinfobox) do -- get data if country should be printed in this wiki
		if value == wiki then display_nickname=false end
	end	

	local display_cm=false
	for _, value in pairs(display_cm_in_riderinfobox) do -- get data if country should be printed in this wiki
		if value == wiki then display_cm=true end
	end	
--	getSomeNames(details, entityID, 'P1477', 1, display_language) --birthname
	--less prio than P1477
	if display_nickname then
		getSomeNames(details, entityID, 'P1559', 1, display_language) --birthname, bis
		getSomeNames(details, entityID, 'P1449', 2, display_language) --nick name
	end
	
	getSomeNames(details, entityID, 'P1448', 3, display_language) --official name
	
	if display_nickname then
		getSomeNames(details, entityID, 'P1813', 4, display_language) --short name
	end

	local birth, death, initialYear, finalYear=getBirthDeathDate(entityID, display_age)
	
	if not details[5].content then
		details[5].content=birth
	end
	if not details[6].content then
		details[6].content= death
	end	

	local display_flag=false
	for _, value in pairs(display_flag_in_riderinfobox) do -- get data if country should be printed in this wiki
		if value == wiki then display_flag=true end
	end

	listWPlinkChrono(details, 7, entityID, {'P1532','P27'}, 'country', initialYear, display_flag)

	if not details[8].content then
		local plural
		details[8].content, plural=presentTeam(entityID)
		if plural then
			details[8].name = details[8].name_plural
		end
	end

	--speciality
	listWPlink(details, 9, entityID, 'P413',false)

	--lateralisation, for cycling not very interesting
	--listWPlink(details, 10, entityID, 'P552',false)

	--blood group, idem
	--listWPlink(details, 11, entityID, 'P1853',false)

	--height
	if not details[12].content then
		details[12].content=getHeight(entityID, display_cm) 
	end

	local display_weight=true
	for _, value in pairs(display_noweight_in_riderinfobox) do -- get data if country should be printed in this wiki
		if value == wiki then display_weight=false end
	end
	--weight
	if not details[13].content and  display_weight then
		details[13].content=getWeight(entityID)
	end	

	--award, should be table
	--awards look weird
	--if not details[14].content then
	--	listWPlink(details, 14, entityID, 'P166',false)
	--end

	local amateurTeam, nonUCITeam, proTeam, UCITeam --local data
	local amateurWD=true
	local proWD=true
	local managedWD=true

	local teamAmateur,teamPro, teamMountainBike, teamCycloCross, teamTrack=listOfTeamTable(entityID, initialYear, finalYear)
	local nationalTeam, managedTeam=listOfManagedTeamTable(entityID, initialYear, finalYear)
	local managedTeam_names, managedTeam_periods, amateurTeam_names, amateurTeam_periods
	local nonUCITeam_names, nonUCITeam_periods, proTeam_names, proTeam_periods
	local nationalTeam_names, nationalTeam_periods
	local UCITeam_names, UCITeam_periods

	if teams[1].content then
		managedTeam_names=teams[1].content
		managedTeam_periods=teams[2].content
		managedWD=false
	end

	if teams[3].content then
		amateurWD=false
		amateurTeam_names=teams[3].content
		amateurTeam_periods=teams[4].content
	end
			
	if teams[5].content then 
		amateurWD=false
		nonUCITeam_names=teams[5].content
		nonUCITeam_periods=teams[6].content
	end

	if teams[7].content then
		proWD=false
		proTeam_names=teams[7].content
		proTeam_periods=teams[8].content
	end
	
	if teams[9].content then
		proWD=false
		UCITeam_names=teams[9].content
		UCITeam_periods=teams[10].content
	end	
	
	if teams[11].content then
		nationalTeam_names=teams[11].content
		nationalTeam_periods=teams[12].content
		managedWD=false
	end

	--plate and grab
	tab = infoInitTab("300px", name, icon, 2)
	if subtitle[1].content then
	    tCell=tab:tag('tr'):tag('td'):attr('colspan','2')
		:cssText('solid white; text-align:center')
		:wikitext(subtitle[1].content)
	end

	infoFillOthersDetails(tab, others, details,translate("riderinfobox",55,w_race),"260px")
	if amateurWD then
		teamTable(tab, teamAmateur, translate("riderinfobox",26,w_race), translate("riderinfobox",27,w_race))
	else
	 	localTeamTable(tab,amateurTeam_names, amateurTeam_periods, translate("riderinfobox",26,w_race), translate("riderinfobox",27,w_race))
		localTeamTable(tab,nonUCITeam_names, nonUCITeam_periods, translate("riderinfobox",29,w_race), translate("riderinfobox",30,w_race))
	end
	
	if proWD then
		teamTable(tab, teamPro, translate("riderinfobox",45,w_race),translate("riderinfobox",46,w_race))
		teamTable(tab, teamMountainBike, translate("riderinfobox",39,w_race), translate("riderinfobox",40,w_race))
		teamTable(tab, teamCycloCross, translate("riderinfobox",41,w_race), translate("riderinfobox",42,w_race))
		teamTable(tab, teamTrack, translate("riderinfobox",43,w_race), translate("riderinfobox",44,w_race))
	else
		localTeamTable(tab,proTeam_names, proTeam_periods,translate("riderinfobox",45,w_race), translate("riderinfobox",46,w_race))
		localTeamTable(tab,UCITeam_names, UCITeam_periods, translate("riderinfobox",35,w_race), translate("riderinfobox",36,w_race))
	end

	--managed teams
	if managedWD then
		teamTable(tab, nationalTeam, translate("riderinfobox",52,w_race), translate("riderinfobox",53,w_race))
		teamTable(tab, managedTeam, translate("riderinfobox",23,w_race), translate("riderinfobox",24,w_race))
	else
		localTeamTable(tab,managedTeam_names, managedTeam_periods,translate("riderinfobox",23,w_race), translate("riderinfobox",24,w_race))
	end
	
	if victories[1].content then
		tab:node(addATitle(translate("riderinfobox",38,w_race))) 
		tab:tag('tr'):tag('td')
		:css('vertical-align','top'):attr('colspan','2')
		:wikitext(victories[1].content)
	end
	
	if medals[1].content then
		tab:node(addATitle(translate("riderinfobox",47,w_race))) 
		tab:tag('tr'):tag('td')
		:css('vertical-align','top'):attr('colspan','2')
		:wikitext(medals[1].content)
	end
	wdDoc(tab, "d:Wikidata:WikiProject Cycling/Documentation/riderinfobox", translate("raceinfobox",26,w_race), entityID)
	return tab
end

--=== P) Team infobox
local function get_rider_number(entityID, details, index)
	if not details[index].content then
		local riders = #wikibase.getAllStatements(entityID, 'P527') -- P527 is 'has part'
		if riders > 0 then
			local stagiaire = string.gsub(getLabelFallback('Q2328847'), "%b()", "")
			local nb_stagiaires=0
			for ii, p527 in statements(entityID, 'P527') do
				local q = p527.qualifiers
				if q and q.P39 and q.P39[1] and	q.P39[1].snaktype == 'value' and
				   q.P39[1].datavalue.value=='Q2328847'then
				   nb_stagiaires=nb_stagiaires+1
				end
			end
		    if nb_stagiaires>0 then
				details[index].content = riders ..' ('.. tostring(nb_stagiaires).." "..stagiaire..')'
			else
				details[index].content = riders
			end
		end	
	end
end

function p.teamseasoninfobox(frame)
	local WDlink_on = (wiki == "mk" or wiki == "ja")
	local seasonID, lf = get_and_checkID(frame)
	
	local w_race=isWomenteam(seasonID)
	local gender="m"
	if w_race then gender="f" end

	local details = {
		{ name = translate("teaminfobox",2,w_race)}, -- sport
		{ name = translate("headoftableII",3,w_race)}, -- team
		{ name = translate("teaminfobox",3,w_race), name_plural = translate("teaminfobox",4,w_race)}, -- type 	
		{ name = translate("teaminfobox",5,w_race), name_plural = translate("teaminfobox",6,w_race)}, -- UCI-cod
		{ name = translate("teaminfobox",7,w_race), name_plural = translate("teaminfobox",8,w_race)}, -- сountry
		{ name = translate("getSquadTableColumn",7,w_race)}, --team size
		{ name = translate("teaminfobox",13,w_race)}, -- official web site
		{ name = translate("teaminfobox",27,w_race), name_plural = translate("teaminfobox",28,w_race)},  --sponsor
		{ name = translate("teaminfobox",24,w_race), name_plural = translate("teaminfobox",25,w_race) }, -- bike
		{ name = translate("teaminfobox",26,w_race)}, -- budget
	}	

	local managers ={
		{ name = translate("teaminfobox",14,w_race), name_plural = translate("teaminfobox",15,w_race)}, -- manager													--country
		{ name = translate("teaminfobox",16,w_race), name_plural = translate("teaminfobox",17,w_race)}, -- sports director
	}

	local others=get_others_dic()

	infoGetOthers(others, seasonID)
	getLocalContent(details, lf.args)
	getLocalContent(others, lf.args)
	
	local sport_id=firstValue(seasonID, 'P641', 'id')
	local icon = (sport_id == "Q3609") and -- P641 is 'sport', Q3609 is 'road bicycle racing'
		picto_road or ''
	local name =  getLabelFallback(seasonID) or ''
	local listOfNames=getFormerNames(seasonID, 'P1448',true)
	--1st ist sport
	if not details[1].content and sport_id then
		details[1].content = WPlinkpure(sport_id)
	end
	
	local timeOfRace=getTimeOfRace(seasonID)
	local initialYear
	if timeOfRace then
		initialYear=string.sub(timeOfRace,2,5)
	else
		error("no timeOfRace found for "..seasonID)
	end
    local sitelink, catID, _=getTeamLinkCat(seasonID, timeOfRace, nil, true)
    --team
	if not details[2].content then 
		details[2].content=sitelink
	end

	--type
	listWPlinkChrono(details, 3, seasonID, {'P2094'}, 'rider', initialYear, nil, nil, true)
	
	if not details[3].content then --fallback
	    if catID then
	    	details[3].content=getRiderLink(catID, timeOfRace) --it is not a rider, but it gives the correct result
	    end
	end	
	
	listWPlinkChrono(details, 4, seasonID, {'P1998'}, 'UCIcode', initialYear, nil, true,true)

	local display_flag=true					
	listWPlinkChrono(details, 5, seasonID, {'P1532','P17'}, 'country', initialYear, display_flag,nil,true)

	-- number of riders
	get_rider_number(seasonID, details, 6)

	-- official site
	if not details[7].content then
		details[7].content = officialSite(seasonID)
	end
	--Sponsor
	listWPlinkChrono(details, 8, seasonID, {'P859'}, 'rider', initialYear, nil, nil, true)
	
	--bike
	listWPlinkChrono(details, 9, seasonID, {'P1876'}, 'rider', initialYear, nil, nil, true)

	--budget
	if not details[10].content then
		p=firstValue(seasonID,'P2769')
		if p and p.mainsnak.snaktype == 'value' then
			local amount=p.mainsnak.datavalue.value.amount
			local unit=p.mainsnak.datavalue.value.unit
			details[10].content=dispmoney(amount, unit)
		end
	end
	
	local listofcalendar, UCIQtoYear=riderranking_sub(w_race)

	local tTable={} --no need for year, it is clear
	for _, calendar  in pairs(listofcalendar) do
		tTable[calendar]={}
	end
	--not over-writable presently
	tTable=get_teamranking(seasonID, w_race, UCIQtoYear,listofcalendar, tTable,gender)

	--Staff, there can be several
	-- manager
	listWPlinkChrono(managers, 1, seasonID, {'P505'}, 'rider', initialYear, nil, nil, true)

	-- sports director
	listWPlinkChrono(managers, 2, seasonID, {'P286'}, 'rider', initialYear, nil, nil, true)
	
	--Build the table
	tab = infoInitTab("300px", name, icon, 2)
	infoFillOthersDetails(tab, others, details, translate("teaminfobox",1,w_race))
	
	--in case there are several names
	if listOfNames and #listOfNames>1 then --Always display a list of names
		tab:node(addATitle(translate("teaminfobox",19,w_race))) 
		for _, v in pairs(listOfNames) do
			tab:node(addARow(v[2],v[3])) --period, name
		end
	end
	
	if managers[1].content or managers[2].content then
		tab:node(addATitle(translate("teaminfobox",18,w_race)))
		for _, row in ipairs(managers) do
	    	tab:node(addARow(row.name, row.content)) --node check itself if nil
		end
	end
	--Palmares
	tab:node(addATitle(translate("raceinfobox",20,w_race)))
	local wins = #wikibase.getAllStatements(seasonID, 'P2522') 
	if wins then
		tab:node(addARow(translate("victories",2,w_race),tostring(wins)))
	end

	for calendar, v_calendar in pairs(tTable) do
		if v_calendar[initialYear] then
			local v=v_calendar[initialYear]
			local calendar_name=translate("riderranking",KeytoRiderRankingCode[calendar],w_race)
			if v["sitelink"] then
				tab:node(addATitle('[['..v["sitelink"]..'|'..calendar_name..']]'))
			else
				tab:node(addATitle(calendar_name))
			end
			
			if v["teamrank"] then
				tab:node(addARow(translate("riderranking",20,w_race),v["teamrank"]))
			end
			if v["rider"] then
				tab:node(addARow(translate("riderranking",21,w_race),v["rider"]))
			end
		end
	end

-- an empty line with a title under the form in the form of an image or third-party template
	if get_arg('jersey',lf) then -- if the jersey is not specified, then the JERSEY header is not displayed 
		tab:node(addATitle(translate("teaminfobox",20,w_race)))
	    local outTable = mw.html.create('tr')
		local tCell=outTable:tag('td'):attr('colspan','3'):css('text-align','center')		    
		tCell:wikitext(get_arg('jersey',lf)) -- adding a form via "argument 2" by an image or an extraneous template 
		tab:node(outTable)
	end		

-- adding a link to articles about the last and current seasons (the same as for the race) 	
	tab:node(getPreviousNextLine(seasonID))
	wdDoc(tab, "d:Wikidata:WikiProject Cycling/Documentation/raceinfobox", translate("raceinfobox",26,w_race), seasonID)
	return tab	
end

function p.teaminfobox(frame)
	-- If true, winners will have Wikidata logos with link to Wikidata
	local WDlink_on = (wiki == "mk" or wiki == "ja")
	
	local entityID, lf = get_and_checkID(frame)
	local w_race=isWomenrace(entityID)
	
	local tRace = {race={
			raceId,
			raceDate,
			future,
			}, 
		  }
	
	local details = {
		{ name = translate("teaminfobox",2,w_race)}, -- sport
		{ name = translate("teaminfobox",3,w_race), name_plural = translate("teaminfobox",4,w_race)}, -- type 	
		{ name = translate("teaminfobox",5,w_race), name_plural = translate("teaminfobox",6,w_race)}, -- UCI-cod
		{ name = translate("teaminfobox",7,w_race), name_plural = translate("teaminfobox",8,w_race)}, -- сountry
		{ name = translate("teaminfobox",9,w_race)}, -- creation date
		{ name = translate("teaminfobox",10,w_race)}, -- disparition date
		{ name = translate("teaminfobox",11,w_race)}, -- number of season
		{ name = translate("teaminfobox",13,w_race)}, -- official web site
		{ name = translate("teaminfobox",27,w_race), name_plural = translate("teaminfobox",28,w_race)},  --sponsor
		{ name = translate("teaminfobox",24,w_race), name_plural = translate("teaminfobox",25,w_race) }, -- bike
		{ name = translate("teaminfobox",26,w_race)}, -- budget
	}
	
	local others=get_others_dic()
	local managers ={
		{ name = translate("teaminfobox",14,w_race), name_plural = translate("teaminfobox",15,w_race)}, -- manager													--country
		{ name = translate("teaminfobox",16,w_race), name_plural = translate("teaminfobox",17,w_race)}, -- sports director
	}
	
	local managers_season ={
		{ name = translate("teaminfobox",14,w_race), name_plural = translate("teaminfobox",15,w_race)}, -- manager													--country
		{ name = translate("teaminfobox",16,w_race), name_plural = translate("teaminfobox",17,w_race)}, -- sports director
	}
	
	local details_season = {
		{ name = translate("getSquadTableColumn",7,w_race)}, --team size
		{ name = translate("victories",2,w_race)} --number of victories
	}

	local name =  getLabelFallback(entityID,  lang_priority) or ''
	infoGetOthers(others, entityID)	
	
	getLocalContent(details, lf.args)
	getLocalContent(others, lf.args)
	getLocalContent(managers, lf.args)
	
    local listOfNames=getFormerNames(entityID, 'P1448')
	
	local sport_id=firstValue(entityID, 'P641', 'id')
	local icon = (sport_id == "Q3609") and -- P641 is 'sport', Q3609 is 'road bicycle racing'
		picto_road or ''

	--1st ist sport
	if not details[1].content and sport_id then
		details[1].content = WPlinkpure(sport_id)
	end
	
	local creation=firstValue(entityID, 'P571', 'time')
	local initialYear=string.sub(creation,2,5)
	
	-- type 
	listWPlinkChrono(details, 2, entityID, {'P31'}, 'rider', initialYear)--it is not a rider, but we need link + official name
	
	--UCI code
	listWPlinkChrono(details, 3, entityID, {'P1998'}, 'UCIcode', initialYear, nil, true)

	-- сountry
	local display_flag=true					
	listWPlinkChrono(details, 4, entityID, {'P1532','P17'}, 'country', initialYear, display_flag)

	--creation date
	if not details[5].content and creation then
		details[5].content = funcDate(creation, "onlyyear" )
	end

	-- disparition date
	local disparition=firstValue(entityID, 'P576', 'time')
	if not details[6].content and disparition then
		details[6].content =  funcDate(disparition,"onlyyear")
	end

	--populate tRace
	listOfWinners(entityID, tRace,true,lf)
	
	-- number of season
	if not details[7].content and tRace.numberOfEditions and tRace.lastEditionYear then
		details[7].content = tostring(tRace.numberOfEditions).." (" .. translate("teaminfobox",12,w_race) .. " "..tostring(tRace.lastEditionYear)..")"
	end

	-- official site
	if not details[8].content then
		details[8].content = officialSite(entityID)
	end
	
	--9 is sponsor
	listWPlinkChrono(details, 9, entityID, {'P859'}, 'rider', initialYear)
	
	--10 is bike 
	listWPlinkChrono(details, 10, entityID, {'P1876'}, 'rider', initialYear)
	--11 budget
	listWPlinkChrono(details, 11, entityID, {'P2769'}, 'money', initialYear)

	-- manager
	listWPlinkChrono(managers, 1, entityID, {'P505'}, 'rider', initialYear)

	-- sports director
	listWPlinkChrono(managers, 2, entityID, {'P286'}, 'rider', initialYear)

	--Build the table
	tab = infoInitTab("300px", name, icon, 2)
	--former names
	wiki_listOfNamesAtBottom={'ru'}
	
	local listOfNamesAtBottom = false
	for _, value in pairs(wiki_listOfNamesAtBottom) do -- 
		if value == wiki then listOfNamesAtBottom = true end
	end
	--picture at the top
	infoFillOthersDetails(tab, others, details, translate("teaminfobox",1,w_race),"260px")

	if managers[1].content or managers[2].content then
		tab:node(addATitle(translate("teaminfobox",18,w_race)))
		for _, row in ipairs(managers) do
	    	tab:node(addARow(row.name, row.content)) --node check itself if nil
		end
	end
	
	if listOfNames and #listOfNames>0 then --Always display a list of names
		tab:node(addATitle(translate("teaminfobox",19,w_race))) 
		for _, v in pairs(listOfNames) do
			tab:node(addARow(v[2],v[3])) --period, name
		end
	end

-- an empty line with a title under the form in the form of an image or third-party template
	if get_arg(2,lf) then -- if the jersey is not specified, then the JERSEY header is not displayed 
		tab:node(addATitle(translate("teaminfobox",20,w_race)))
	    local outTable = mw.html.create('tr')
		local tCell=outTable:tag('td'):attr('colspan','3'):css('text-align','center')		    
		tCell:wikitext(get_arg(2,lf)) -- adding a form via "argument 2" by an image or an extraneous template 
		tab:node(outTable)
	end		

-- adding a link to articles about the last and current seasons (the same as for the race) 	
	if tRace.lastID then
		-- manager
		listWPlinkChrono(managers_season, 1, tRace.lastID, {'P505'}, 'rider', tRace.lastEditionYear, nil, nil, true)
		-- sports director
		listWPlinkChrono(managers_season, 2, tRace.lastID, {'P286'}, 'rider', tRace.lastEditionYear, nil, nil, true)
		
		get_rider_number(tRace.lastID, details_season, 1)

		local wins = #wikibase.getAllStatements(tRace.lastID, 'P2522') 
		local today=os.date("*t") 
		if wins and tonumber(tRace.lastEditionYear)==tonumber(today['year']) then --display only if the season if for this year
			details_season[2].content=tostring(wins)
		end
		
		infoFillOthersDetails(tab, nil, managers_season, translate("teaminfobox",21,w_race),"260px")
		infoFillOthersDetails(tab, nil, details_season, nil,"260px")
		
		local outTable 
		if tRace.lastLink then
		    outTable = mw.html.create('tr')
			local tCell=outTable:tag('td'):attr('colspan','2'):css('text-align','center')
			local lastText="[[File:Crystal Clear app kworldclock.png|left|37px]]"..
			translate("teaminfobox",22,w_race)..
			":<br>'''"..
			tRace.lastLink.."'''"
			tCell:wikitext(lastText)
			tab:node(outTable)
		end	
		
		if tRace.nextLink then
			outTable = mw.html.create('tr')
			local tCell=outTable:tag('td'):attr('colspan','2'):css('text-align','center')
		    local nextText = "[[File:Crystal Clear app kworldclock.png|left|37px]]"..
		    translate("teaminfobox",23,w_race)..
		    ":<br>'''"..
		    tRace.nextLink.."'''"
			tCell:cssText("text-align:center"):wikitext(nextText)
			tab:node(outTable)
		end
	end	

	wdDoc(tab, "d:Wikidata:WikiProject Cycling/Documentation/raceinfobox", translate("raceinfobox",26,w_race), entityID)
	return tab
end

--== teamriderCompetitionranking
function p.teamriderCompetitionranking(frame)
	local tempID, lf=get_and_checkID(frame)
	local calendarID
	
	local timeOfRace=getTimeOfRace(tempID)
	local initialYear
	if timeOfRace then
		year=string.sub(timeOfRace,2,5)
	end

	local header_1_tab = {["UWT"]=13 ,["europe"]=14 ,["asia"]=15,["america"]=16 ,["africa"]=17 ,["oceania"]=18, ["WWT"]=11, ["women"]=1, ["Pro"]=22}
	local header_1_number = 12
	local key=get_arg(2,frame)
	
	if key and year then
		calendarID=data.UCIYearToQ[key][year]
		header_1_number = header_1_tab[key]
	end
	local w_race=isWomenteam(calendarID)
	if not calendarID or calendarID == "" then return "" end

	local s = {
		header_function = "calendar", 
		header_1 =header_1_number, 
		header_2 = {2, 3, 5, 4, 24, 23},
		data_sort_type = {'', '','', 'unsortable', '', ''},
		property="P1344",
		calendarID=calendarID,
		item = tempID, --should be called item for tableA
		lf=lf,
		w_race=w_race
	}
	return teamriderCompetitionranking_main(s,tableA(s))	
end

local function get_competition_bestrider(RaceID, seasonID, gender)
	local riderLink, rank, disqualified, cancelled, q 
	local bold=false

	for _, p1344 in statements(seasonID, 'P1344') do 
		thisCompetition = p1344.mainsnak.datavalue.value.id
		if thisCompetition and thisCompetition==RaceID then
			q = p1344.qualifiers
			if q then
				if q and q.P1352 and q.P1352[1].snaktype == 'value' then --rank
					rank= tonumber(q.P1352[1].datavalue.value.amount) 
					if rank==1 then
						bold=true
					end
					rank=number(gender,rank,wiki)
				end
				--get best rider
				if q and q.P710 and q.P710[1].snaktype == 'value' then --participant
					rider = q.P710[1].datavalue.value.id
					riderLink = getRiderLink(rider, thisdate)
					countryID = getNationality(rider, thisdate)
					if countryID then
						riderLink = flag(countryID, thisdate) .. ' ' .. riderLink
					end
				end		
				_,disqualified=isdisqualified(p1344, q)
				if riderLink and disqualified==true then
					riderLink='<s>'..riderLink..'</s>'
				end
			end
		end
	end
	return riderLink, rank, bold
end

function teamriderCompetitionranking_main(s, resultTable)--Display the UCI women calendar of one year
	local best_rider, rank
	local lf = s.lf
	local calendarID=s.calendarID
	local seasonID= s.item
	local t_Body ={}
	local w_race=s.w_race
	local gender="m"
	if w_race then gender="f" end

	local temp=firstValue(calendarID, s.property)
	if not temp or temp=="" then 
		s.error_message = 2 
		if wiki == "ar" then return "" end
	end
	local country=getCountryBool(s.no_country)

	----- Begin of the main part of the code
	local ind=0
	for _, p527 in statements(calendarID, 'P527') do
		local RaceID = p527.mainsnak.datavalue.value.id
		
		local temp=firstValue(RaceID, 'P1346','id')
		local cancelled=false
		if temp and temp=='Q30108381' or temp=='Q54806642' or temp=='Q23023872' then --race cancelled
			cancelled=true
		else
			ind=ind+1
		end
		if not cancelled then
			---- Create a row ----
			local timeOfRace, date_tCell, date_sortkey = fn_date(RaceID)
			local future=compareDate(timeOfRace)
			local parentID, race_tCell, _= fn_race(RaceID,nil,false,timeOfRace,nil,country)
	
			if race_tCell~=nil then --otherwise the class is not display
				local country_flag, country_name, country_tCell=fn_country(RaceID, timeOfRace, country, race_tCell, parentID) 
				--create the table
				local tRow = mw.html.create('tr'):cssText( "line-height: 1.8em; padding: 5px;")
				tRow:node(date_tCell)
				tRow:tag('td'):cssText("text-align:center;padding:0 0.5em"):wikitext(tostring(ind)) --correct only if the races are sorted correctly in wikidata
				tRow:node(country_tCell)
				if country then	tRow:node(race_tCell) end
	
				--logic to get the best rider||ranking
				riderLink, rank, bold=get_competition_bestrider(RaceID, seasonID, gender)
				local tCell=tRow:tag('td'):cssText("text-align:".. textalign ..";padding:0 0.5em")
				if riderLink then
					tCell:wikitext(riderLink)
				elseif future then
					tCell:wikitext("")
				else
					tCell:wikitext(" - ")
				end
				tCell=tRow:tag('td'):cssText("text-align:".. textalign ..";padding:0 0.5em")
				if bold then
					tCell:cssText("font-weight:bold;")
				end
				if rank then
					tCell:wikitext(rank)
				elseif future then
					tCell:wikitext("")			
				else
					tCell:wikitext(" - ")
				end
				---- Add the row to the table
				table.insert(t_Body, {sortkey=date_sortkey, body=tRow})
			end
		end 
	end
	return sortAndConcat(t_Body, resultTable)
end

--=== Z) Miscellaneous / Other / Tests 
--[[ Give access to a local variable. Used by other modules. ]]
function p.getLocal(name)
	if name == 'getTeamLinkCat' then return getTeamLinkCat end
	if name == 'getStatementForTime' then return getStatementForTime end
end

function p.testlocal(frame) --function to test local functions
	local function_name=frame.args[1]
	local argu=frame.args
	local temp, temp2

	if function_name=='firstValue' then
		return firstValue(argu[2],argu[3],argu[4])
	elseif function_name=='getOfficialName' then
		temp, temp2 =getOfficialName(argu[2],argu[3],argu[4])
		return temp
	elseif function_name=='getRiderLink' then
		if argu[3]=="nil" then arg3=nil else arg3=argu[3] end
		temp=getRiderLink(argu[2],arg3) --only first arg returned
		return temp
	elseif function_name=='funcDate' then
		return funcDate(argu[2],argu[3])
	elseif function_name=='funcDateFigure' then
		return funcDateFigure(argu[2],argu[3])		
	elseif function_name=='getStartEndTime1' then	
		temp, temp2=getStartEndTime(argu[2],argu[3],argu[4])
		return temp
	elseif function_name=='getStartEndTime2' then	
		temp, temp2=getStartEndTime(argu[2],argu[3],argu[4])
		return temp2
	elseif function_name=='getPeriodSub' then
		temp, temp2=getPeriodSub(argu[2],argu[3],toboolean(argu[4]))
		return temp
	elseif function_name=='getTeam' then
		temp=getTeam(argu[2],argu[3],argu[4])
		if temp then return temp else return 'nil' end
	elseif function_name=='getStatementForTime' then
		temp=getStatementForTime(argu[2],argu[3],argu[4])	
		if temp then
			return temp.mainsnak.datavalue.value.id
		else
			return 'nil'
		end
	elseif function_name=='getTeamLinkCat' then
		temp=getTeamLinkCat(argu[2],argu[3],toboolean(argu[4]))	
		if temp then return temp else return 'nil' end
	elseif function_name=='getTeamLinkCat2' then
		temp, temp2=getTeamLinkCat(argu[2],argu[3],toboolean(argu[4]))	
		if temp2 then return temp2 else return 'nil' end
	elseif function_name=='getPlaceLink' then 
		if argu[3]=="nil" then arg3=nil else arg3=argu[3] end
		return getPlaceLink(argu[2],arg3)
	elseif function_name=='getPlaceLink2' then 		
		return getPlaceLink(argu[2],argu[3],nil,true)
	elseif function_name=='seasonToTeamID' then
		if argu[2]=="nil" then arg2=nil else arg2=argu[2] end
		return tostring(seasonToTeamID(arg2))
	elseif function_name=='translate' then
		return translate(argu[2],tonumber(argu[3]),toboolean(argu[4]))
	elseif function_name=="classLinkFn" then
		return classLinkFn(argu[2])
	elseif function_name=='raceLink' then
		return tostring(raceLink(argu[2]))
	elseif function_name=='getMainRaceLink' then
		if argu[5]=="nil" then arg5=nil else arg5=argu[5] end
		if argu[3]=='stage' then arg3='stage' else arg3=tonumber(argu[3]) end
		return tostring(getMainRaceLink(argu[2],arg3,argu[4], arg5,argu[6]))
	elseif  function_name=='getYear' then
		return getYear(argu[2])
	elseif function_name=='getCountryName' then
		return tostring(getCountryName(argu[2]))
	elseif function_name=='getTeamCodeCat' then
		return tostring(getTeamCodeCat(argu[2],argu[3]))
	elseif function_name=='getTeamCode' then
		return tostring(getTeamCode(argu[2],argu[3],argu[4]))
	elseif function_name=='getCountryBool' then
		return tostring(getCountryBool({argu[2],argu[3]}))
	elseif function_name=='WPlinkpure' then
		return WPlinkpure(argu[2])
	elseif function_name=='uciCodeCountry' then
		return uciCodeCountry(argu[2])
	elseif function_name=='isHuman' then
		return tostring(isHuman(argu[2]))
	elseif function_name=='isCountry' then
		return tostring(isCountry(argu[2]))
	elseif function_name=='isWomenrace' then
		return tostring(isWomenrace(argu[2]))
	elseif function_name=='isWomenteam' then
		return tostring(isWomenteam(argu[2]))		
	elseif function_name=='commaStage' then
		temp =commaStage(argu[2],argu[3])
		return temp["prefix"]
	elseif function_name=='number' then
		return number(argu[2],tonumber(argu[3]), argu[4])
	elseif function_name=='classToCircuit' then
	    return classToCircuit(argu[2], argu[3], toboolean(argu[5]), nil) 
	elseif function_name=='getGenderCode' then
	    return tostring(getGenderCode(argu[2], argu[3]))
	elseif function_name=='calculateTime' then
		return calculateTime(argu[2])
	elseif function_name=='getClass1' then
		temp, temp2 = getClass(argu[2])
		return temp 
	elseif function_name=='getClass2' then
		temp, temp2 = getClass(argu[2])
		return temp2 	
	elseif function_name=='infoGetPlace' then
		local details = {{ name = "test", name_plural="tests"}} -- course / not used
		infoGetPlace(details,1, argu[2], argu[3], argu[4])
		return details[1].content
	elseif function_name=='getFormerNames1' then
		temp=getFormerNames(argu[2],'P1448')
		if temp[1] then
			return temp[1][2]  --period
		else
			return ""
		end
	elseif function_name=='getFormerNames2' then
		temp=getFormerNames(argu[2],'P1448')
		if temp[1] then
			return temp[1][3]  --name
		else
			return ""
		end
	elseif function_name=='getType' then
		return getType(argu[2])
	elseif function_name=='compareDate' then
		return tostring(compareDate(argu[2]))
	elseif function_name=='officialSite' then
		return officialSite(argu[2])
	elseif function_name=='trans' then
		return tostring(trans(argu[2], argu[3], argu[4]))
	elseif function_name=='parseDate1' then	
		temp1, temp2, temp3, temp4, temp5= parseDate(argu[2], argu[3], argu[4], argu[5], "", "error text")
		return temp1
	elseif function_name=='parseDate2' then	
		temp1, temp2, temp3, temp4, temp5= parseDate(argu[2], argu[3], argu[4], argu[5], "", "error text")
		return temp2
	elseif function_name=='parseDate5' then			
		temp1, temp2, temp3, temp4, temp5= parseDate(argu[2], argu[3], argu[4], argu[5], "", "error text")
		return temp5
	elseif function_name=='findLastName' then
		return findLastName(argu[2],wiki)
	elseif function_name=='findSortKey' then
		if wiki=="ru" or wiki=="mk" then
			return findSortKey(argu[2],false, true)
		else
			return findSortKey(argu[2],true, false)
		end
	elseif function_name=='calculateAge' then
		temp1, _, _ =calculateAge(argu[2])
		return temp1
	elseif function_name=='getBirthDeathDate1' then
	    temp1, temp2 =	getBirthDeathDate(argu[2])
		return temp1
	elseif function_name=='getBirthDeathDate2' then
		temp1, temp2 =	getBirthDeathDate(argu[2])
		return temp2	
	elseif function_name=='getLocalContent' then
		local details = {
	            	{ name = argu[2], name_plural= argu[3]}
	            }
		local arguments = {}
		arguments[argu[4]]="test"

		getLocalContent(details, arguments)
		return details[1].content
	elseif function_name=='plural1' then	
		_, temp1, temp2=plural(tonumber(argu[2]))
		return temp1
	elseif function_name=='plural2' then	
		_, temp1, temp2=plural(tonumber(argu[2]))
		return temp2
	elseif function_name=='getNationality' then
		return getNationality(argu[2], argu[3])
	elseif function_name=='getCountryID' then
		return getCountryID(argu[2], argu[3])
	elseif function_name=='get_formatted_date1' then
		if argu[3]=="nil" then arg3=nil else arg3=argu[3] end
		temp, temp2= get_formatted_date(argu[2], arg3)
		if temp then return temp end
	elseif function_name=='get_formatted_date2' then
		if argu[3]=="nil" then arg3=nil else arg3=argu[3] end
		temp, temp2= get_formatted_date(argu[2], arg3)
		if temp2 then return temp2 end
	elseif function_name=="getSpeed" then
		if argu[4]=="nil" then arg4=nil else arg4=tonumber(argu[4]) end
		return tostring(getSpeed(argu[2], toboolean(argu[3]),arg4, argu[5]))
	elseif function_name=="formatNumber" then
		return formatNumber(tonumber(argu[2]), toboolean(argu[3]),tonumber(argu[4]))
	end
end

function p.test_import(frame)
	local function_name=frame.args[1]
	local argu=frame.args

	if function_name=='class_dic' then
		return tostring(data.class_dic[argu[2]])
	elseif function_name=="class_sort" then
		return tostring(data.class_sort[argu[2]])
	elseif function_name=='bg_color_table' then	
		local temp = data.bg_color_table[argu[2]]
		temp=string.gsub(temp,'#',"")
		return temp
	end
end

return p