Module:Cycling race

La documentation pour ce module peut être créée à Module:Cycling race/Documentation

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
local localframe  -- Value may be given by functions which use frame functions like getReference
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
-- == 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 ==

--dictionnaries
local teamCats=data.teamCats
local class_sort=data.class_sort
local class_dic=data.class_dic
local UCI_Circuits=data.UCI_Circuits
local stages=data.stages
local bg_color_table = data.bg_color_table
local NationalRoadCyclingChampionships=data.NationalRoadCyclingChampionships
local NationalITTCyclingChampionships=data.NationalITTCyclingChampionships
local womenNcRoadtable=data.womenNcRoadtable
local womenNcITTtable=data.womenNcITTtable
local menNcRoadtable=data.menNcRoadtable
local menNcITTtable=data.menNcITTtable
local amateurcat=data.amateurcat
local nationalcat=data.nationalcat

local available, translations = pcall(require, "Module:Cycling race/lang")
local available_list = available and type(translations.list) == "function"
local available_lang_priority = available == true and type(translations.lang_priority) == "table"

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 no_country_calendar={'ru','ar'}
local no_country_victories={'ru','ar'}
local no_country_classification={'es','da','no','ru','ar'}
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 silver_theme_countries={'da'}

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="#EAECF0" 
		backgroundColorLight="#EFEFEF"
	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, womenrace_bool, title)
	if index == nil then index=1 end -- for prologue
	if index==1000 then --code for some custom function
		return title
	else
		if func_name_short then
			local func_name
			if womenrace_bool 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 
			return "error: no func_name found"
		end
	end
end

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

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 stageLink(x, a, b) -- x= 10a: a = 10, b = a. x = 5: a = 5, b = ""
	local l10nDef = {["fr"]="étape", ["en"]="stage", ["ar"]="المرحلة", ["br"]="Tennad", ["ca"]="etapa", ["cs"]="etapa", ["de"]="Etappe", ["da"]="etape", ["eo"]="Etapo",
	["es"]="etapa", ["eu"]="Etapa", ["fi"]="Etappi", ["fo"]="teinur", ["hu"]="szakasz", ["it"]="Tappa", ["ja"]="ステージ", ["la"]="Statio", ["lb"]="Etapp",
	["lv"]="Posms", ["mk"]="Етапа", ["nl"]="Etappe", ["no"]="etappe", ["pl"]="Etap", ["pt"]="Etapa", ["ro"]="Etapa", ["ru"]="Этап", ["sk"]="Etapa",
	["sv"]="Etapp", ["ast"]="etapa" }

	local word1, word2
	word2=l10nDef[wiki]
	if word2 == nil then word2=l10nDef["en"] end -- if no translation, show en translation
	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 l10nDef = {
		["ar"] = {plain = "مرحلة مستوية", hilly="مرحلة التلال", inter='مرحلة متوسطة', mount='مرحلة جبلية', time_prologue='مرحلة سباق زمني', time_team='مرحلة سباق الزمن للفرق', time_indiv='مرحلة سباق الزمن فردي', uphill='مرحلة تسلق الجبل زمني', rest='يوم راحة'},
		["ast"] = {plain = "etapa llana", hilly="etapa escarpada", inter='etapa de mediu monte', mount='etapa de monte', time_prologue='prólogu', time_team='contrarreló per equipos', time_indiv='contrarreló individual', uphill='cronoescalada', rest='xornada de descansu'},
		["fr"] = {plain = "étape de plaine", hilly="étape vallonnée", inter='étape de moyenne montagne', mount='étape de montagne', time_prologue='prologue', time_team='contre-la-montre par équipes', time_indiv='contre-la-montre individuel', uphill='contre-la-montre en côte', rest='étape de repos'},
		["en"] = {plain = "plain stage", hilly="hilly stage", inter='intermediate stage', mount='mountain stage', time_prologue='time trial stage', time_team='team time trial stage', time_indiv='individual time trial stage', uphill='uphill time trial stage', rest='rest day'},
		["br"] = {plain = "tennad plaen", hilly="tennad digompez", inter='tennad damveneziek', mount='tennad meneziek', time_prologue='prolog', time_team='ABEU a-skipailhoù', time_indiv='ABEU', uphill='', rest='devezh diskuizh'},
		["ca"] = {plain = "etapa plana", hilly="etapa accidentada", inter='etapa de mitja muntanya', mount='etapa de muntanya', time_prologue='pròleg', time_team='contrarellotge per equips', time_indiv='contrarellotge individual', uphill='', rest='etapa de descans'},
		["cs"] = {plain = "rovinatá etapa", hilly="", inter='kopcovitá etapa', mount='horská etapa', time_prologue='prolog', time_team='týmová časovka', time_indiv='individuální časovka', uphill='', rest=''},
		["da"] = {plain = "flad etape", hilly="kuperet etape", inter='middel bjergetape', mount='bjergetape', time_prologue='prolog', time_team='holdtidskørsel', time_indiv='enkeltstart', uphill='bjergenkeltstart', rest='hviledag'},
		["de"] = {plain = "Flachetappe", hilly="Hügelige Etappe", inter='Mittelschwere Etappe', mount='Hochgebirgsetappe', time_prologue='Prolog', time_team='Teamzeitfahren', time_indiv='Einzelzeitfahren', uphill='Bergzeitfahren', rest='Ruhetag'},
		["eo"] = {plain = "ebena etapo", hilly="malebena etapo", inter='mezgranda montaro etapo', mount='montara etapo', time_prologue='prologo', time_team='teama kontraux-la-kronometro', time_indiv='individua kontraux-la-kronometro', uphill='malebena kontraux-la-kronometro', rest='ripoza etapo'},
		["es"] = {plain = "etapa llana", hilly="etapa escarpada", inter='etapa de media montaña', mount='etapa de montaña', time_prologue='prólogo', time_team='contrarreloj por equipos', time_indiv='contrarreloj individual', uphill='cronoescalada', rest='jornada de descanso'},
		["eu"] = {plain = "etapa laua", hilly="etapa gorabeheratsua", inter='bitarteko etapa', mount='mendiko etapa', time_prologue='aitzinetapa', time_team='taldekako erlojupekoa', time_indiv='banakako erlojupekoa', uphill='erlojupeko igoera', rest='atseden eguna'},
		["fi"] = {plain = "Tasamaaetappi", hilly="Mäkietappi", inter='Keskivaikea vuorietappi', mount='Vuorietappi', time_prologue='', time_team='Joukkueaika-ajo', time_indiv='Henkilökohtainen aika-ajo', uphill='mäkiaika-ajo', rest='välipäivä'},
		["fo"] = {plain = "Slætt", hilly="Slætt við brúgvasteinum", inter='Óslætt', mount='Fjallateinur', time_prologue='Forteinur', time_team='Liðsúkkling', time_indiv='Einkultstartur', uphill='', rest='Hvílidagur'},
		["hu"] = {plain = "sík szakasz", hilly="dombos szakasz", inter='közepes hegyi szakasz', mount='hegyi szakasz', time_prologue='prolog', time_team='csapat időfutam', time_indiv='egyéni időfutam', uphill='hegyi időfutam', rest=''},
		["ja"] = {plain = "平坦ステージ", hilly="丘陵ステージ", inter='中間ステージ', mount='山岳ステージ', time_prologue='タイムトライアルステージ', time_team='チームタイムトライアルステージ', time_indiv='個人タイムトライアルステージ', uphill='アップヒルタイムトライアルステージ', rest='休養日'},
		["lb"] = {plain = "Flaach Etapp", hilly="Hiwweleg Etapp", inter='Mëttelschwéier Etapp', mount='Biergetapp', time_prologue='Prolog', time_team='Contre-la-montre (Ekipp)', time_indiv='Contre-la-montre (Eenzel)', uphill='Biergcourse', rest='Roudag'},
		["lv"] = {plain = "līdzenuma posms", hilly="paugurains posms", inter='vidēju kalnu posms', mount='kalnu posms', time_prologue='individuālais brauciens', time_team='komandu brauciens', time_indiv='individuālais brauciens', uphill='individuālais brauciens kalnā', rest='atpūtas diena'},
		["mk"] = {plain = "рамна етапа", hilly="ридеста етапа", inter='среднопланинска етапа', mount='планинска етапа', time_prologue='пролог', time_team='екипен хронометар', time_indiv='индивидуален хронометар', uphill='', rest='ден за одмор'},
		["nl"] = {plain = "vlakke rit", hilly="heuvelrit", inter='heuvelrit', mount='bergrit', time_prologue='proloog', time_team='ploegentijdrit', time_indiv='individuele tijdrit', uphill='klimtijdrit', rest='rustdag'},
		["no"] = {plain = "flat etappe", hilly="kupert etappe", inter='middels klatreetappe', mount='klatreetappe', time_prologue='prolog', time_team='lagtempo', time_indiv='temporitt', uphill='klatretempoetappe', rest='hviledag'},
		["pl"] = {plain = "płaski", hilly="pagórkowaty", inter='górzysty', mount='górski', time_prologue='prolog', time_team='jazda drużynowa na czas', time_indiv='jazda indywidualna na czas', uphill='jazda indywidualna na czas pod górę', rest='dzień przerwy'},
		["pt"] = {plain = "etapa plana", hilly="etapa escarpada", inter='média montanha', mount='alta montanha', time_prologue='prólogo', time_team='contrarrelógio por equipes', time_indiv='contrarrelógio individual', uphill='cronoescalada', rest='jornada de descanso'},
		["ro"] = {plain = "etapă de plat", hilly="etapă valonată", inter='etapă intermediară', mount='etapă de munte', time_prologue='prolog', time_team='contratimp pe echipe', time_indiv='contratimp individual', uphill='', rest='zi de repaus'},
		["ru"] = {plain = "равнинный", hilly="холмистый", inter='среднегорный', mount='горный', time_prologue='пролог', time_team='командная разделка', time_indiv='индивидуальная разделка', uphill='горная разделка', rest='день отдыха'},
		["sv"] = {plain = "Flack etapp", hilly="", inter='Kuperat', mount='Bergsetapp', time_prologue='Prolog', time_team='Lagtempoetapp', time_indiv='Tempoetapp', uphill='', rest='Vilodag'},
	}
	local l10n = l10nDef[wiki]
	if not l10n then l10n = l10nDef["en"] end  -- default

	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
		if typ=="Q2348250" then return "[[File:Team Time Trial Stage.svg"..border.."|20px|"..l10n.time_team.."]]" end
		if typ=="Q2266066" then return "[[File:Time Trial.svg"..border.."|20px|"..l10n.time_indiv.."]]" end
		if typ=="Q485321"  then return "[[File:Time Trial.svg"..border.."|20px|"..l10n.time_prologue.."]]" end
	end
end

local function typeofstagelogo(stageID, noborder)
	local sType 
	p = mw.wikibase.getBestStatements(stageID, 'P31') -- P31 is 'instance of'
	for _,t in pairs(p) do
		if t.mainsnak.snaktype == 'value' then
			local iOf = t.mainsnak.datavalue.value.id
			if iOf == "Q20646667" then sType = typeofstage('plain stage', nil, noborder) break end
			if iOf == "Q20646670" then sType = typeofstage('hilly stage', nil,noborder) break end
			if iOf == "Q20680270" then sType = typeofstage('intermediate stage', nil,noborder) break end
			if iOf == "Q20646668" then sType = typeofstage('mountain stage',nil, noborder) break end
			if iOf == "Q485321" then sType = typeofstage('time trial stage', "Q485321", noborder) break end -- prologue
			if iOf == "Q2266066" then sType = typeofstage('time trial stage', "Q2266066", noborder) break end -- individual time trial
			if iOf == "Q2348250" then sType = typeofstage('time trial stage', "Q2348250", noborder) break end -- team time trial
			if iOf == "Q20679712" then sType = typeofstage('uphill time trial stage', nil, 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
	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 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
	if not q then
		return s
	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 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 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 month_pl = {"stycznia", "lutego", "marca", "kwietnia", "maja", "czerwca", "lipca", "sierpnia",
	"września", "października", "listopada", "grudnia"}
	--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' then
			starttime =lang:formatDate( "Y", sTime )
		else
			starttime ='-'
		end
	else
		if y ~= y2 then
			if mode=='long' then
				starttime = lang:formatDate( "j F Y", sTime )
			else
				starttime = lang:formatDate( "j M Y", sTime )
			end
		elseif m ~= m2 then
			if mode=='long' 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 ", sTime ) .. month_pl[tonumber(lang:formatDate( "n", sTime ))] .. lang:formatDate( " Y", sTime )
			elseif m ~= m2 then starttime = lang:formatDate( "j ", sTime ) .. month_pl[tonumber(lang:formatDate( "n", sTime ))]
			else starttime = lang:formatDate( "j", sTime )
			end
		end
	end
	
	if m2=='00' then --manage the 30 November issue
		if  mode=='long' then
			endtime= lang:formatDate( "Y", eTime )
		else
			endtime= '-'
		end
	else
		if mode=='long' and y ~= y2 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 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 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 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 ", eTime ) .. month_pl[tonumber(lang:formatDate( "n", eTime ))] ..
			lang:formatDate( " 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
    
	local month_pl = {"stycznia", "lutego", "marca", "kwietnia", "maja", "czerwca", "lipca", "sierpnia",
	"września", "października", "listopada", "grudnia"}

	--handle problems with lack of precision
	local daycorrect=true
	local monthcorrect=true

	if string.sub(date,10,11)=='00' then daycorrect=false end
	if string.sub(date,7,8)=='00' then monthcorrect=false end

	if mode == 'Y' then
		return string.sub(date,2,5) --only year, note: contentLanguage:formatDate("Y", date) returns the wrong year
	end

	if daycorrect and monthcorrect then
		if wiki=="pl" then-- overcome declination issue
			return lang:formatDate( "j ", date ) .. month_pl[tonumber(lang:formatDate( "n", date ))] ..
			lang:formatDate( " Y", date )
		else
			return contentLanguage:formatDate(format[mode], date)
		end
	else
		if daycorrect or (monthcorrect==false and daycorrect==false) then --no month
			if mode=='long' then
				return string.sub(date,2,5) --only year, note: contentLanguage:formatDate("Y", date) returns the wrong year
			else --otherwise we don't know
				return '-'
			end
		else --month correct, but day incorrect
			if mode=='onlyday' then
				return '-'
			else
				local newdate=string.sub(date,1,9).."01"..string.sub(date,12)
				if wiki=="pl" then
					return month_pl[tonumber(lang:formatDate( "n", date ))] ..lang:formatDate( " Y", date )
				else
					return string.sub(contentLanguage:formatDate(format[mode], newdate), 3) --cut the day
				end
			end
		end
	end	
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

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 = {}
    
   	if available_lang_priority then
		for i, lang in ipairs(translations.lang_priority) do --from Module:Cycling_race/lang
			wantedLanguages[lang] = i
		end
	end
    --case one, one official name / period overloaded with other languages as qualifier
    --for instance https://www.wikidata.org/wiki/Q195833
	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 available_lang_priority and 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
			best = 999
			if available_lang_priority and wantedLanguages[lang] and wantedLanguages[lang] < best then
				best = wantedLanguages[lang]
				name = p1448.mainsnak.datavalue.value.text
			elseif strictLangBool then
				if wiki==lang then
					name = p1448.mainsnak.datavalue.value.text
				end
			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 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

-- 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 "[[" .. 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 "[[" .. sitelink .. "|" .. label .. "]]", correctlanguage
						end
					end
				end
			end
			if wiki == 'ru' then
				local label = revertfirstlast(mw.text.trim(string.gsub(sitelink, "%b()", "")))
				return "[[" .. sitelink .. "|" .. label.. "]]", correctlanguage
			else
				return "[[" .. 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, {'en', 'de', 'fr','es'})
			if link then
				link = string.gsub(link, "%b()", "")
			else
				link = "(label missing)"
			end
		end
		return link, correctlanguage
	end
end

--[[ Get the name of a country ]]
local function getCountryName(countryID)
	local name = ''
	if available_list then
		name = translations.list(countryID)
	end
	if name == '' 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
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, season)
	local name, sitelink, parentID, catID 
	local national_team_boolean=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
			local natureID = p2094.mainsnak.datavalue.value.id
			if teamCats[natureID] then
				catID = natureID
				break
			end
		end
	end	
	
	-- Fallback with P31 (deprecated)
	for _, p31 in statements(teamID, 'P31') do
		if checktime(p31, p31.qualifiers, timeOfRace) then
			local natureID = p31.mainsnak.datavalue.value.id
			if teamCats[natureID] then
				catID = natureID
				break
			end
		end
	end

	--look by the parent, then P31 is used
	if not catID then
		parentID = getParentID(teamID)
		if parentID then
			local p31 = getStatementForTime(parentID, 'P31', timeOfRace)
			if p31 then catID = p31.mainsnak.datavalue.value.id end
		end
		catID = catID or 'Q53534649'
	end
	-- Find country if needed
	local countryID
	if country or catID == 'Q23726798' or catID == 'Q20738667' or catID == 'Q54555994' then
		local stm = getStatementForTime(teamID, 'P1532', timeOfRace) -- P1532 is country for sport
		if stm == nil then
			stm = getStatementForTime(teamID, 'P17', timeOfRace) -- P17 is country
		end
		if stm then countryID = stm.mainsnak.datavalue.value.id end
	end
	if countryID and (catID == 'Q23726798' or catID == 'Q20738667'
		 or catID == 'Q54660600' or catID == 'Q54555994' or catID == 'Q99658502') then
		-- It is a national cycling team
		national_team_boolean=true
		if countryID=='Q145' then
			name = getCountryName('Q23666')
		else --to solve the United-Kingdom/Great Britain problem by national team
			name = getCountryName(countryID)
		end
		if catID == 'Q20738667' then -- national cycling team U23
			local s
			if wiki == 'fr' then s = ' espoirs'
			elseif wiki == 'mk' then s = ' под 23 години'
			elseif wiki == 'ar' then s = ' تحت 23'
			elseif wiki == 'es' then s = ' sub-23'
			else s = ' U23'
			end
			name = name .. s
		elseif catID == 'Q54555994' then -- national cycling team U19
			local s
			if wiki == 'fr' then s = ' juniors'
			elseif wiki == 'mk' then s = ' под 19 години'
			elseif wiki == 'ar' then s = ' تحت 19'
			elseif wiki == 'es' then s = ' sub-19'
			else s = ' U19'
			end
			name = name .. s
		elseif catID == 'Q99658502' then -- national cycling team "B"
			local s
			if wiki == 'fr' then s = ' "B"'
			elseif wiki == 'mk' then s = ' "B"'
			elseif wiki == 'ar' then s = ' "ب"'
			elseif wiki == 'es' then s = ' "B"'
			else s = ' "B"'
			end
			name = name .. s
		end	
		sitelink = getRawTeamLink(teamID)
	else
		-- It is not a national cycling team
		local isLocal
		if season and season == true then
			sitelink = wikibase.getSitelink(teamID)
			name, isLocal = getOfficialName(teamID, timeOfRace,true)
			if not sitelink then
				parentID = getParentID(teamID)
				if parentID then sitelink = wikibase.getSitelink(parentID) end
			end
		else
			parentID = getParentID(teamID)
			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 available_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, national_team_boolean
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(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 localframe:extensionTag('ref', refText, refargs)
		end
	end
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

	if available_list then
		name = translations.list(placeID) --return '' if nothing
	end
	if name==nil or name=='' 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(class, 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 class=="Q18536594" then 
		if wiki=="fr" then
			label="JO"
		else
			label="OG"
		end
	else
		 label = getLabelFallback(class, {wikilang, 'en', 'fr', 'de'})
	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(class , "", 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)
	dis="road"
	if q and q.P642 and q.P642[1] and q.P642[1].snaktype == 'value' then
		if q.P642[1].datavalue.value.id == 'Q520611' or q.P642[1].datavalue.value.id =='Q1031445' then
			onlyRoad=false
			dis="mountainBike"
		elseif  q.P642[1].datavalue.value.id == 'Q335638' then
			onlyRoad=false
			dis="cycloCross"
		elseif q.P642[1].datavalue.value.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, national_team_boolean = 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, national_team_boolean = getTeamLinkCat(teamID, timeOfRace)
					end
				end
			end
		end
	end
	return link, teamID, catID, countryID, national_team_boolean
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, {wikilang, 'en', 'fr', 'de'}) 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
	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
	return country
end

local function tableA(s)
	local error_message = ''
	if wiki == "ar" and s.item == "" or not s.item then return "" end
	if s.error_message == 1 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
	
	local table = mw.html.create('table')
		:addClass('sortable')
		:attr('cellpadding', '0')
		:attr('cellspacing', '0')
		:css('border' , '1px solid rgb(200,200,200)')
		:css('padding', '3px')
	
	local title =translate(s.header_function,s.header_1, s.womenrace_bool, 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 = table:tag('tr'):tag('th'):attr('colspan', tostring(#s.header_2 + 1))
	:cssText('padding:2px; text-align:center; line-height: 1.8em;')
	:css('background-color',backgroundColor)
	caption:wikitext(tostring(wd_link)..' '..error_message ..' '..title)

	local country=getCountryBool(s.no_country)

	local header = table:tag('tr')
	for i,k in ipairs(s.header_2) do
		if i == s.country_column then
			if available_list and 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.womenrace_bool))
			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.womenrace_bool))
			if s.data_sort_type[i] == 'unsortable' then
				column:addClass('unsortable')
			end
		end
	end

	return table
end

local function tableB(s) --for startlist
	local error_message = ''
	if wiki == "ar" and s.item == "" or not s.item then return "" end
	if s.error_message == 1 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
	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 rgb(200,200,200); margin: 0 0 0 0;"..
				"background-color: rgb(255, 255, 255); padding: 0px; float: left;"..
				"clear: left; ; 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("NavFrame")
		:cssText('center = margin: 0 0.5em 0;clear:both; border: 1px solid rgb(200,200,200);' ..
		'cellpadding="4" cellspacing="0" style="width:100%; background-color: rgb(255, 255, 255);padding: 5px;'..
		'margin-bottom:1em; background-color:'..backgroundColor..';')
		:attr('title','['..translate("startlist",14)..']/['..translate("startlist",15)..']')
		local tDiv= rollTable1:tag('div'):addClass("NavHead")
		:cssText('text-align:'.. textalign .." =;height:1.8em; color:black;font-weight:bold;")
		:css('background-color',backgroundColor)
		tDiv:tag('span')

		local tSpan=tDiv:wikitext(tostring(wdlink_span))
		tDiv:wikitext(translate("startlist",1))
		
		tDiv = rollTable1:tag('div'):addClass("NavContent"):cssText("margin:0; background:white; display:block; text-align:left;")
	
		local tTable= tDiv:tag('table'):cssText("border:1px solid rgb(200,200,200)")
		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)
		:attr('colspan','3'):attr('align','center')
		tCell:node(wdlink_span)
		tCell:wikitext(translate("startlist",1,s.womenrace_bool 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', '+1937-12-29'}},
		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'}},
		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'}},
		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', '+1946-06-19'},
			{'Flag of Italy (1861–1946).svg', '+1861', '+1946-06-19'}},
		Q39 = {'SUI', {'Flag of Switzerland.svg', '+1889-12-12'},
			{'Flag of Switzerland.svg', '+1879-01-01'}},
		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', '+1806'}},
		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.svg', '+1794-05-20'}},
		Q145 = {'GBR', {'Flag of the United Kingdom.svg'}},
		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'}},
		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 (1928–1994).svg', '+1928-05-31', '+1994-04-27'}},
		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-14'}},
		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'}},
		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'}},
		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'}},
		Q916 = {'ANG', {'Flag of Angola.svg', '+1975-11-11'}},
		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', '+1690'}}, --Kingdom of the Netherlands
		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
		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 = mw.wikibase.getBestStatements(countryID, "P41") -- P41 is flag image
		if p41[1] and p41[1].mainsnak.snaktype == 'value' then
			result = '[[File:' .. p41[1].mainsnak.datavalue.value .. '|border|' .. flagpxSize ..'|(Wikidata:' .. countryID .. ')]]'
			if arwiki_totemplate then
				result = '{{flagicon image|' .. p41[1].mainsnak.datavalue.value .. '}}'
			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
		if available_list then
			if type(translations.list) == "function" then
				countryName = translations.list(countryID)
			end
		end
		if countryName == nil or countryName=='' 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

	local data = {
		{'Q33881', 'montagne', '+1975', '+2500', 'Q25265958', 'Q927157'}, -- Tour de France
		{'Q33881', 'leader', '+1919', '+2500', 'Q24257871', 'Q738903'},
		{'Q33881', 'points', '+1953', '+1967', 'Q24645209', 'Q175399'}, -- Jersey green.svg
		{'Q33881', 'points', '+1968', '+1968', 'Q26919974', 'Q175399'}, -- Jersey red.svg
		{'Q33881', 'points', '+1969', '+2500', 'Q24645209', 'Q175399'}, -- Jersey green.svg
		{'Q33881', 'jeune', '+1975', '+2500', 'Q640430', 'Q2254180'}, -- Jersey white.svg
		{'Q33881', 'winner_fighting', '+2003', '+2500', 'Q27644113', 'Q2094179'}, -- Jersey red number.svg
		{'Q33881', 'winner_fighting2', '+2003', '+2500', 'Q27644113', 'Q2094179'}, -- Jersey red number.svg
		{'Q33881', 'equipe', '+2006', '+2500', 'Q27644112', 'Q1436680'}, -- Jersey yellow number.svg

		{'Q33861', 'leader', '+1931', '+2500', 'Q24257763', 'Q1164275'}, -- Giro d'Italia, Jersey pink.svg
		{'Q33861', 'points', '+1967', '+1968', 'Q26919974', 'Q641083'}, -- Jersey red.svg
		{'Q33861', 'points', '+1969', '+2009', 'Q26945272', 'Q641083'}, -- Jersey violet.svg
		{'Q33861', 'points', '+2010', '+2016', 'Q26919974', 'Q641083'}, -- Jersey red.svg
		{'Q33861', 'points', '+2017', '+2500', 'Q26945272', 'Q641083'}, -- Jersey violet.svg
		{'Q33861', 'montagne', '+1974', '+2011', 'Q24645209', 'Q641060'}, -- Jersey green.svg
		{'Q33861', 'montagne', '+2012', '+2500', 'Q24687409', 'Q641060'}, -- Jersey blue.svg
		{'Q33861', 'jeune', '+1976', '+2500', 'Q640430', 'Q641662'}, -- Jersey white.svg

		{'Q33937', 'leader', '+1935', '+1936', 'Q24258056', 'Q3278226'}, -- Vuelta a España, Jersey orange.svg
		{'Q33937', 'leader', '+1941', '+1941', 'Q26696171', 'Q640430'}, -- Jersey white.svg
		{'Q33937', 'leader', '+1942', '+1942', 'Q24258056', 'Q3278226'}, -- Jersey orange.svg
		{'Q33937', 'leader', '+1945', '+1945', 'Q24257872', 'Q2534046'}, -- Jersey red.svg
		{'Q33937', 'leader', '+1946', '+1950', 'Q26696171', 'Q640430'}, -- Jersey white.svg
		{'Q33937', 'leader', '+1955', '+1976', 'Q24257871', 'Q738903'}, -- Jersey yellow.svg
		{'Q33937', 'leader', '+1977', '+1977', 'Q24258056', 'Q3278226'}, -- Jersey orange.svg
		{'Q33937', 'leader', '+1978', '+1998', 'Q24257871', 'Q738903'}, -- Jersey yellow.svg
		{'Q33937', 'leader', '+1999', '+2009', 'Q24257991', 'Q27665179'}, -- Jersey gold.svg
		{'Q33937', 'leader', '+2010', '+2500', 'Q24257872', 'Q2534046'}, -- Jersey red.svg
		{'Q33937', 'points', '+1945', '+1986', 'Q24687409', 'Q2746711'}, -- Jersey blue.svg
		{'Q33937', 'points', '+1987', '+1989', 'Q24645209', 'Q11638007'}, -- Jersey green.svg
		{'Q33937', 'points', '+1990', '+2009', 'Q24687409', 'Q2746711'}, -- Jersey blue.svg
		{'Q33937', 'points', '+2010', '+2500', 'Q24645209', 'Q11638007'}, -- Jersey green.svg
		{'Q33937', 'montagne', '+1935', '+1985', 'Q27670182', 'Q11638007'}, -- Jersey green.svg
		{'Q33937', 'montagne', '+1986', '+1986', 'Q27670174', 'Q3278226'}, -- Jersey orange.svg
		{'Q33937', 'montagne', '+1987', '+1987', 'Q27670178', 'Q2534046'}, -- Jersey red.svg
		{'Q33937', 'montagne', '+1988', '+1989', 'Q27670105', 'Q27670115'}, -- Jersey blackdots.png
		{'Q33937', 'montagne', '+1990', '+2005', 'Q27670182', 'Q11638007'}, -- Jersey green.svg
		{'Q33937', 'montagne', '+2006', '+2008', 'Q27670174', 'Q3278226'}, -- Jersey orange.svg
		{'Q33937', 'montagne', '+2009', '+2009', 'Q27670126', 'Q27670163'}, -- Jersey granate.svg
		{'Q33937', 'montagne', '+2010', '+2500', 'Q25265959', 'Q27670167'}, -- Jersey bluedots.svg
		{'Q33937', 'jeune', '+2019', '+2500', 'Q640430', 'Q60233927'}, -- Jersey white.svg

		{'Q2091354', 'leader', '+2011', '+2500', 'Q24257871'}, -- Tour of Norway, Jersey yellow.svg
		{'Q2091354', 'sprints', '+2011', '+2011', 'Q26806427'}, -- Jersey green.svg
		{'Q2091354', 'points', '+2012', '+2017', 'Q24645209'}, -- Jersey green.svg
		{'Q2091354', 'points', '+2018', '+2018', 'Q28820618'}, -- MaillotCyan.PNG
		{'Q2091354', 'points', '+2019', '+2500', 'Q47945989'}, -- Jersey dark blue.svg
		{'Q2091354', 'montagne', '+2011', '+2015', 'Q25265958'}, -- Jersey polkadot.svg
		{'Q2091354', 'montagne', '+2016', '+2017', 'Q27670174'}, -- Jersey orange.svg
		{'Q2091354', 'montagne', '+2018', '+2500', 'Q25265958'}, -- Jersey polkadot.svg
		{'Q2091354', 'jeune', '+2011', '+2500', 'Q640430'}, -- Jersey white.svg
		{'Q2091354', 'winner_fighting', '+2017', '+2017', 'Q29957114'}, -- MaillotCyan.PNG
		{'Q128713', 'leader', '+2013', '+2017', 'Q24257871'}, -- Tour des Fjords, Jersey yellow.svg
		{'Q128713', 'leader', '+2018', '+2018', 'Q29594434'}, -- MaillotCyan.PNG
		{'Q128713', 'points', '+2013', '+2014', 'Q24645209'}, -- Jersey green.svg
		{'Q128713', 'points', '+2015', '+2017', 'Q24687409'}, -- Jersey blue.svg
		{'Q128713', 'points', '+2018', '+2018', 'Q25265938'}, -- Jersey violet.svg
		{'Q128713', 'montagne', '+2013', '+2018', 'Q25265958'}, -- Jersey polkadot.svg
		{'Q128713', 'jeune', '+2013', '+2018', 'Q640430'}, -- Jersey white.svg
		{'Q128713', 'winner_fighting', '+2015', '+2015', 'Q30035038'}, -- Jersey green.svg
		{'Q128713', 'winner_fighting', '+2016', '+2017', 'Q30035039'}, -- Jersey orange.svg
		{'Q128961', 'leader', '+2013', '+2500', 'Q24687408'}, -- Arctic Race of Norway, Jersey blue.svg
		{'Q128961', 'points', '+2013', '+2500', 'Q24645209'}, -- Jersey green.svg
		{'Q128961', 'montagne', '+2013', '+2014', 'Q27670178'}, -- Jersey red.svg
		{'Q128961', 'montagne', '+2015', '+2500', 'Q27670174'}, -- Jersey orange.svg
		{'Q128961', 'jeune', '+2013', '+2500', 'Q640430'}, -- Jersey white.svg
		{'Q128961', 'winner_fighting', '+2014', '+2500', 'Q27644113'}, -- Jersey red number.svg
		{'Q17619325', 'leader', '+2014', '+2014', 'Q24257871'}, -- Ladies Tour of Norway, Jersey yellow.svg
		{'Q17619325', 'leader', '+2015', '+2016', 'Q26945272'}, -- Jersey violet.svg
		{'Q17619325', 'leader', '+2017', '+2500', 'Q24257871'}, -- Jersey yellow.svg
		{'Q17619325', 'points', '+2014', '+2500', 'Q24645209'}, -- Jersey green.svg
		{'Q17619325', 'montagne', '+2014', '+2500', 'Q25265958'}, -- Jersey polkadot.svg
		{'Q17619325', 'jeune', '+2014', '+2500', 'Q640430'}, -- Jersey white.svg
		{'Q17619325', 'winner_fighting', '+2016', '+2500', 'Q30035039'}, -- Jersey orange.svg
	}
	--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) 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, {wikilang, 'en', 'fr'})
					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, getkm) ===
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(riderId)
	local isCountry = false
	if riderId then
		local p31 = wikibase.getBestStatements(riderId, '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

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 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
	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(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)
			
			if q.P642 and q.P642[1].snaktype == 'value' then
				for _, q642 in pairs(q.P642) do
					wOf = q642.datavalue.value.id -- P642 is 'of'
					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(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
										local p17 = getStatementForTime(wID, 'P17', timeOfRace) --P27 is country of citizenship
										if p17 then
											countryID = p17.mainsnak.datavalue.value.id
										end
									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[1] < b[1] end)
	for _, m in ipairs(t_Body) do resultTable:node(m[2]) end
	return resultTable
end

--------- Definition sub-functions for calendar and victory ------
local function getTimeOfRace(raceID)
	local timeOfRace = firstValue(raceID, 'P580', 'time')
	if timeOfRace==nil then
		timeOfRace = firstValue(raceID, 'P585', 'time') -- P585 is 'point in time'
		if timeOfRace==nil then
			timeOfRace = firstValue(raceID, 'P582', 'time')
			if timeOfRace==nil then
				local link = getSitelinkFallback(raceID, {'en', 'fr', 'de'})
				if link then
					local year = string.match(link, '%d%d%d%d')
					if year then
						timeOfRace = year .. '-01-01T00:00:00Z'
					end
				end
			end
		end
	end
	if timeOfRace == nil and wiki == "ar" then
		timeOfRace = '+1970-01-01T00:00:00Z'
	end
	return timeOfRace, '> Wikidata is missing data about start time (P580) or point in time (P582)'
end

local function fn_date(entityID, functionName)  --to move as a general function
	local tempdate, timeOfRace, sortkey, sortkeyDate
	local outTable={}
	local sTime = firstValue(entityID, 'P580', 'time') -- P580 is 'start time'
	local eTime = firstValue(entityID, 'P582', 'time') -- P582 is 'end time'
	if sTime and eTime then
		local startTime, endTime = getStartEndTime(sTime, eTime, 'small')
		if functionName==nil then --calendar
			tempdate = startTime .. ' – ' .. endTime  --mettre year en option!
			sortkeyDate = sTime
		else  --victory, general classification
			tempdate =endTime
			sortkeyDate =eTime
		end
		timeOfRace = eTime
	else
		-- This function give a format to dates when P585 (date) is used in a single day race
		local pTime = firstValue(entityID, 'P585', 'time') -- P585 is 'point in time'
		if pTime then
			tempdate = funcDate(pTime, 'small')
			timeOfRace = pTime
			sortkeyDate = pTime
		end
	end
	local _, _, y, m, d = string.find(sortkeyDate or "", "(%d+)-(%d+)-(%d+)")
	if y~= nil and m~= nil and d~=nil then
		sortkey = y..m..d
	elseif y~= nil and m~= nil then
		sortkey = y..m
	elseif y~= nil then
		sortkey = y
	else 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)
	
	outTable["timeOfRace"]=timeOfRace
	outTable["tCell"]=tostring(tCell)
	outTable["sortkey"]=sortkey
	return outTable
end

local function fn_country(entityID, timeOfRace,countrybool, raceCell, parentID)
	-- This function gives countries where the race take place
	-- parentID taken from fn_race, optional

	local country, countryname, outTable= {}, {}, {}
	local countryID

	local cssCell="text-align:" .. textalign .. ";padding:0 0.5em"
	local tCell= mw.html.create('td'):cssText(cssCell)
	
	local listOfProperty={'P1532','P17'} -- P1512 is 'country for sport' to handle problems with Hong Kong etc.
	local listOfID = {entityID, parentID}
	
	for _, thisID in ipairs(listOfID) do
		if thisID~=nil then
			for _, prop in ipairs(listOfProperty) do
				if countryID == nil then --like "break"
					for _, p1532 in statements(thisID, prop) do 
						countryID = p1532.mainsnak.datavalue.value.id
						countryname[#countryname + 1] = getCountryName(countryID)
						if countrybool==false or not countryname[#countryname] then
							country[#country + 1]=flag(countryID, timeOfRace)
						else
							country[#country + 1]=flag(countryID, timeOfRace).." "..countryname[#countryname]
						end
						outTable["flag"]=flag(countryID, timeOfRace)
					end
				end
			end
		end
	end

	if countryID == nil then outTable["flag"]="no flag" end
	if countryname[1] then tCell:attr('data-sort-value',countryname[1]) end
	if countrybool==false then
		tCell:wikitext((country[1] or '').." "..(raceCell or ''))
		outTable["countryname"]=''
	else
		if countryname[1] then
			outTable["countryname"]=countryname[1]
			if country[1] then tCell:wikitext(country[1]) end
		else
			outTable["countryname"]=''
		end
		
	end
	outTable["tCell"]=tCell
	return outTable
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'}
	
	--system with P3450 and P2094
	instanceOf=firstValue(entityID, 'P3450', 'id')
	--else use P31
	if instanceOf==nil then
		for _, p31 in statements(entityID, 'P31') do
			instanceOfTemp = p31.mainsnak.datavalue.value.id
			if instanceOfTemp ~= "Q27020041" and class_dic[instanceOfTemp]==nil then	--we don't want the class, but the main race
				instanceOf=instanceOfTemp
			end
		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=wikibase.label(instanceOf)
			if wiki == 'ar' then arlabel = mw.wikibase.getLabelByLang(instanceOf, 'ar') end
			if not label then
				label = getLabelFallback(entityID, {'en', 'fr', 'de'}) 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=wikibase.label(entityID)
		if wiki == 'ar' then arlabel = mw.wikibase.getLabelByLang(entityID, 'ar') end
		if not label then
			label = getLabelFallback(entityID, {'en', 'fr', 'de'}) or ''
		end
	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 UCI_Circuits[parentCircuitID] then
							displayedCircuitID=circuitID
						end
					end
				end
			else --for instance Flèche wallonne
				if q then
					if q.P642 and q.P642[1].snaktype == 'value' and q.P642[1].datavalue.value.id then	
						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 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

	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, sTime
end

-- for display period with only year, for instance (2020-2021)
local function getPeriod(q, brackets)
	local sTime, eTime = getStartEndfromQuali(q)
	return getPeriodSub(sTime, eTime, brackets)
end

local function getClassCalendar_sub(entityID)
	local classID=firstValue(entityID, 'P279', 'id') 
	
	if classID==nil then
		for _, p31 in statements(entityID, 'P31') do
			if class_dic[p31.mainsnak.datavalue.value.id]~=nil then
				classID=p31.mainsnak.datavalue.value.id
				break
			end
		end
	end
	return classID
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 class_dic[classID]~=nil then 
			    circuitID=classToCircuit(classID, entityID, false, p279.qualifiers) 
			    classLink=classLinkFn(classID,circuitID)
				if circuitID and 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]
		circuitLink=WPlinkpure(class[3])
	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
	local outTable={}

	for _, p31 in statements(entityID, 'P31') do
		if stages[p31.mainsnak.datavalue.value.id] then
			entity_type = 'stage'  --then the class is one stage above!
			local parentID = getParentID(entityID)
			classID=getClassCalendar_sub(parentID)
			
			outTable["parentID"] = parentID --as we read it here, no need to read it afterwards
			stageID= entityID --everything slide from one rank
			entityID = parentID
		end
	end
	
	if classID==nil then
		classID=getClassCalendar_sub(entityID)
	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
		Sitelink=getMainRaceLink(entityID,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)
		outTable["raceCell"]=tostring(tCell)
	else
		outTable["raceCell"]=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

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

local function fn_rider(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(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
	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+1
		else
			return eYear-tYear-1, tYear, eYear+1
		end
	else
		return 0, tYear, eYear+1
	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)
	local winners = {	Q20882667 = '',}-- Q20882667 is 'overall winner general classification'
	local winnersId={	Q20882667 = '',}--to detect disqualification
	local WDlink_on, sitelink

	-- WDlink_on is used to decide if a Wikidata flag will be shown
	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(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" 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' 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 there is nothing to check
		num=#t.race
		numberOfEditions=num
		lastRunEdition=num
		lastEditionDate=t.race[num]['raceDate']
	end

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

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

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)
	local listOfNames={}
	local langFallback, officialname,language

	if wiki=="mk" then
		langFallback= {wiki} --only exact language
	else
		langFallback= {wiki, 'en','fr', 'de', 'es', 'nl', 'it'} --all languages, but tested one at a time
	end
	
	local kk=1
	while #listOfNames == 0 and kk<=#langFallback do
		lang=langFallback[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)
					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 p856 = wikibase.getBestStatements(itemID, 'P856')
	if p856[1] and p856[1].mainsnak.snaktype == 'value' then
		local url = p856[1].mainsnak.datavalue.value
		return '['..url.." "..translate("raceinfobox",3)..']'
	end
	return nil
end

local function getKm(wiki)
	local km
	if wiki == "ar" then km = 'كم'
	elseif wiki == "mk" then km = 'км'
	elseif wiki == "ru" then km = 'км'
	elseif wiki == "ja" then km = 'キロメートル'
	else km = 'km' end
	return km
end

local function getm(wiki)
	local m
	if wiki == "ar" then m = 'م'
	elseif wiki == "mk" then m = 'м'
	elseif wiki == "ru" then m = 'м'
	elseif wiki == "ja" then m = ''
	else m = 'm' end
	return m
end

local function getKg(wiki)
	local kg
	if wiki == "ar" then kg = 'كجم'
	elseif wiki == "mk" then kg = 'кг'
	elseif wiki == "ru" then kg = 'кг'
	elseif wiki == "ja" then kg = ''
	else kg = 'kg' end
	return kg
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)
	local m, unit
	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
			return m
		elseif unit=='http://www.wikidata.org/entity/Q174728' then --cm
			return m*0.01
		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 getHeight(entityID)
	local m
	local text
	local lang = contentLanguage

	local p = mw.wikibase.getBestStatements(entityID, 'P2048')	
	m= checkm(p)
	if m then
		text = lang:formatNum(m)
		if wiki == 'fo' then
			text = string.gsub(text, "%.", ",")
		end
		text = text .. ' ' .. getm(wiki)
	end
	return text
end

local function getWeight(entityID)
	local kg
	local text
	local lang = contentLanguage
	
	local p = mw.wikibase.getBestStatements(entityID, 'P2067')	
	kg = checkkg(p)

	if kg then
		text = lang:formatNum(kg)
		if wiki == 'fo' then
			text = string.gsub(text, "%.", ",")
		end
		text = text .. ' ' .. getKg(wiki)
	end
	return text
end

local function getDistance(raceID, addUnit)
	local km
	local p = mw.wikibase.getBestStatements(raceID, 'P3157') -- P3157 is 'event distance'
	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
			stageID = p527.mainsnak.datavalue.value.id
			stagep=mw.wikibase.getBestStatements(stageID, 'P3157')
			tempkm=checkkm(stagep)
			if tempkm then
				if not km then
					km=tempkm
				else
					km=km+tempkm
				end
			end
		end
	end
	local text
	local lang = contentLanguage
	if km then
		-- The unit should always be km. Skip if it isn't.
		text = lang:formatNum(km)
		if wiki == 'fo' then
			text = string.gsub(text, "%.", ",")
		end
		if addUnit then
			text = text .. ' ' .. getKm(wiki)
		end
	end
	return text, km
end

local function getKmh(wiki)
	local kmh
	if wiki == "ar" then kmh = 'كم/س'
	elseif wiki == "da" then kmh = 'km/t'
	elseif wiki == "fo" then kmh = 'km/t'
	elseif wiki == "nl" then kmh = 'km/u'
	elseif wiki == "no" then kmh = 'km/t'
	elseif wiki == "mk" then kmh = 'км/ч'
	elseif wiki == "ru" then kmh = 'км/ч'
	elseif wiki == "ja" then kmh = 'キロメートル毎時'
	else kmh = 'km/h' end
	return kmh
end

local function getElevation(raceID)
	local l10nDef = {
		["en"] = " m",
		["ar"] = " م",
	}
	local l10n = l10nDef[wiki] or l10nDef["en"]
	local temp = mw.wikibase.getBestStatements(raceID, 'P7297')
	if temp[1] and temp[1].mainsnak.snaktype == 'value' then
		local unit = temp[1].mainsnak.datavalue.value.unit
		if unit == 'http://www.wikidata.org/entity/Q11573' then
			return tonumber(temp[1].mainsnak.datavalue.value.amount) .. l10n
		end
	end
	return nil
end

local function getSpeed(raceID, addUnit,kmdistance, property)
	local p = mw.wikibase.getBestStatements(raceID, 'P2052') -- P2052 is 'speed'
	local kmh, unit, text, found, timeOfRace
	local lang = contentLanguage
	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'
			found=true
		end
	end
	if not found 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
				found=true
				kmh=math.modf(1000*kmdistance/(timeOfRace/3600))/1000
			end
		end
	end
	if found then	
		-- The unit should always be km/h. Skip if it isn't.
		text = lang:formatNum(kmh)
		if wiki == 'fo' then
			text = string.gsub(text, "%.", ",")
		end
		if addUnit then
			text = text .. ' ' .. getKmh(wiki)
		end
	end
	return text
end

local function getGenderCode(riderID, default)
	local gender
	local p21 = mw.wikibase.getBestStatements(riderID, 'P21') -- P21 is gender
	if p21[1] and p21[1].mainsnak.snaktype == 'value' then
		local g = p21[1].mainsnak.datavalue.value.id
		if g == 'Q6581097' then gender = 'm' -- Male
		elseif g == 'Q6581072' then gender = 'f' -- Female
		elseif g == 'Q1052281' then gender = 't' -- Transgenre
		end
	end
	return gender or default -- default is for teams, n or f
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

function func_error_message(x)
	local l10nDef = {
		["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.wikipedia.org"] = '[[Kategorie:Údržba:Doplnit štítek na Wikidatech]]',
		["//lv.wikipedia.org"] = '[[Category:Vikidatos trūkst nosaukuma latviešu valodā]]',
		["//he.wikipedia.org"] = '[[קטגוריה:ויקינתונים:ערכים חסרי תווית בעברית: קבוצת אופניים]]',
	}
	local l10n = l10nDef[mw.site.server]
	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")
		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 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')
	if wiki == "eo" then
		tab:cssText(standardtablecss):css('width','23em')
		:addClass('infobox')
	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 white; 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')
		: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
	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:75%')
		:wikitext(icon):tag('td')
	else
		tC=tCell:attr('colspan','2')
	end
    local wd_link = wdLink(ID)
	local link = "[[" .. s .. "|" .. translation .. "]] "..wd_link
	if wiki == "ar" then
		link = wd_link .." [[" .. s .. "|" .. translation .. "]]"
	end
	tC:cssText('text-align:right; border-top:3px solid '..backgroundColor..'; font-size:75%')
	: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)
	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)
						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
							if display_flag then	
								value= flag(ID, sTime).." "..getCountryName(ID)
							else	
								value=getCountryName(ID)
							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) --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(wikibase.label(riderReason), "%b()", "") or getLabelFallback(riderReason,{'en', 'fr', 'de'})
			riderRef = getReference(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(wikibase.label(stagiaire), "%b()", "") or getLabelFallback(stagiaire,{'en', 'fr', 'de'})
			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 = c..' '..a..' '..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 not label then
			label = getLabelFallback(riderID, {'en', 'fr', 'de', 'es'})
			return findLastName(label,wiki)
		else
			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
	else
		local label = getLabelFallback(riderID, {'en', 'fr', 'de', 'es'})
		return findLastName(label,wiki)
	end
end

--== V) Main functions ==
--=== A) Function race reference ===
local function race_reference(raceID)
	-- 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="}
	}
	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(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

	if wiki == "ar" and string.match(frame:getParent():getTitle(), '%P+') == mw.site.namespaces.Template.name
	then frame = frame:getParent() end

	if frame.args[1] ~= nil then calendarID = string.gsub(frame.args[1], "%c", "") end

	local display_numbering=false --default
	local country_column=2
	if istrue(frame.args['display_numbering']) 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(frame.args['no_country']) or wiki == "ar" then
		no_country={wiki}
	end
	-- country --
	table.insert(headers, 5)
	--race--
	table.insert(headers, 4)

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

	local data_type={}
	for ii=1,#headers do
		table.insert(data_type,'')
	end
	
    local womenrace_bool=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,
		error_message = 0,
		displayed_class =nil,
		display_team=display_team,
		display_class=display_class,
		display_leader= display_leader,
		frame=frame,
		womenrace_bool=womenrace_bool
	}
	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
	if wiki == "ar" then frame = frame:getParent() end
	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
	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
		if not calendarID  and frame.args[key] then
			local year = frame.args[key]
			year = string.gsub(year , "%c", "")
			if v[year] then
				calendarID = v[year]
				header_1_number = header_1_tab[key]
				display_code = display_code_tab[key]
			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
	else
		tempdic=tempdic2
	end
	if istrue(frame.args['display_numbering']) then
		tempdic.display_numbering=true
	elseif frame.args['display_numbering'] and istrue(frame.args['display_numbering']) == nil then
		tempdic.display_numbering=false
	end
	local womenrace_bool=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,
		error_message = 0,
		displayed_class = nil, --all
		display_team=tempdic.display_team,
		display_class=tempdic.display_class,
		display_leader=tempdic.display_leader,
		frame=frame,
		womenrace_bool=womenrace_bool
	}
	return calendar_main(s, tableA(s))
end

function calendar_main(s, resultTable)--Display the UCI women calendar of one year
	localframe=s.frame
	local calendarID=s.item
	local fn_racetable,fn_datetable, fn_countrytable
	local t_Body ={}
	local womenrace_bool=isWomenrace(calendarID)

	local temp=firstValue(calendarID, s.property)
	if not temp then s.error_message = 2 return '' end

	local country=getCountryBool(s.no_country)
	if available_list==false then country=false end --otherwise the display put no "country" column...

	----- 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 ----
		fn_datetable = fn_date(RaceID)
		fn_racetable= fn_race(RaceID,s.displayed_class,s.display_class,fn_datetable["timeOfRace"],nil,country)

		if fn_racetable["raceCell"]~=nil then --otherwise the class is not display
			fn_countrytable=fn_country(RaceID,
									   fn_datetable["timeOfRace"],
									   country,
									   fn_racetable["raceCell"],
									   fn_racetable["parentID"]
									   ) 
			
			local tRow = mw.html.create('tr'):cssText( "line-height: 1.8em; padding: 5px;")

			tRow:node(fn_datetable["tCell"])
			if s.display_numbering == true then
				tRow:tag('td'):cssText("text-align:center;padding:0 0.5em"):wikitext(tostring(kk))
			end
			
			tRow:node(fn_countrytable["tCell"])
			if country then
				tRow:node(fn_racetable["raceCell"])
			end
			if fn_racetable["classCell"] then tRow:node(fn_racetable["classCell"]) end --class
			local tCell, _ =fn_rider(RaceID,fn_datetable["timeOfRace"],s.display_team,s.only_winner)
			tRow:node(tCell)
			if s.display_leader==true then
				tRow:node(fn_rider(RaceID,fn_datetable["timeOfRace"],s.display_team,3))
			end
			---- Add the row to the table
			t_Body[#t_Body + 1] = {fn_datetable["sortkey"], tRow}
		end 
	end

	return sortAndConcat(t_Body, resultTable)
end

function p.nationalchampionships(frame)
	local calendarroadID, calendarITTID, year
	if wiki == "ar" then
		frame = frame:getParent()
	end
	local listOfCalendar={NationalRoadCyclingChampionships,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
			if ((ii==1 and calendarroadID==nil) or (ii==2 and calendarITTID ==nil)) and frame.args[key] then
				year = frame.args[key] 
				year = string.gsub( year , "%c", "")	
				if v[year] then
					if ii==1 then
						calendarroadID = v[year]
					else
						calendarITTID = v[year]
					end
				end
			end
		end
	end
	
	local womenrace_bool=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
		error_message = 0,
		display_team = true,
		display_countrylink = true,
		frame = frame,
		womenrace_bool=womenrace_bool
	}
	return nationalchampionships_main(s,tableA(s))
end

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

	local temp=firstValue(s.calendarroadID, s.property)
	if temp then else s.error_message = 2 return '' 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
				fn_countrytable=fn_country(thisID,timeOfRace,s.country)
				sortkey=string.gsub(fn_countrytable["countryname"], 'É', 'E') --case États Unis

				--create the table
				if tableChamp[sortkey]==nil then 
					tableChamp[sortkey]={}
					tableChamp[sortkey]['countryname']=fn_countrytable["countryname"] --raw
					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']=fn_countrytable["flag"]
				end
				
				--fill the table
				tRace, thereisawinner=fn_rider(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']=tRace
				else
					tableChamp[sortkey]['ITTwinner']=tRace
				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'])
			t_Body[#t_Body + 1] = {key, tRow}
		end --no winner
	end --end list of key

	return sortAndConcat(t_Body, resultTable)  
end

--=== C) Victory ===
function p.victories(frame)
	local IDtemp=frame.args[1]
	local womenrace_bool=isWomenrace(IDtemp)
	
	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 = IDtemp,
		property = 'P2522',
		no_country = no_country_victories,
		error_message = 0,
		frame=frame,
		womenrace_bool=womenrace_bool
	}
	return victory_main(s ,tableA(s))
end

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

	local temp=firstValue(s.item, s.property,'id')
	if temp then else s.error_message = 2 return '' end

	local country=getCountryBool(s.no_country)
	if available_list==false then country=false end

	local sortkey
	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;")

		fn_datetable = fn_date(RaceID, 'victory')
		fn_racetable=fn_race(RaceID,nil ,true,fn_datetable["timeOfRace"], 'victory',country)--displayed_class=nil
		
		if fn_racetable["raceCell"]~= nil then --otherwise class not to be displayed
			fn_countrytable=fn_country(RaceID,
						               fn_datetable["timeOfRace"],
						               country,
						               fn_racetable["raceCell"],
									   fn_racetable["parentID"]
									   )
			
			tRow:node(fn_datetable["tCell"])
			if country==true then
				tRow:node(fn_racetable["raceCell"])  --race site link is in fn_countrytable
			end
			tRow:node(fn_countrytable["tCell"]) 
			tRow:node(fn_racetable["classCell"]) --class
			tRow:node(fn_rider(RaceID,fn_datetable["timeOfRace"],false,1))
			t_Body[#t_Body + 1] = {fn_datetable["sortkey"], tRow}
		end --no winner
	end --end list of key
	
	return sortAndConcat(t_Body, resultTable)
end

--== D) Stage infobox
function p.stageinfobox(frame)
	local entityID = mw.text.trim(frame.args[1])
	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
	
	local womenrace_bool=isWomenrace(entityID)
		
	local details = {
		{ name = translate("stageinfobox",2,womenrace_bool)}, -- course / not used
		{ name =  translate("stageinfobox",2,womenrace_bool)}, -- competition
		{ name = translate("stageinfobox",3,womenrace_bool), name_plural = translate("infobox",4,womenrace_bool)}, -- stage type 
		{ name = translate("stageinfobox",4,womenrace_bool), name_plural = translate("infobox",7,womenrace_bool)}, -- date
		{ name = translate("stageinfobox",6,womenrace_bool)}, -- distance
		{ name = translate("stageinfobox",7,womenrace_bool), name_plural = translate("infobox",10,womenrace_bool)}, -- country
		{ name = translate("stageinfobox",9,womenrace_bool)}, -- start place
		{ name = translate("stageinfobox",10,womenrace_bool)}, -- endplace
		{ name = translate("stageinfobox",11,womenrace_bool)}, -- participants at start
		{ name = translate("stageinfobox",12,womenrace_bool)}, -- participants at end
		{ name = translate("stageinfobox",13,womenrace_bool)}, -- speed
		{ name = translate("stageinfobox",44,womenrace_bool)}, -- elevation
		{ name = translate("infobox",32,womenrace_bool), special = true}, -- special 1
		{ name = translate("infobox",33,womenrace_bool), special = true}, -- special 2
	}
	local others = {
		{ name = translate("infobox",29,womenrace_bool)}, -- picture
		{ name = translate("infobox",30,womenrace_bool)}, -- caption
		{ name = translate("infobox",31,womenrace_bool)}, -- map
		{ name = 'sectional'},             -- sectional
		{ name = translate("infobox",30,womenrace_bool)}, -- caption map
		{ name = translate("infobox",30,womenrace_bool)}, -- caption sectional
	}
			--begin of the function
	local t_P642 = {
			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'}
	}
	
	local localframe
	if string.match(frame:getParent():getTitle(), '%P+') == mw.site.namespaces.Template.name then
		localframe = frame:getParent()
	else
		localframe = frame
	end
	
	getLocalContent(details, localframe.args)
	getLocalContent(others, localframe.args)

	local timeOfRace
	local temp = firstValue(entityID, 'P31','id')
	icon = ''
	if temp and temp ~= 'Q18131152' then
		if temp=='Q2266066' or temp=='Q2348250' or temp=='Q485321' then 
			icon = " [[File:Cycling (track) pictogram.svg|35px]]"
		else 
			icon = " [[File:Cycling (road) pictogram.svg|35px]]" 
		end
		details[3].content = typeofstagelogo(entityID, true).." "..WPlinkpure(temp)
	end
	
	local name =  getLabelFallback(entityID, {wikilang, 'en', 'fr', 'de'}) 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, entityID)	

	--name
	if course==nil then
		temp = firstValue(entityID, 'P1545')
		if temp then
			details[2].content =getStageLabel(temp)
			raceId = firstValue(entityID, 'P361','id')
			if raceId then
				details[2].content = (details[2].content or '') .. '، '.. WPlinkpure(raceId)
				for k, p31 in statements(raceId, 'P31') do
					if race==nil then race={} end
					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(entityID, '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(entityID, true) end -- distance
	
	infoGetCountry(details,6, entityID, timeOfRace)
	infoGetStartEnd(details,7, entityID, timeOfRace)
	infoGetParticipants(details,9, entityID)
	if not details[11].content then details[11].content = getSpeed(entityID, true, kmdistance, 'P2417') end --speed
	if not details[12].content then 
		local elevation=getElevation(entityID) 
		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(entityID, '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, ..)
			if q.P642 and q.P642[1].snaktype == 'value' then
				for _, vv in pairs(q.P642) do
					local qual = vv.datavalue.value.id
					if qual~=nil and deprecated~='deprecated' and t_P642[qual] then
						if qual=="Q21686770" and t_s['results']['winner_fighting'][1] ~= "" then 
							t_P642[qual][2] = 'winner_fighting2' 
						end
						type_ofclas=t_P642[qual][1] --annex or gen
						name_ofclas=t_P642[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
	local listoftable = {'results','gen'}

	-- look into P2417, stage classification, then p2321 gen classification
	for ii, thistable in ipairs(listoftable) do
		if ii==1 then
			prop='P2417'
			order = {'first', 'second', 'third'}
		else
			prop='P2321'
			order = {'leader', 'deuxieme', 'troisieme'}
		end
		
		for _, p2417 in statements(entityID, 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

	listoftable={t_s.results,t_s.gen,t_s.annex}
	
	for _, thistable in ipairs(listoftable) 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,womenrace_bool))

-- 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 #fff2cc; background-color:#FFE7A0; text-align:center')
			:css('font-weight','bold')
			:wikitext(translate("stageinfobox",thistable.header,womenrace_bool))

			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,womenrace_bool)..')'
						end
					end
					if v['points'] then
						if v['points'] > 1 then 
							temp=translate("unit",7,womenrace_bool)
						else 
						    temp=translate("unit",6,womenrace_bool) 
						end 
						v['points'] = v['points']..temp
					end
					local title, k = string.gsub(translate("stageinfobox",v['translation'],womenrace_bool), " ", "&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:#fff2cc;text-align:" .. 
					textalign .. ";padding:0 2px 0 2px;white-space:nowrap")
				
					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'],womenrace_bool))
							else
								tCell:wikitext(number(v['genre'], key, wiki))
							end
						else
							if jerseyWPID=='' then
								temp=''
							else 
								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(entityID,true))
	wdDoc(tab, "d:Wikidata:WikiProject Cycling/Documentation/stageinfobox", translate("stageinfobox",39,womenrace_bool), frame.args[1])
	return tab
end

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

	local timeOfRace, errorMessage = getTimeOfRace(raceID)
	if not timeOfRace then return errorMessage end
	
	local womenrace_bool=isWomenrace(raceID)

	local teamCats = { -- {c,d,e} c = singular team type, d = plural team type, e = print order of the team types
		["Q6154783"]  = {4,5,1},   -- WorldTeam
		["Q80425135"] = {4,5,2},   -- UCI Women’s WorldTeam
		["Q20638319"] = {6,7,3},   -- ProTeam (2005-2014)
		["Q78464255"] = {6,7,4},   -- ProTeam (2020-)
		["Q382927"]   = {8,9,5},   -- UCI Professional Continental Team (2005-2019)
		["Q1756006"]  = {10,11,6}, -- UCI Continental Team
		["Q20639847"] = {16,17,7}, -- professional cycling team		
		["Q20653563"] = {20,21,8}, -- Groupe Sportif I
		["Q20653564"] = {22,23,9}, -- Groupe Sportif II
		["Q20653566"] = {24,25,10}, -- Groupe Sportif III	
		["Q2466826"]  = {28,29,11}, -- UCI Women’s Team
		["Q23726798"] = {12,13,12}, -- national cycling team
		["Q99658502"] = {12,13,13}, -- national cycling team "B"
		["Q20738667"] = {12,13,14}, -- national cycling team U23
		["Q54555994"] = {12,13,15}, -- national cycling team U19		
		["Q28492441"] = {12,13,16}, -- national cycling team with sponsor name
		["Q20652655"] = {18,19,17}, -- amateur cycling team
		["Q26849121"] = {30,31,18}, -- Women's amateur cycling team
		["Q20639848"] = {14,15,19}, -- club and region cycling team
		["Q20653570"] = {14,15,20}, -- club and 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, true)
			local flagImage = countryID and flag(countryID, timeOfRace) or ''
			teams[#teams + 1] = {flagImage .. ' ' .. teamLink, teamCat,
				teamCats[teamCat] and teamCats[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
		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[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, womenrace_bool) -- singular name
					else
						header_label = translate("headoftableIII",33, womenrace_bool) -- plural name
					end
					done=true
				end
			end
			
			if done==false then
				if count == 1 then
					header_label = translate("headoftableIII",teamCats[CatID][1], womenrace_bool) -- singular name
				else
					header_label = translate("headoftableIII",teamCats[CatID][2], womenrace_bool) -- 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, {wikilang, 'en', 'fr', 'de'})) 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 rgb(200,200,200)")
	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 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 = string.gsub(frame.args[1] or frame:getParent().args[1], "%c", ""),
		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=1000 --unlimited the whole team must be displayed
		}
	return new_classification(frame, s)
end

function p.pointsclassification(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 = string.gsub(frame.args[1] or frame:getParent().args[1], "%c", ""),
		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
		}
	return new_classification(frame, s)
end

function p.teamsclassificationbytime(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 = frame.args[1],
		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
	}
	return new_classification(frame, s)
end

function p.teamsclassificationbypoints(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 = frame.args[1],
		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
		}
	return new_classification(frame, s)
end

function p.stageclassification(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 = frame.args[1],
		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 = tonumber(frame.args[2]) == 0 and 0 or 1,
		max_rank_displayed=10
		}
	return new_classification(frame, s)
end

function p.generalclassification(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 = frame.args[1],
		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 = tonumber(frame.args[2]) == 0 and 0 or 1,
		max_rank_displayed=25,
		}
	return new_classification(frame, s)
end

function p.generalclassificationpoint(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 = frame.args[1],
		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 = tonumber(frame.args[2]) == 0 and 0 or 1,
		max_rank_displayed=25
		}
	return new_classification(frame, s)	
end		

function p.generalclassificationforttt(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 = frame.args[1],
		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 = tonumber(frame.args[2]) == 0 and 0 or 1,
		max_rank_displayed=10
	}
	return new_classification(frame, s)
end

function p.teamtimetrialclassification(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 = frame.args[1],
		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 = tonumber(frame.args[2]) == 0 and 0 or 1,
		max_rank_displayed=25
	}
	return new_classification(frame, s)
end

function p.mountainsclassification(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 = string.gsub(frame.args[1] or frame:getParent().args[1], "%c", ""),
		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
		}
	return new_classification(frame, s)
end

function p.sprintsclassification(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 = string.gsub(frame.args[1] or frame:getParent().args[1], "%c", ""),
		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
		}
	return new_classification(frame, s)
end

function p.bestyoungclassificationbypoints(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 = string.gsub(frame.args[1] or frame:getParent().args[1], "%c", ""),
		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
		}
	return new_classification(frame, s)
end

function p.bestyoungclassification(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 = string.gsub(frame.args[1] or frame:getParent().args[1], "%c", ""),
		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
		}
	return new_classification(frame, s)
end

function p.u23classification(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 = string.gsub(frame.args[1] or frame:getParent().args[1], "%c", ""),
		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
		}
	return new_classification(frame, s)
end

function p.combinationclassification(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 = string.gsub(frame.args[1] or frame:getParent().args[1], "%c", ""),
		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
		}
	return new_classification(frame, s)
end

function p.combativeclassification(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 = string.gsub(frame.args[1] or frame:getParent().args[1], "%c", ""),
		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
		}
	return new_classification(frame, s)
end

function p.custompointsclassification(frame)
	local team_title
	if frame.args[4] and string.find(frame.args[4],"{{{")==nil then team_title=string.gsub(frame.args[4], "%c", "") 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=string.gsub(frame.args[3], "%c", ""),
		item = string.gsub(frame.args[1] or frame:getParent().args[1], "%c", ""),
		property = string.gsub(frame.args[2], "%c", ""), -- 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
		}
	return new_classification(frame, s)
end

function p.customtimeclassification(frame)
	local team_title
	if frame.args[4] and string.find(frame.args[4],"{{{")==nil then team_title=string.gsub(frame.args[4], "%c", "") 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=string.gsub(frame.args[3], "%c", ""),
		item = string.gsub(frame.args[1] or frame:getParent().args[1], "%c", ""),
		property = string.gsub(frame.args[2], "%c", ""), -- 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
		}
	return new_classification(frame, s)
end

function new_classification(frame, s)
	local country = true
	for _, value in pairs(no_country_classification) do -- get data if country should be printed in this wiki
		if value == wiki then country = false end
	end
	local raceID = s.item
	local womenrace_bool=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, errorMessage = getTimeOfRace(raceID)
	if not timeOfRace then return errorMessage end

	local plus = ''
	if string.match(frame:getParent():getTitle(), '%P+') == mw.site.namespaces.Template.name
	then localframe = frame:getParent() else localframe = frame end
	if localframe.args[1] ~= nil then localframe.args[1] = string.gsub(localframe.args[1], "%c", "") end

	if localframe.args.country ~= nil then -- switch country column on or off in the article
		if localframe.args.country == 'true' then country = true end
		if localframe.args.country == 'false' then country = false end
	end
	local tableHeader2_size = #s.header_2
	
	local max_rank_displayed=s.max_rank_displayed
	if localframe.args['max_rank_displayed'] and localframe.args['max_rank_displayed'] ~= '' then
		max_rank_displayed=tonumber(localframe.args['max_rank_displayed'])
	end

	if s.header_1_text ==nil then s.header_1_text=translate(s.header_function,s.header_1,womenrace_bool) 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,womenrace_bool) 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; 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 and available_list) 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,womenrace_bool)
			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,womenrace_bool)--"HD","NP","DQ"
					elseif dnf=='Q54881674' or dnf=='Q7113430' then riderDNF =translate("startlist",7,womenrace_bool)
					elseif dnf=='Q1210382' then riderDNF =translate("startlist",8,womenrace_bool)
					elseif dnf=='Q1229261' then riderDNF =translate("startlist",9,womenrace_bool)
					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(m) or '')
				teamLink = getTeam(riderID, timeOfRace, q)
				countryID = getNationality(riderID, timeOfRace,q)
			end
			if countryID then
				flagLink = flag(countryID, timeOfRace)
				if available_list and country then
					if type(translations.list) == "function" then
						countryName = translations.list(countryID)
					end
					if countryName == '' then
						local label, lang = mw.wikibase.getLabelWithLang(countryID)
						--[[ Uses standard language fallback. Should not be nil, as all countries have English labels. ]]
						if lang == wikilang then
							countryName = label
						else
							countryName = label .. ' (' .. lang .. ')'
						end
					end
				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 bg_color_table[jersey] then
						bg_color = 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 not teamLink then teamLink = '' end
				if not available_list then
					tCell:wikitext(flagLink .. ' '.. riderLink .. jersey(h.jersey))
					if s.display_team~=false then
						tBody:tag('td'):wikitext(teamLink)
					end
				else
					if country == true 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)
					end
				end
			else --team
				if available_list==true and 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,womenrace_bool)
						else
							temp2=translate("unit",6,womenrace_bool)
						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,womenrace_bool)
					else
						temp2=translate("unit",6,womenrace_bool)
					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,womenrace_bool))
				end
			end
			
			if rank~='' and rank<=max_rank_displayed then --else no display
				if riderDNF=='' then
					t_Body[#t_Body + 1] = {(type(rank) == 'number') and rank or 999, tostring(tBody)}
				else --disqualified should be higher than not disqualified if the ranking was revided
					t_Body[#t_Body + 1] = {(type(rank) == 'number') and rank-0.1 or 999, 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))
	end
	
	--general table style and last line
	local tableStyle, tableNewline
	if localframe.args.newline == 'false' then -- parameter newline in WP article is 'false'
		tableStyle = "float:" .. floattable .. "; margin-right:0.5em; border:1px solid rgb(200,200,200)"
		tableNewline = ''
	end
	if localframe.args.newline == 'true' then -- parameter newline in WP article is 'true'
		tableStyle = "border:1px solid rgb(200,200,200)"
		tableNewline = '<br style="clear:left;">'
	end
	if localframe.args.newline == 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 rgb(200,200,200)"
			tableNewline = ''
		else
			tableStyle = "border:1px solid rgb(200,200,200)"
			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)
	return infobox_main(frame,0)
end

function p.infoboxseason(frame)
	return infobox_main(frame,1)
end

function p.infoboxChamp(frame)
	return infobox_main(frame,2)
end

function infobox_main(frame, selector)
	localframe = frame
	-- If true, winners will have Wikidata logos with link to Wikidata
	local WDlink_on = (wiki == "mk" or wiki == "ja")

	-- If true, winners will the team of the cyclist
	local team = true
	local details, others, winners
	
	local entityID = mw.text.trim(frame.args[1])
	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
	local womenrace_bool=isWomenrace(entityID)
	
	if selector==0 then --normal infobox
		details = {
			{ name = translate("infobox",2,womenrace_bool)}, -- course
			{ name = translate("infobox",3,womenrace_bool), name_plural = translate("infobox",4,womenrace_bool)}, -- competition
			{ name = translate("infobox",5,womenrace_bool)}, -- stages
			{ name = translate("infobox",6,womenrace_bool), name_plural = translate("infobox",7,womenrace_bool)}, -- date
			{ name = translate("infobox",8,womenrace_bool)}, -- distance
			{ name = translate("infobox",9,womenrace_bool), name_plural = translate("infobox",10,womenrace_bool)}, -- country
			{ name = translate("infobox",11,womenrace_bool)}, -- start place
			{ name = translate("infobox",12,womenrace_bool)}, -- endplace
			{ name = translate("infobox",13,womenrace_bool)}, -- teams
			{ name = translate("infobox",14,womenrace_bool)}, -- participants at start
			{ name = translate("infobox",15,womenrace_bool)}, -- participants at end
			{ name = translate("infobox",16,womenrace_bool)}, -- speed
			{ name = translate("infobox",43,womenrace_bool)}, -- elevation
			{ name = translate("infobox",17,womenrace_bool)}, -- cost
			{ name = translate("infobox",32,womenrace_bool), special = true}, -- special 1
			{ name = translate("infobox",33,womenrace_bool), special = true}, -- special 2
		}
	elseif selector==1 then  --season infobox
		details = {
			{ name = translate("infobox",46,womenrace_bool)}, -- edition (1)
			{ name = translate("infobox",3,womenrace_bool), name_plural = translate("infobox",4,womenrace_bool)}, -- competition (2)
			{ name = translate("infobox",6,womenrace_bool), name_plural = translate("infobox",7,womenrace_bool)}, -- date (3)
			{ name = translate("infobox",45,womenrace_bool)}, -- rasing (4)		
			{ name = translate("infobox",47,womenrace_bool), name_plural = translate("infobox",48,womenrace_bool)}, -- location (country) (5)
			{ name = translate("infobox",49,womenrace_bool), name_plural = translate("infobox",50,womenrace_bool)}, -- organizer (6)
			{ name = translate("infobox",63,womenrace_bool), name_plural = translate("infobox",63,womenrace_bool)}, -- team class (7)	
			{ name = translate("infobox",32,womenrace_bool), special = true}, -- special 1
			{ name = translate("infobox",33,womenrace_bool), special = true}, -- special 2
		}
	else  --champ
		 details = {
			{ name = translate("infobox",46,womenrace_bool)}, -- edition (1)
			{ name = translate("infobox",6,womenrace_bool), name_plural = translate("infobox",7,womenrace_bool)}, -- date (2)
			{ name = translate("infobox",9,womenrace_bool), name_plural = translate("infobox",10,womenrace_bool)}, -- country (3)	
			{ name = translate("infobox",67,womenrace_bool), name_plural = translate("infobox",68,womenrace_bool)}, -- location (city) (4)
			{ name = translate("infobox",61,womenrace_bool), name_plural = translate("infobox",62,womenrace_bool)}, -- arena / stadion (5)
			{ name = translate("infobox",60,womenrace_bool)}, -- medals (6)
			{ name = translate("infobox",13,womenrace_bool)}, -- team (7)			
			{ name = translate("infobox",49,womenrace_bool), name_plural = translate("infobox",50,womenrace_bool)}, -- organizer (8)
			{ name = translate("infobox",32,womenrace_bool), special = true}, -- special 1
			{ name = translate("infobox",33,womenrace_bool), special = true}, -- special 2
		}
	end
	
	others = {  --same for 3 infobox
		{ name = translate("infobox",29,womenrace_bool)}, -- picture
		{ name = translate("infobox",30,womenrace_bool)}, -- caption
		{ name = translate("infobox",31,womenrace_bool)}, -- map
		{ name = 'sectional'},             -- sectional
		{ name = translate("infobox",30,womenrace_bool)}, -- caption map
		{ name = translate("infobox",30,womenrace_bool)}, -- caption sectional
	}

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

	local localframe
	if string.match(frame:getParent():getTitle(), '%P+') == mw.site.namespaces.Template.name then
		localframe = frame:getParent()
	else
		localframe = frame
	end
	getLocalContent(details, localframe.args)
	getLocalContent(others, localframe.args)
	
	if selector==0 or selector==1 then
		getLocalContent(winners, localframe.args)
	end

	local timeOfRace, class
	local icon = (firstValue(entityID, 'P641','id') == "Q3609") and -- P641 is 'sport', Q3609 is 'road bicycle racing'
		' [[File:Cycling (road) pictogram.svg|35px]]' or ''

	local name =  getLabelFallback(entityID, {wikilang, 'en', 'fr', 'de'}) 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 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
			for _, p31 in statements(entityID, 'P31') do -- P31 is 'instance of'
				local instanceOf = p31.mainsnak.datavalue.value.id
				if instanceOf ~= 'Q27968055' and instanceOf ~= 'Q27020041' and class_dic[instanceOf] == nil 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
	if selector==0 then
		index_date=4
	elseif selector==1 then
		index_date=3
	else 
		index_date=2
	end

	if selector==0 or selector==1 then
		if not details[index_date].content then -- date
			local sTime = firstValue(entityID, 'P580', 'time') -- P580 is 'start time'
			local eTime = firstValue(entityID, 'P582', 'time') -- P582 is 'end time'
			if sTime and eTime then
				local startTime, endTime = getStartEndTime(sTime, eTime)
				details[index_date].content = startTime .. ' – ' .. endTime
				details[index_date].name = details[index_date].name_plural
				timeOfRace = eTime
			else
				-- This function give a format to dates when P585 (date) is used in a single day race
				local pTime = firstValue(entityID, 'P585', 'time') -- P585 is 'point in time'
				if pTime then
					details[index_date].content = funcDate(pTime, 'long')
					timeOfRace = pTime
				end
			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
			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,'P644',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,'P644',true) --org
		end
	end

	tab = infoInitTab("300px", name, icon)
	infoFillOthersDetails(tab, others, details,translate("infobox",1,womenrace_bool))
	
	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(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 white; background-color:'..backgroundColor..'; text-align:center')
			:css('font-weight','bold')
			:wikitext(translate("infobox",18,womenrace_bool))
			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,womenrace_bool), entityID)
	return tab
end

--=== H) race infobox
function p.raceinfobox(frame)
	localframe = frame
	local lang = contentLanguage
	-- If true, winners will have Wikidata logos with link to Wikidata
	local WDlink_on = (wiki == "mk" or wiki == "ja")
	
	local tRace = {race={
			raceId,
			raceDate,
			future,
			}, 
		  vainqueur= {},
		  lastEditionMonth, 
		  lastEditionYear, 
		  numberOfEditions,
		  lastLink,
		  nextLink,
		  lastWinner,
		  maxWinner,
		  }
	
	local entityID = mw.text.trim(frame.args[1])
	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		  
	local womenrace_bool=isWomenrace(entityID)
	
	local details = {
		{ name = translate("raceinfobox",4,womenrace_bool)}, -- sport
		{ name = translate("raceinfobox",5,womenrace_bool)}, -- creation date
		{ name = translate("raceinfobox",6,womenrace_bool)}, -- disparition date
		{ name = translate("raceinfobox",7,womenrace_bool)}, -- number of editions
		{ name = translate("raceinfobox",8,womenrace_bool)}, -- periodicity
		{ name = translate("raceinfobox",9,womenrace_bool)}, -- type , name_plural = translate("infobox",10)
		{ name = translate("raceinfobox",33,womenrace_bool), name_plural = translate("raceinfobox",34,womenrace_bool)},													--country
		{ name = translate("raceinfobox",10,womenrace_bool), name_plural = translate("raceinfobox",11,womenrace_bool)}, -- place
		{ name = translate("raceinfobox",12,womenrace_bool), name_plural = translate("raceinfobox",13,womenrace_bool)}, --org
		{ name = translate("raceinfobox",27,womenrace_bool), name_plural = translate("raceinfobox",28,womenrace_bool)}, --race director
		{ name = translate("raceinfobox",14,womenrace_bool)}, -- official web site
		{ name = translate("raceinfobox",15,womenrace_bool), name_plural = translate("raceinfobox",16,womenrace_bool)}, -- Cat
		{ name = translate("raceinfobox",17,womenrace_bool)}, -- circuit
	}
	
	local others = {
		{ name = translate("infobox",29,womenrace_bool)}, -- picture
		{ name = translate("infobox",30,womenrace_bool)}, -- caption
		{ name = translate("infobox",31,womenrace_bool)}, -- map
		{ name = 'sectional'},             -- sectional
		{ name = translate("infobox",30,womenrace_bool)}, -- caption map
		{ name = translate("infobox",30,womenrace_bool)}, -- caption sectional
	}

	local name =  getLabelFallback(entityID, {wikilang, 'en', 'fr', 'de'}) or ''
	infoGetOthers(others, entityID)	
		
	local localframe
	if string.match(frame:getParent():getTitle(), '%P+') == mw.site.namespaces.Template.name then
		localframe = frame:getParent()
	else
		localframe = frame
	end
	getLocalContent(details, localframe.args)
	getLocalContent(others, localframe.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'
		' [[File:Cycling (road) pictogram.svg|35px]]' 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, "Y" )
	end

	--disparition
	local disparition=firstValue(entityID, 'P576', 'time')
	if not details[3].content and disparition then
		details[3].content =  funcDate(disparition,"Y")
	end
	
	--populate tRace
	listOfWinners(entityID, tRace)
	
	--number of editions
	if not details[4].content and tRace.numberOfEditions and tRace.lastEditionYear then
		details[4].content = tostring(tRace.numberOfEditions).." (" .. translate("raceinfobox",31,womenrace_bool) .. " "..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,7, 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
	
	if not details[11].content then
		details[11].content = officialSite(entityID)
	end
	--Class and circuit	
	
	local classContent, circuitLink, numberClass= getClass(entityID)
	if not details[12].content then
		details[12].content = classContent
		if numberClass >1 then
	 		details[12].name = details[12].name_plural
		end
 	end
 	
 	if not details[13].content then
		details[13].content = circuitLink
	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,womenrace_bool),"260px")
	if not listOfNamesAtBottom then
		if listOfNames and #listOfNames>1 then
			tab:node(addATitle(translate("raceinfobox",18,womenrace_bool)))  
			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,womenrace_bool),"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,womenrace_bool)))  
			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,womenrace_bool)))
		if (tRace.lastWinner and tRace.lastWinner~='') then
			tab:node(addARow(translate("raceinfobox",21,womenrace_bool),tRace.lastWinner))
		end
		if (tRace.maxWinner and tRace.maxWinner~='') then
			tab:node(addARow(translate("raceinfobox",22,womenrace_bool),tRace.maxWinner))
		end
	end

	if tRace.nextLink or tRace.lastLink then
		tab:node(addATitle(translate("raceinfobox",23,womenrace_bool)))
		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,womenrace_bool)..
			":<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,womenrace_bool)..
		    ":<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,womenrace_bool), entityID)
	return tab
end

--=== I) Team roster
function p.teamroster(frame)
	localframe=frame
	local squadID
	if frame.args[1] then squadID = string.gsub(frame.args[1], "%c", "") end
	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, startOfSeason, 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 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 string.match(frame:getParent():getTitle(), '%P+') == mw.site.namespaces.Template.name
	then localframe = frame:getParent() else localframe = frame end
	if localframe.args[2] ~= nil then
		if mw.ustring.find(mw.ustring.lower(localframe.args[2]), "sort") then sort = true else sort = false end
	end
	if wiki == "lv" or wiki == "mk" or wiki == "ru" then sort = true end

	local womenrace_bool=isWomenrace(squadID)
	local temp = firstValue(squadID, 'P361', 'id')
	if temp then teamID = temp end

	temp = firstValue(squadID, 'P580', 'time')
	if temp then
		startOfSeason = temp
	else
		local Sitelink=getSitelinkFallback(squadID,{'en', 'fr', 'de'})
		if Sitelink == nil then return '> Wikidata is missing data about the start time (P580) and end time (P582) of the season'
		else startOfSeason = '+'..string.match(Sitelink, '%d%d%d%d' ) ..'-01-01T00:00:00Z'
		end
	end

	for _, p527 in statements(squadID, '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)

		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)

					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 and #riderTablecorrect~=0 and #riderTablenotcorrect~=0 then -- It was
	if sort == true and #riderTablecorrect==0 and #riderTablenotcorrect==0 then -- replaced with this to display the team roster in the ru-wiki
		table.sort(riderTablecorrect, function(a,b) return a[1]<b[1] end)
		table.sort(riderTablenotcorrect, function(a,b) return a[1]<b[1] 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(frame.args[1]..'#P527'))
	if arwiki_totemplate then wd_link = wdLink(frame.args[1] .. '#P527') end
	local outTable = mw.html.create('table')
	                        :addClass('sortable')
	                        :attr('cellpadding', '2')
	                        :attr('cellspacing', '0')
	                        :css('border' , '1px solid rgb(200,200,200)')
	                        :css('padding', '3px')
	local th_colspan = 4
	if wiki == "ar" then th_colspan = 5 end
	outTable:tag('tr'):css('line-height','1.8em')
	    :css('background-color',backgroundColor)
	    :tag('th'):attr('colspan', th_colspan):cssText('text-align:center;white-space:nowrap')
		:wikitext(tostring(wd_link))
	    :wikitext(translate("getSquadTableColumn",7,womenrace_bool))
	local header = outTable:tag('tr')
	header:tag('th'):cssText('text-align:center;padding:2px 20px 2px 2px;white-space:nowrap'):wikitext(translate("getSquadTableColumn",1,womenrace_bool))
	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,womenrace_bool))
	if available_list and wiki ~= 'lv' then
	    header:tag('th'):cssText('text-align:center;padding:2px 20px 2px 2px;white-space:nowrap'):wikitext(translate("getSquadTableColumn",6,womenrace_bool))
	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,womenrace_bool))
	else
		header:tag('th'):cssText('text-align:center;padding:2px 20px 2px 2px;white-space:nowrap'):wikitext(translate("getSquadTableColumn",3,womenrace_bool))
	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 available_list or wiki == 'lv' 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..frame.args[1]..'|'..translate("getSquadTableColumn",4,womenrace_bool)..']]'
				if wiki == "ar" then note = '، [[#tr_'..i..frame.args[1]..'|'..translate("getSquadTableColumn",4,womenrace_bool)..']]' 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..frame.args[1]..'|'..translate("getSquadTableColumn",4,womenrace_bool)..']]'.. ')')
		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(frame:expandTemplate{ title = 'Template:Birth date and age2', args = { beginYear, beginMonth, beginDay, endYear, endMonth, endDay } })
		else
			tCell:wikitext(funcDate(v['riderBirthday'] or '', 'long'))
			if available_list 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
		else
			if 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
		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,womenrace_bool)..': '.. v['riderName'].. temp
			else
				tableEndText = tableEndText.. '<span style="color:white">'.. translate("getSquadTableColumn",5,womenrace_bool)..': </span>'.. riderName.. temp
			end
			iii = iii + 1
			if riderRef ~= nil then tableEndText = tableEndText..
				frame:extensionTag{name='ref', content=v['riderRef'], args = {name='tr_'..iii..frame.args[1]}} end
			tableEndText = tableEndText.. '<br>'
		end
	end
	if labelMissing then outTable:wikitext(getMissingLabelTrackingCategory()) end
	
	local UCIlink
	if wiki=="fr" then
		UCIlink="https://www.uci.org/fr/route/%C3%A9quipe"
	else
		UCIlink="https://www.uci.org/road/teams"
	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(translate("race_reference", 1,womenrace_bool).."["..UCIlink..' UCI]')
	
	return tostring(outTable)..tableEndText
end

--== J) List of winners ==
function p.listofwinners(frame)
	local winnersProperty = {'Q20882667','Q20882668','Q20882669'}
	local display_team = false -- display of a rider without a team
	if tonumber(frame.args[5]) ==1 then display_team = true end -- display of the rider with the team
	local s = {
		countryflag=true,
		beginyear=tonumber(frame.args[2]),			
		endyear=tonumber(frame.args[3]),
		shapka=tonumber(frame.args[4]),
		display_team=display_team,		
		winnersProperty=winnersProperty,
		custom=false
	}
	return listofwinners_main(frame, s)
end

function p.listofwinnersyoung(frame)
	local winnersProperty = {'Q20883139','Q72099969','Q72099972'}
	local display_team = false -- display of a rider without a team
	if tonumber(frame.args[4]) ==1 then display_team = true end -- display of the rider with the team
	local s = {
		countryflag=true,
		beginyear=tonumber(frame.args[2]),			
		endyear=tonumber(frame.args[3]),
		shapka=tonumber(frame.args[4]),
		display_team=tonumber(frame.args[5]), -- since the answer is "args[4]"		
		winnersProperty=winnersProperty,
		custom=false
		}
	return listofwinners_main(frame, s)
end

function p.listofwinnersChamp(frame)
	local winnersProperty = {'Q20882667','Q20882668','Q20882669'}
	local s = {
		countryflag=false,
		beginyear=tonumber(frame.args[2]),			
		endyear=tonumber(frame.args[3]),
		shapka=tonumber(frame.args[4]),
		winnersProperty=winnersProperty,
		display_team = false,
		custom=false
		}
	return listofwinners_main(frame, s)
end

--listofwinnerssecondpart and so on can be coded with p.listofwinners
function p.listofwinnersnowiki(frame)
	local winnersProperty = {'Q20882667','Q20882668','Q20882669'}
	local display_team = false -- display of a rider without a team
	if tonumber(frame.args[5]) ==1 then display_team = true	end -- display of the rider with the team
	local s = {
		countryflag=true,
		beginyear=tonumber(frame.args[2]),			
		endyear=tonumber(frame.args[3]),
		shapka=tonumber(frame.args[4]),
		display_team=display_team, -- since the answer is "args[4]"		
		winnersProperty=winnersProperty,
		custom=false
	}
	return frame:extensionTag{ name = 'nowiki', content = listofwinners_main(frame, s)}
end

function p.listofwinnersteamofpoint(frame)
	local winnersProperty = {'Q27104269','Q72065970','Q72065977'}
	local display_team = false -- display of a rider without a team
	if tonumber(frame.args[5]) ==1 then display_team = true end -- display of the rider with the team
	local s = {
		countryflag=true,
		beginyear=tonumber(frame.args[2]),			
		endyear=tonumber(frame.args[3]),
		shapka=tonumber(frame.args[4]),
		display_team=display_team, -- since the answer is "args[4]"		
		winnersProperty=winnersProperty,
		custom=false
		}
	return listofwinners_main(frame, s)
end

function p.listofwinnersGSI(frame)
	local winnersProperty = {'Q98959152','Q98959192','Q98959196'}
	local display_team = false -- display of a rider without a team
	if tonumber(frame.args[5]) ==1 then display_team = true end -- display of the rider with the team
	local s = {
		countryflag=true,
		beginyear=tonumber(frame.args[2]),			
		endyear=tonumber(frame.args[3]),
		shapka=tonumber(frame.args[4]),
		display_team=display_team, -- since the answer is "args[4]"		
		winnersProperty=winnersProperty,
		custom=false
		}
	return listofwinners_main(frame, s)
end

function p.listofwinnersGSII(frame)
	local winnersProperty = {'Q98959153','Q98959194','Q98959197'}
	local display_team = false -- display of a rider without a team
	if tonumber(frame.args[5]) ==1 then display_team = true end -- display of the rider with the team
	local s = {
		countryflag=true,
		beginyear=tonumber(frame.args[2]),			
		endyear=tonumber(frame.args[3]),
		shapka=tonumber(frame.args[4]),
		display_team=display_team, -- since the answer is "args[4]"		
		winnersProperty=winnersProperty,
		custom=false
		}
	return listofwinners_main(frame, s)
end

function p.listofwinnersGSIII(frame)
	local winnersProperty = {'Q98959155','Q98959195','Q98959198'}
	local display_team = false -- display of a rider without a team
	if tonumber(frame.args[5]) ==1 then display_team = true end -- display of the rider with the team
	local s = {
		countryflag=true,
		beginyear=tonumber(frame.args[2]),			
		endyear=tonumber(frame.args[3]),
		shapka=tonumber(frame.args[4]),
		display_team=display_team, -- since the answer is "args[4]"		
		winnersProperty=winnersProperty,
		custom=false
		}
	return listofwinners_main(frame, s)
end

function p.listofwinnerscountry(frame)
	local winnersProperty = {'Q72068715','Q72068718','Q72068721'}
	local display_team = false -- display of a rider without a team
	if tonumber(frame.args[5]) ==1 then display_team = true end -- display of the rider with the team
	local s = {
		countryflag=true,
		beginyear=tonumber(frame.args[2]),			
		endyear=tonumber(frame.args[3]),
		shapka=tonumber(frame.args[4]),
		display_team=display_team, -- since the answer is "args[4]"		
		winnersProperty=winnersProperty,
		custom=false
		}
	return listofwinners_main(frame, s)
end

function p.listofwinnerscountryU23(frame)
	local winnersProperty = {'Q72068724','Q72068725','Q72068729'}
	local display_team = false -- display of a rider without a team
	if tonumber(frame.args[5]) ==1 then display_team = true end -- display of the rider with the team
	local s = {
		countryflag=true,
		beginyear=tonumber(frame.args[2]),			
		endyear=tonumber(frame.args[3]),
		shapka=tonumber(frame.args[4]),
		display_team=display_team, -- since the answer is "args[4]"		
		winnersProperty=winnersProperty,
		custom=false
		}
	return listofwinners_main(frame, s)
end

function p.listofwinnerscustom(frame)
	local winnersProperty ={}
	--general
	if frame.args[5] ~= nil and tonumber(frame.args[5]) ==1 then table.insert( winnersProperty,'Q20882667') end
	--podium
	if frame.args[6] ~= nil and tonumber(frame.args[6]) ==1 then 
		table.insert( winnersProperty,'Q20882668') 
		table.insert( winnersProperty,'Q20882669') 
	end
	--points
	if frame.args[7] ~= nil and tonumber(frame.args[7]) ==1 then table.insert( winnersProperty, 'Q20883007' ) end
	--mounstain
	if frame.args[8] ~= nil and tonumber(frame.args[8]) ==1 then table.insert( winnersProperty, 'Q20883212' ) end
	-- sprints
	if frame.args[9] ~= nil and tonumber(frame.args[9]) ==1 then table.insert( winnersProperty, 'Q20883328' ) end
	-- youth
	if frame.args[10] ~= nil and tonumber(frame.args[10]) ==1 then table.insert( winnersProperty, 'Q20883139' ) end
	-- supercombativity
	if frame.args[11] ~= nil and tonumber(frame.args[11]) ==1 then table.insert( winnersProperty, 'Q101246973' ) end
	-- combativity
	if frame.args[11] ~= nil and tonumber(frame.args[11]) ==1 then table.insert( winnersProperty, 'Q20893983' ) end
	-- volante
	if frame.args[12] ~= nil and tonumber(frame.args[12]) ==1 then table.insert( winnersProperty, 'Q27067359' ) end
	-- regularity 
	if frame.args[13] ~= nil and tonumber(frame.args[13]) ==1 then table.insert( winnersProperty, 'Q27067170' ) end
	-- combination
	if frame.args[14] ~= nil and tonumber(frame.args[14]) ==1 then table.insert( winnersProperty, 'Q20893979' ) end
	-- breakaway
	if frame.args[15] ~= nil and tonumber(frame.args[15]) ==1 then table.insert( winnersProperty, 'Q27907715' ) end
	-- azzurri
	if frame.args[16] ~= nil and tonumber(frame.args[16]) ==1 then table.insert( winnersProperty, 'Q27907747' ) end
	-- rookie
	if frame.args[17] ~= nil and tonumber(frame.args[17]) ==1 then table.insert( winnersProperty, 'Q28092831' )	end 
	-- teams
	if frame.args[18] ~= nil and tonumber(frame.args[18]) ==1 then table.insert( winnersProperty, 'Q20882921' )	end
	 -- teamspoints
	if frame.args[19] ~= nil and tonumber(frame.args[19]) ==1 then table.insert( winnersProperty, 'Q27104269' ) end	
	-- amateur
	if frame.args[20] ~= nil and tonumber(frame.args[20]) ==1 then table.insert( winnersProperty, 'Q61976850' ) end	
	 --nationality
	if frame.args[21] ~= nil and tonumber(frame.args[21]) ==1 then table.insert( winnersProperty, 'Q61976872' ) end	
	-- country
	if frame.args[22] ~= nil and tonumber(frame.args[22]) ==1 then table.insert( winnersProperty, 'Q72068715' ) end	
	-- country U-23
	if frame.args[23] ~= nil and tonumber(frame.args[23]) ==1 then table.insert( winnersProperty, 'Q72068724' ) end	
	local s = {
		countryflag=true,
		beginyear=tonumber(frame.args[2]),			
		endyear=tonumber(frame.args[3]),
		shapka=tonumber(frame.args[4]),
		display_team = false,
		winnersProperty=winnersProperty,
		custom=true
		}
	return listofwinners_main(frame, s)
end

function listofwinners_main(frame, s)
	local rows = {}
	frame.args[1] = string.gsub(frame.args[1], "%c", "")
	local raceID = frame.args[1]
	local WDlink_on = (wiki == "mk") or (wiki == "ja") or (wiki == "ru")
		-- WDlink_on is used to decide if a Wikidata logo will be shown
	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 womenrace_bool=isWomenrace(raceID)
	
	if s.custom then
		titletable={
		[ 'Q20882667' ]=translate("listofwinners",2, womenrace_bool), -- winner
		[ 'Q20882668' ]=translate("listofwinners",3, womenrace_bool), -- second		
		[ 'Q20882669' ]=translate("listofwinners",4, womenrace_bool), -- third		
		[ 'Q20883007' ]=translate("listofwinners",5, womenrace_bool), -- points  
		[ 'Q20883212' ]=translate("listofwinners",6, womenrace_bool), -- mountains
		[ 'Q20883328' ]=translate("listofwinners",7, womenrace_bool), -- sprints
		[ 'Q20883139' ]=translate("listofwinners",8, womenrace_bool), -- youth
		[ 'Q101246973' ]=translate("listofwinners",9, womenrace_bool), -- supercombativity		
		[ 'Q20893983' ]=translate("listofwinners",9, womenrace_bool), -- combativity
		[ 'Q20893979' ]=translate("listofwinners",10, womenrace_bool), -- combination
		[ 'Q20882921' ]=translate("listofwinners",11, womenrace_bool), -- teams
		[ 'Q27067359' ]=translate("listofwinners",12, womenrace_bool), -- volantes
		[ 'Q27067170' ]=translate("listofwinners",13, womenrace_bool), -- regularity
		[ 'Q27104269' ]=translate("listofwinners",14, womenrace_bool), -- teamspoints
		[ 'Q27907715' ]=translate("listofwinners",15, womenrace_bool), -- breakaway
		[ 'Q27907747' ]=translate("listofwinners",16, womenrace_bool), -- azzurri
		[ 'Q28092831' ]=translate("listofwinners",17, womenrace_bool), -- rookie
		[ 'Q61976850' ]=translate("listofwinners",18, womenrace_bool), -- amateur
		[ 'Q61976872' ]=translate("listofwinners",19, womenrace_bool), -- nationality
		[ 'Q72068715' ]=translate("listofwinners",23, womenrace_bool), -- winner country
		[ 'Q72068724' ]=translate("listofwinners",24, womenrace_bool), -- winner countryU23
	}
	else --main
	     titletable={
-- winner:
		[ 'Q20882667' ]=translate("listofwinners",2, womenrace_bool), -- winner
		[ 'Q20883007' ]=translate("listofwinners",2, womenrace_bool), -- points  
		[ 'Q20883212' ]=translate("listofwinners",2, womenrace_bool), -- mountains
		[ 'Q20883328' ]=translate("listofwinners",2, womenrace_bool), -- sprints
		[ 'Q20883139' ]=translate("listofwinners",2, womenrace_bool), -- youth (time or point)
		[ 'Q101246973' ]=translate("listofwinners",2, womenrace_bool), -- supercombativity		
		[ 'Q20893983' ]=translate("listofwinners",2, womenrace_bool), -- combativity
		[ 'Q20893979' ]=translate("listofwinners",2, womenrace_bool), -- combination
		[ 'Q20882921' ]=translate("listofwinners",2, womenrace_bool), -- team (time)
		[ 'Q27067359' ]=translate("listofwinners",2, womenrace_bool), -- volantes
		[ 'Q27067170' ]=translate("listofwinners",2, womenrace_bool), -- regularity
		[ 'Q27104269' ]=translate("listofwinners",2, womenrace_bool), -- teampoints
		[ 'Q27907715' ]=translate("listofwinners",2, womenrace_bool), -- breakaway
		[ 'Q27907747' ]=translate("listofwinners",2, womenrace_bool), -- azzurri
		[ 'Q28092831' ]=translate("listofwinners",2, womenrace_bool), -- rookie
		[ 'Q61976850' ]=translate("listofwinners",2, womenrace_bool), -- amateur
		[ 'Q61976872' ]=translate("listofwinners",2, womenrace_bool), -- nationality
		[ 'Q72068715' ]=translate("listofwinners",2, womenrace_bool), -- winner country
		[ 'Q72068724' ]=translate("listofwinners",2, womenrace_bool), -- winner countryU23
		[ 'Q98959152' ]=translate("listofwinners",2, womenrace_bool), -- winner team GS-I
		[ 'Q98959153' ]=translate("listofwinners",2, womenrace_bool), -- winner team GS-II
		[ 'Q98959155' ]=translate("listofwinners",2, womenrace_bool), -- winner team GS-III		
-- 2 place:
		[ 'Q20882668' ]=translate("listofwinners",3, womenrace_bool), -- second		
		[ 'Q72065970' ]=translate("listofwinners",3, womenrace_bool), -- second teampoints
		[ 'Q72099969' ]=translate("listofwinners",3, womenrace_bool), -- youth (time or point)		
		[ 'Q72068718' ]=translate("listofwinners",3, womenrace_bool), -- second country
		[ 'Q72068725' ]=translate("listofwinners",3, womenrace_bool), -- second countryU23
		[ 'Q98959192' ]=translate("listofwinners",3, womenrace_bool), -- second team GS-I
		[ 'Q98959194' ]=translate("listofwinners",3, womenrace_bool), -- second team GS-II
		[ 'Q98959195' ]=translate("listofwinners",3, womenrace_bool), -- second team GS-III		
-- 3 place:
		[ 'Q20882669' ]=translate("listofwinners",4, womenrace_bool), -- third	
		[ 'Q72065977' ]=translate("listofwinners",4, womenrace_bool), -- third teampoints	
		[ 'Q72099972' ]=translate("listofwinners",4, womenrace_bool), -- youth (time or point)		
		[ 'Q72068721' ]=translate("listofwinners",4, womenrace_bool), -- third country
		[ 'Q72068729' ]=translate("listofwinners",4, womenrace_bool), -- third countryU23
		[ 'Q98959196' ]=translate("listofwinners",4, womenrace_bool), -- third team GS-I
		[ 'Q98959197' ]=translate("listofwinners",4, womenrace_bool), -- third team GS-II
		[ 'Q98959198' ]=translate("listofwinners",4, womenrace_bool), -- third team GS-III		
	}
	end

	--localframe defined as global for references
	if string.match(frame:getParent():getTitle(), '%P+') == mw.site.namespaces.Template.name then
		localframe = frame:getParent()
	else
		localframe = frame
	end
	if localframe.args[1] then
		localframe.args[1] = string.gsub(localframe.args[1], "%c", "")
	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 localframe.args[2] then
		for num, _ in pairs(localframe.args) do
			if num > 1 and mw.ustring.find(mw.ustring.lower(localframe.args[num]), 'row') then
				local _, _, kebeginYear, val = mw.ustring.find(localframe.args[num], "([^:]+)%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) --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' then --race cancelled
							local cancelledlabel = getLabelFallback('Q30108381', {wikilang, 'en', 'fr', 'de'})
							tCell=mw.html.create('td'):attr('colspan','4')
							:cssText('text-align:center; font-style: italic')
							:wikitext(cancelledlabel)
							tCellstr=tostring(tCell)
						else
							winner(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)
	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,womenrace_bool)) --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 p.listofstages(frame)
	-- WDlink_on is used to decide if a Wikidata logo will be shown
	local WDlink_on = wiki == "mk" or wiki == "ja"
	local WPcontent = {}
	local raceID = frame.args[1]
	local thereiselevation=false
	local result, tableBody

	local localframe
	if string.match(frame:getParent():getTitle(), '%P+') == mw.site.namespaces.Template.name then
		localframe = frame:getParent()
	else
		localframe = frame
	end
	if localframe.args[1] then
		localframe.args[1] = string.gsub(localframe.args[1], "%c", "")
	end
	local womenrace_bool=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 localframe.args[2] 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(localframe.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) or ''
			
			local sPointID = firstValue(stageID, 'P1427', 'id')
			local sPoint = (sPointID and getPlaceLink(sPointID, timeOfRace)) or ''

			if sPointID and not onecountry and timeOfRace then
				local startcountry= getStatementForTime(sPointID, 'P17',timeOfRace)
				if startcountry then
					local startcountryID = startcountry.mainsnak.datavalue.value.id
					if firstcountryID ~= startcountryID then
						local sflag = flag(startcountryID, timeOfRace)
						sPoint = sflag.." "..sPoint
					end
				end
			end

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

			if dPointID and not onecountry and timeOfRace then
				local dcountry= getStatementForTime(dPointID, 'P17',timeOfRace)
				if dcountry then
					local dcountryID = dcountry.mainsnak.datavalue.value.id
					if firstcountryID ~= dcountryID then
						local dflag = flag(dcountryID, timeOfRace)
						dPoint = dflag.." "..dPoint
					end
				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(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"), "#" .. translate("func_prologue")
			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] = {
				tonumber(sNumber) or 0, sLetter,  -- Sort keys
				sLink, sDate, WDLink, sPoint, dPoint, sType, sDistance, sElevation, winners['Q20882747'], tempoverall -- Content
			}
		end
	end

	table.sort(rows, function(a, b)
		if a[1] ~= b[1] then return a[1] < b[1] end
		return a[2] < b[2]
	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')
	tRow:tag('th'):css('white-space','nowrap')
	:wikitext(Id..translate("headoftable",1,womenrace_bool))
	tRow:tag('th'):wikitext(translate("headoftable",2,womenrace_bool))
	tRow:tag('th'):wikitext(translate("headoftable",3,womenrace_bool))
	tRow:tag('th'):css('color',backgroundColor):wikitext("type")
	tRow:tag('th'):wikitext(translate("headoftable",4,womenrace_bool))
	if thereiselevation then 
		tRow:tag('th'):wikitext(translate("headoftable",7,womenrace_bool))
	end
	tRow:tag('th'):wikitext(translate("headoftable",5,womenrace_bool))
	tRow:tag('th'):wikitext(translate("headoftable",6,womenrace_bool))
	local header = tostring(tRow)
	for num, row in pairs(rows) do
		local sLink, sDate, WDLink, sPoint, dPoint, sType, sDistance, sElevation, sSWin, sGWin
			= row[3], row[4], row[5], row[6], row[7], row[8], row[9], row[10], row[11], row[12]

		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(sLink)
		tCell:tag('span'):css('white-space','nowrap'):wikitext("&nbsp;".. WDLink )
		tRow:tag('td'):css('white-space','nowrap'):cssText("text-align:right; padding-right:0px")
		:wikitext(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(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(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(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)
	-- WDlink_on is used to decide if a Wikidata logo will be shown
	local stageID = frame.args[1]
	-- from to 
	local p = mw.wikibase.getBestStatements(stageID, 'P1427') -- P1427 is 'start point'
	local sPointID = p[1] and p[1].mainsnak.snaktype == 'value' and p[1].mainsnak.datavalue.value.id
	local sPoint = sPointID and getPlaceLink(sPointID) or ''
	p = mw.wikibase.getBestStatements(stageID, 'P1444') -- P1444 is 'destination point'
	local dPointID = p[1] and p[1].mainsnak.snaktype == 'value' and p[1].mainsnak.datavalue.value.id
	local dPoint = dPointID and getPlaceLink(dPointID) or ''

	local sDistance = getDistance(stageID, true) or ''
	-- find the type of stage
	local sType = typeofstagelogo(stageID)
	
	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 womenrace_bool=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 womenNcRoadtable[v] or menNcRoadtable[v] then
				 road = true
				 roadtemp=true
			elseif womenNcITTtable[v] or 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,womenrace_bool).." "..translate("startlist",12,womenrace_bool).." "..translate("startlist",11,womenrace_bool)..")</small>"
	elseif road then
		result = "<small>("..translate("startlist",10,womenrace_bool)..")</small>"
	elseif ITT then
		result = "<small>("..translate("startlist",11,womenrace_bool)..")</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.P642 and q.P642[1].snaktype == 'value' then
				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 bg_color_table[thisjersey] then
					bg_color = 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 = frame.args[1]
	local womenrace_bool=isWomenrace(raceID)
	local sType
	local localframe
	if string.match(frame:getParent():getTitle(), '%P+') == mw.site.namespaces.Template.name then
		localframe = frame:getParent()
	else
		localframe = frame
	end
	if localframe.args[1] then
		localframe.args[1] = string.gsub(localframe.args[1], "%c", "")
	end

	--link for Grand Tour
	local GTid={['Q33881']=true,['Q33861']=true,['Q33937']=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
			Sitelink = wikibase.getSitelink('Q2267539')
			if Sitelink then overallname="[["..Sitelink .."|"..translate("headoftableII",9,womenrace_bool).."]]" end
			Sitelink = wikibase.getSitelink('Q175399')
			if Sitelink then pointsname="[["..Sitelink .."|"..translate("infobox",22,womenrace_bool).."]]" end
			Sitelink = wikibase.getSitelink('Q927157')
			if Sitelink then mountainname="[["..Sitelink .."|"..translate("infobox",23,womenrace_bool).."]]" end
			Sitelink = wikibase.getSitelink('Q641662')
			if Sitelink then youngname="[["..Sitelink .."|"..translate("infobox",25,womenrace_bool).."]]" end
			Sitelink = wikibase.getSitelink('Q1436680')
			if Sitelink then teamname="[["..Sitelink .."|"..translate("infobox",28,womenrace_bool).."]]" end

			Sitelink = wikibase.getSitelink('Q2094179')
			if Sitelink then combativityname="[["..Sitelink .."|"..translate("infobox",26,womenrace_bool).."]]" end

			Sitelink = wikibase.getSitelink('Q2094179')
			if Sitelink then supercombativityname="[["..Sitelink .."|"..translate("infobox",26,womenrace_bool).."]]" end


			Sitelink = wikibase.getSitelink('Q1835362')
			if Sitelink then combinedname="[["..Sitelink .."|"..translate("infobox",27,womenrace_bool).."]]" end
		elseif thisGT=='Q33861' then
			Sitelink = wikibase.getSitelink('Q1164275')
			if Sitelink then overallname="[["..Sitelink .."|"..translate("headoftableII",9,womenrace_bool).."]]" end
			Sitelink = wikibase.getSitelink('Q641083')
			if Sitelink then pointsname="[["..Sitelink .."|"..translate("infobox",22,womenrace_bool).."]]" end
			Sitelink = wikibase.getSitelink('Q641060')
			if Sitelink then mountainname="[["..Sitelink .."|"..translate("infobox",23,womenrace_bool).."]]" end
			Sitelink = wikibase.getSitelink('Q641662')
			if Sitelink then youngname="[["..Sitelink .."|"..translate("infobox",25,womenrace_bool).."]]" end
		else
			Sitelink = wikibase.getSitelink('Q2532554')
			if Sitelink then overallname="[["..Sitelink .."|"..translate("headoftableII",9,womenrace_bool).."]]" end
			Sitelink = wikibase.getSitelink('Q2241695')
			if Sitelink then pointsname="[["..Sitelink .."|"..translate("infobox",22,womenrace_bool).."]]" end
			Sitelink = wikibase.getSitelink('Q1118296')
			if Sitelink then mountainname="[["..Sitelink .."|"..translate("infobox",23,womenrace_bool).."]]" end
			Sitelink = wikibase.getSitelink('Q2330008')
			if Sitelink then combinedname="[["..Sitelink .."|"..translate("infobox",27,womenrace_bool).."]]" end
		end
	end

	local winners = {
		{ name = translate("infobox",19,womenrace_bool), QID = 'Q20882747'}, -- stage
		{ name = overallname or translate("headoftableII",9,womenrace_bool), QID = 'Q20882763' }, -- overall
		{ name = pointsname or translate("infobox",22,womenrace_bool), QID = 'Q20883008' }, -- points
		{ name = mountainname or translate("infobox",23,womenrace_bool), QID = 'Q20883213' }, -- mountains
		{ name = translate("infobox",24,womenrace_bool), QID= 'Q20883329' }, -- sprints
		{ name = youngname or translate("infobox",25,womenrace_bool), QID='Q20883140' }, -- youth
		{ name = combativityname or translate("infobox",26,womenrace_bool), QID= 'Q21686770' }, -- combativity
		{ name = supercombativityname or translate("infobox",26,womenrace_bool), QID= 'Q20893984' }, -- combativity
		{ name = translate("infobox",35,womenrace_bool), QID= 'Q27104688' }, -- volantes
		{ name = translate("infobox",36,womenrace_bool), QID= 'Q27104684' }, -- regularity
		{ name = combinedname or translate("infobox",27,womenrace_bool), QID='Q20965880' }, -- combination
		{ name = translate("infobox",38,womenrace_bool), QID='Q27907714' }, -- breakaway
		{ name = translate("infobox",39,womenrace_bool), QID='Q27907748' }, -- azzurri
		{ name = translate("infobox",40,womenrace_bool), QID='Q28096780'}, -- rookie
		{ name = teamname or translate("infobox",28,womenrace_bool), QID='Q20882922' }, -- teams
		{ name = translate("infobox",37,womenrace_bool), QID ='Q27104271' }, -- teamspoints
		{ name = translate("infobox",41,womenrace_bool), QID ='Q61976847' },-- amateur
		{ name = translate("infobox",42,womenrace_bool), 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"), "#" .. translate("func_prologue")
			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(stageID, win, timeOfRace, false, WDlink_on, false, false) --fill win table
			if ii==1 then --only first stage
				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==1 then --read the jersey in the first stage of a race
						columntable[v.QID].jersey=jerseytable[v.QID]
						columntable[v.QID].bg_color=bgcolortable[v.QID]
					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(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,womenrace_bool), 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')
	tRow:tag('th'):css('white-space','nowrap')
	:wikitext(((not WDlink_on and wdLink(string.gsub(raceID, '%s', '') .. "#P527")) or "")..
	translate("headoftable",1,womenrace_bool))
	
	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,womenrace_bool)) --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,womenrace_bool)) --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 IDtemp
	if frame.args[1] ~= nil then
		IDtemp=string.gsub(frame.args[1], "%c", "")
	end
	local womenrace_bool=isWomenrace(IDtemp)
	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=IDtemp,
		title="Start list",
		data_sort_type={'unsortable', 'unsortable', 'unsortable'},
		property ='P710',
		no_roll_startlist=no_roll_startlist,
		womenrace_bool=womenrace_bool
	}

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

function p.startlisttable(frame)
	local IDtemp
	if frame.args[1] ~= nil then
		IDtemp=string.gsub(frame.args[1], "%c", "")
	end
	local womenrace_bool=isWomenrace(IDtemp)

	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=IDtemp,
		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,
		womenrace_bool=womenrace_bool
	}
	return startlisttable_main(s, tableA(s))
end

local function startlist_sub(p710, timeOfRace,  WDlink_on, istable,womenrace_bool)
	local h, resultTable= {}, {}
	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,womenrace_bool)--"HD","NP","DQ"
			elseif dnf=='Q54881674' or dnf=='Q7113430' then riderDNF =translate("startlist",7,womenrace_bool)
			elseif dnf=='Q1210382' then riderDNF =translate("startlist",8,womenrace_bool)
			elseif dnf=='Q1229261' then riderDNF =translate("startlist",9,womenrace_bool)
			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, national_team_boolean = getTeam(riderID, timeOfRace, q)
	riderTeamID=seasonToTeamID(riderTeamID)
	riderTeamCode= getTeamCode(riderID, timeOfRace, q)
	
	--Custom display for national selection
	if national_team_boolean 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

	if riderTeamLink == nil then riderTeamLink ="" end
	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)
	end
	tBody:tag('td'):cssText('text-align:'..textalign.. ';padding:0 0.5em;'..DSQ):wikitext(number(gender,riderRank,wiki)..riderDNF)

	table.insert(resultTable, {sortkey=sortkey, riderTeamLink=riderTeamLink,riderTeamID=riderTeamID,riderTeamCode=riderTeamCode, tBody=tBody})
	return resultTable
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 womenrace_bool=isWomenrace(s.item)

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

	for _, p710 in statements(s.item, 'P710') do -- P710 is participants
		subtable=startlist_sub(p710, timeOfRace, WDlink_on, false,womenrace_bool)
		ridertable[#ridertable + 1] = {
			subtable[1].sortkey, 
			riderTeamLink=subtable[1].riderTeamLink, 
			riderTeamID=subtable[1].riderTeamID, 
			riderTeamCode=subtable[1].riderTeamCode, 
			tBody=subtable[1].tBody
		}
	end
	
	--sort
	table.sort(ridertable, function(a, b) return a[1] < b[1] 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,womenrace_bool))
		tSubtitle:tag('td'):attr('width','200px')
		:css("align:right;text-align:right")
		:wikitext(translate("startlist",3,womenrace_bool))
		tSubtitle:tag('td'):attr('width','85px')
		:css("align:right;text-align:right")
		:wikitext(translate("startlist",4,womenrace_bool))
	else
		tSubtitle=mw.html.create('tr')
		tSubtitle:tag('td'):attr('width','30px'):wikitext(translate("startlist",2,womenrace_bool))
		tSubtitle:tag('td'):attr('width','250px'):wikitext(translate("startlist",3,womenrace_bool))
		tSubtitle:tag('td'):attr('width','35px'):wikitext(translate("startlist",4,womenrace_bool))
	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
			if ridertable[ii].riderTeamLink==nil then ridertable[ii].riderTeamLink=translate("startlist",13,womenrace_bool) end
			if ii~=1 and ridertable[ii].riderTeamID and ridertable[ii].riderTeamID==ridertable[ii-1].riderTeamID then test=0 else test=1 end--team change
				--new team
			if test==1 or ii==1 then
				if thisDS and ii~=1 then
					tDS=insideTable:tag('tr')
					tDS:tag('td'):attr('colspan','3'):attr('align','center')
					:wikitext(translate("startlist",5,womenrace_bool).." "..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 rgb(200,200,200)
				:attr('background-color','rgb(255, 255, 255)')
				: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)
				:attr('align','center')
				local tCell=tTitle:tag('th'):attr('colspan','3')
				tCell:tag('big'):wikitext(ridertable[ii].riderTeamLink.."<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
			insideTable:node(ridertable[ii].tBody)
		end
		--last DS
		if thisDS then
			tDS=insideTable:tag('tr')
			tDS:tag('td'):attr('colspan','3'):attr('align','center')
			:wikitext(translate("startlist",5,womenrace_bool).." "..thisDS)
		end
		tag:node(thisTableRow)

		return resultTable
	end
end

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
		local subtable=startlist_sub(p710, timeOfRace, WDlink_on, true)
		t_Body[#t_Body + 1] = {subtable[1].sortkey, tostring(subtable[1].tBody)}
	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 s = {
		item = string.gsub(frame.args[1] or frame:getParent().args[1], "%c", ""),
	}
	return riderranking_main(frame, s)
end


function riderranking_main(frame,s)
	local thisCompetition, rank, thisyear, sitelink, q, gender, DSQ
	local resultTable, listofcalendar, UCImaster, UCImasterlimist={},{},{},{}
	local minmaxyear= {
		minimum = 0, -- lots of jerseyID
		maximum = 0 -- points, time, time_gap, speed
	}
	local calendarlistpresent={
		["UCIwomen"]=false,
		["UCImen"]=false
	}
	
	local UCI = {}
	--inverse the table
	for k,v in pairs(data.UCIYearToQ) do
		UCI[k]={}
		for kk, vv in pairs(v) do
			UCI[k][vv]=kk
		end
	end
	
	local UCImaster=data.UCImaster
	local gender=getGenderCode(s.item, 'm')
	local womenrace_bool=false
	if gender=="f" then womenrace_bool=true end

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

	UCImasterlimit={
		["women"]=	{b=1989, e=0}, --women=Calendrier international féminin UCI, begin/end 0 = no end
		["WWT"]=	{b=2016, e=0},
	    ["WWC"]=	{b=1998, e=2015},
	    ["UWT"]=	{b=2011, e=2018},
	    ["europe"]= {b=2005, e=0},
		["asia"]=	{b=2005, e=0},
		["oceania"]={b=2005, e=0},
		["america"]={b=2005, e=0},
		["africa"]= {b=2005, e=0},
		["WR"]= 	{b=2016, e=0},
		["WC"]= 	{b=2009, e=2010},
		["UPT"]=	{b=2005, e=2008},
		["UCImen"]= {b=1984, e=2004},
		["WCmen"]=  {b=1989, e=2004},
		["Pernod"]= {b=1959, e=1987},
		["Desgrange"]=  {b=1948, e=1958},
	}
	
	local listofwomencalendar={"women","WWC",  "WWT"} --"women" is in fact UCIwomen 
	local listofmencalendar={"Desgrange","Pernod","UCImen","WCmen","UPT",
							"WC","UWT","WR","europe","asia","america","oceania","africa","Pro"}
	
	if gender=="f" then
		listofcalendar=listofwomencalendar
	else
		listofcalendar=listofmencalendar
	end
	
	--init table
	for ii=1900,2100,1 do
		resultTable[tostring(ii)]={}
		for _, calendar  in pairs(listofcalendar) do
			resultTable[tostring(ii)][calendar]={
				rank=nil, 
				sitelink=nil
			}
		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 UCI[calendar][thisCompetition] then
				thisyear=UCI[calendar][thisCompetition]
				minmaxyear=checkminmaxyear(minmaxyear,thisyear)
				q = p1344.qualifiers
				if q and q.P1352 and q.P1352[1].snaktype == 'value' then --rank
					rank = tonumber(q.P1352[1].datavalue.value.amount)
					DSQ = isdisqualified(p1344, q)
 				else
					rank= nil
				end
				if rank then
					resultTable[thisyear][calendar]["rank"]=tostring(rank)
					resultTable[thisyear][calendar]["DSQ"]=DSQ 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)
		:wikitext(wdLin..' '..translate("riderranking",1,womenrace_bool))

		for ii=minmaxyear.minimum,minmaxyear.maximum,1 do
			tRow:tag('th'):attr("width","50px")
			:css('background-color',backgroundColor)
			: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(UCImaster[calendar])
				local tRow=finalTable:tag('tr')
				local tCell = tRow:tag('th'):cssText("text-align:" .. textalign .. ";") -- left
				if sitelink then
					tCell:wikitext('[['..sitelink..'|'..UCImastername[calendar]..']]')
				else
					tCell:wikitext(UCImastername[calendar])
				end
				
				for yy=minmaxyear.minimum,minmaxyear.maximum,1 do
					thisyear=tostring(yy)
					color="white"
					if resultTable[	thisyear][calendar]["rank"] then
						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
					--this ranking exist for this year, but the rider is not ranked
					elseif yy>=UCImasterlimit[calendar].b and
						(UCImasterlimit[calendar].e==0 or yy<=UCImasterlimit[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)
					end
				end
			end
		end

		local UCIlink, legend
		if wiki=="fr" then
			UCIlink="https://www.uci.org/fr/route/classements"
			legend= "  Légende : nc = non classé"
		else
			UCIlink="https://www.uci.org/road/rankings"
			legend=""
		end
		
		local tableyearsize=minmaxyear.maximum-minmaxyear.minimum+2
		
		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,womenrace_bool).."["..UCIlink..' UCI]')

		return  finalTable
	end
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

	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
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=nationalcat
	else
	   cat=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 = 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 = 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	

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 womenrace_bool=false
	if gender=="f" then womenrace_bool=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,womenrace_bool)
	    elseif gen_plural then
	    	ans=translate("riderinfobox",49,womenrace_bool)
	    else
	    	ans=translate("riderinfobox",50,womenrace_bool)
	    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,womenrace_bool)
		    elseif gen_plural then
		    	ans=translate("riderinfobox",49,womenrace_bool)
		    else
		    	ans=translate("riderinfobox",50,womenrace_bool)
		    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..' (VTT)'
		    elseif dis=='cycloCross' then
		    	row=teamLink..' (cyclo-cross)'
		    else 
		    	row=teamLink..' (piste)'
		    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
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(wikibase.label('Q2328847'), "%b()", "") or getLabelFallback('Q2328847',{'en', 'fr', 'de'})
				nametemp=nametemp..' ('..stagiaire..')'
			end
			tab:node(addARow(periodtemp or '',nametemp)) --period, name
		end
	end
end

--for local data
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 frame = frame
	local lang = contentLanguage
	-- If true, winners will have Wikidata logos with link to Wikidata
	local WDlink_on = (wiki == "mk" or wiki == "ja")

	local localframe
	if string.match(frame:getParent():getTitle(), '%P+') == mw.site.namespaces.Template.name then
		localframe = frame:getParent()
	else
		localframe = frame
	end
	
	local entityID = mw.text.trim(frame.args[1])
	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
	
	local gender=getGenderCode(entityID, 'm')
	local womenrace_bool=false
	if gender=="f" then womenrace_bool=true end

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

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

	local others = {
		{ name = translate("infobox",29,womenrace_bool)}, -- picture
		{ name = translate("infobox",30,womenrace_bool)}, -- caption
		{ name = translate("infobox",31,womenrace_bool)}, -- map
		{ name = 'sectional'},             -- sectional
		{ name = translate("infobox",30,womenrace_bool)}, -- caption map
		{ name = translate("infobox",30,womenrace_bool)}, -- caption sectional
	}

	local name =  getLabelFallback(entityID, {wikilang, 'en', 'fr', 'de'}) 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, localframe.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, localframe.args)
	getLocalContent(teams, localframe.args)
	getLocalContent(others, localframe.args)
    getLocalContent(victories, localframe.args)
    getLocalContent(medals, localframe.args)

	local listOfBirthNames, listOfNickNames, listOfOfficialNames, listOfShortNames
	
	local icon = ' [[File:Cycling (road) pictogram.svg|35px]]'

	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

--	getSomeNames(details, entityID, 'P1477', 1, display_language) --birthname
	--less prio than P1477
	getSomeNames(details, entityID, 'P1559', 1, display_language) --birthname, bis
	getSomeNames(details, entityID, 'P1449', 2, display_language) --nick name
	getSomeNames(details, entityID, 'P1448', 3, display_language) --official name
	getSomeNames(details, entityID, 'P1813', 4, display_language) --short name

	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) 
	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,womenrace_bool),"260px")
	if amateurWD then
		teamTable(tab, teamAmateur, translate("riderinfobox",26,womenrace_bool), translate("riderinfobox",27,womenrace_bool))
	else
	 	localTeamTable(tab,amateurTeam_names, amateurTeam_periods, translate("riderinfobox",26,womenrace_bool), translate("riderinfobox",27,womenrace_bool))
		localTeamTable(tab,nonUCITeam_names, nonUCITeam_periods, translate("riderinfobox",29,womenrace_bool), translate("riderinfobox",30,womenrace_bool))
	end
	
	if proWD then
		teamTable(tab, teamPro, translate("riderinfobox",45,womenrace_bool),translate("riderinfobox",46,womenrace_bool))
		teamTable(tab, teamMountainBike, translate("riderinfobox",39,womenrace_bool), translate("riderinfobox",40,womenrace_bool))
		teamTable(tab, teamCycloCross, translate("riderinfobox",41,womenrace_bool), translate("riderinfobox",42,womenrace_bool))
		teamTable(tab, teamTrack, translate("riderinfobox",43,womenrace_bool), translate("riderinfobox",44,womenrace_bool))
	else
		localTeamTable(tab,proTeam_names, proTeam_periods,translate("riderinfobox",45,womenrace_bool), translate("riderinfobox",46,womenrace_bool))
		localTeamTable(tab,UCITeam_names, UCITeam_periods, translate("riderinfobox",35,womenrace_bool), translate("riderinfobox",36,womenrace_bool))
	end

	--managed teams
	if managedWD then
		teamTable(tab, nationalTeam, translate("riderinfobox",52,womenrace_bool), translate("riderinfobox",53,womenrace_bool))
		teamTable(tab, managedTeam, translate("riderinfobox",23,womenrace_bool), translate("riderinfobox",24,womenrace_bool))
	else
		localTeamTable(tab,managedTeam_names, managedTeam_periods,translate("riderinfobox",23,womenrace_bool), translate("riderinfobox",24,womenrace_bool))
	end
	
	if victories[1].content then
		tab:node(addATitle(translate("riderinfobox",38,womenrace_bool))) 
		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,womenrace_bool))) 
		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,womenrace_bool), entityID)
	return tab
end

--=== P) Team infobox
function p.teaminfobox(frame)
	localframe = frame
	local lang = contentLanguage
	-- If true, winners will have Wikidata logos with link to Wikidata
	local WDlink_on = (wiki == "mk" or wiki == "ja")
	
	local entityID = mw.text.trim(frame.args[1])
	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	
	local womenrace_bool=isWomenrace(entityID)
	
	local tRace = {race={
			raceId,
			raceDate,
			future,
			}, 
		  lastEditionMonth, 
		  lastEditionYear, 
		  numberOfEditions,
		  lastLink,
		  nextLink,
		  }
	
	local details = {
		{ name = translate("teaminfobox",2,womenrace_bool)}, -- sport
		{ name = translate("teaminfobox",3,womenrace_bool), name_plural = translate("teaminfobox",4,womenrace_bool)}, -- type 	
		{ name = translate("teaminfobox",5,womenrace_bool), name_plural = translate("teaminfobox",6,womenrace_bool)}, -- UCI-cod
		{ name = translate("teaminfobox",7,womenrace_bool), name_plural = translate("teaminfobox",8,womenrace_bool)}, -- сountry
		{ name = translate("teaminfobox",9,womenrace_bool)}, -- creation date
		{ name = translate("teaminfobox",10,womenrace_bool)}, -- disparition date
		{ name = translate("teaminfobox",11,womenrace_bool)}, -- number of season
		{ name = translate("teaminfobox",13,womenrace_bool)}, -- official web site
		{ name = translate("teaminfobox",24,womenrace_bool), name_plural = translate("teaminfobox",25,womenrace_bool) }, -- bike
		{ name = translate("teaminfobox",26,womenrace_bool)}, -- budget
	}
	
	local others = {
		{ name = translate("infobox",29,womenrace_bool)}, -- picture
		{ name = translate("infobox",30,womenrace_bool)}, -- caption
		{ name = translate("infobox",31,womenrace_bool)}, -- map
		{ name = 'sectional'},             -- sectional
		{ name = translate("infobox",30,womenrace_bool)}, -- caption map
		{ name = translate("infobox",30,womenrace_bool)}, -- caption sectional
	}
	
	local managers ={
		{ name = translate("teaminfobox",14,womenrace_bool), name_plural = translate("teaminfobox",15,womenrace_bool)}, -- manager													--country
		{ name = translate("teaminfobox",16,womenrace_bool), name_plural = translate("teaminfobox",17,womenrace_bool)}, -- sports director
	}

	local name =  getLabelFallback(entityID, {wikilang, 'en', 'fr', 'de'}) or ''
	infoGetOthers(others, entityID)	
		
	local localframe
	if string.match(frame:getParent():getTitle(), '%P+') == mw.site.namespaces.Template.name then
		localframe = frame:getParent()
	else
		localframe = frame
	end
	getLocalContent(details, localframe.args)
	getLocalContent(others, localframe.args)
	getLocalContent(managers, localframe.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'
		' [[File:Cycling (road) pictogram.svg|35px]]' 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, "Y" )
	end

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

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

	-- official site
	if not details[8].content then
		details[8].content = officialSite(entityID)
	end
	
	--9 is bike (no Wikidata input)
	--10 budget
	listWPlinkChrono(details, 10, 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,womenrace_bool),"260px")

	if managers[1].content or managers[2].content then
		tab:node(addATitle(translate("teaminfobox",18,womenrace_bool)))
		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,womenrace_bool))) 
		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 frame.args[2] then -- if the jersey is not specified, then the JERSEY header is not displayed 
		tab:node(addATitle(translate("teaminfobox",20,womenrace_bool)))
	    local outTable = mw.html.create('tr')
		local tCell=outTable:tag('td'):attr('colspan','3'):css('text-align','center')		    
		tCell:wikitext(frame.args[2]) -- 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.nextLink or tRace.lastLink then
		tab:node(addATitle(translate("teaminfobox",21,womenrace_bool)))
		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,womenrace_bool)..
			":<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,womenrace_bool)..
		    ":<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,womenrace_bool), entityID)
	return tab
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]),toboolean(argu[5]))	
		if temp then return temp 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=='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=='getClassCalendar_sub' then
		return getClassCalendar_sub(argu[2])
	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(class_dic[argu[2]])
	elseif function_name=="class_sort" then
		return tostring(class_sort[argu[2]])
	elseif function_name=='bg_color_table' then	
		local temp = bg_color_table[argu[2]]
		temp=string.gsub(temp,'#',"")
		return temp
	end
end

return p