モジュール:Cycling race

local p = {}
local wiki = string.match(mw.site.server, "%a+")
if wiki == "www" then
	wiki = "fr"
end
--import translation
local l10n = mw.loadData("Module:Cycling race/l10n")
--import data
local data = mw.loadData("Module:Cycling race/data")
local contentLanguage = mw.getContentLanguage()
local wikilang = contentLanguage:getCode()
local wikibase = mw.wikibase
-- == Structure of the code**
-- I) Constant
-- II) Translation
-- III) Basic functions
-- IV) Functions less basic called from other functions
-----A) Time functions
-----B) Link functions
-----C) Functions for the output, like table
-----D) Jersey, flag functions
-----E) Other (winner)
-- V) Main functions
----- A) Function race reference
----- B) Calendar
----- C) Victory
----- Cbis) Function for infobox
----- D) Stage infobox
----- E) List of teams
----- F) Classifications
----- G) Infobox
----- H) Race infobox
----- I) Team roster
----- J) Function list of winners (palmarès)
----- K) List of stages
----- L) List of stages classification
----- M) Start list
----- N) Rider ranking
----- O) Rider infobox
----- P) Team infobox
-- ..................
----- Z) Miscellaneous / Other / Tests 
--Tip: search "--==" to navigate between the sections
--== I) Classes declared as global**
local textalign = "left"
local floattable = "left"
local floatinfobox = "right"
if wiki == "ar" or wiki == "fa" or wiki == "ur" or wiki == "he" then
	textalign = "right"
	floattable = "right"
	floatinfobox = "left"
end
local Wikidatalogosize = "12px"
if wiki == "ar" then Wikidatalogosize = "15px" end
local standardtablecss=data.standardtablecss_part1..textalign..data.standardtablecss_part2
local lang_priority --for lang priority and fallback
if l10n"lang_priority" then
	lang_priority=l10n"lang_priority"
else --default
	lang_priority={}
	table.insert(lang_priority,wikilang)
	for _, lang in ipairs({'mul','en', 'fr', 'de','es','nl','it','da'}) do
		if lang~=wikilang then
			table.insert(lang_priority,lang)
		end
	end
end
--"country" means here, that there will be a separated column containing the country name
--otherwise a flag is typically added in another column, for instance before the rider name
local no_country_calendar={'ru','ar'}
local no_country_victories={'ru','ar','da'}
local no_country_classification={'es','da','no','ru','ar'}
--to avoid wrong display, or country names becoming very long,
--available_list==false --> country=false in the old code,
--should be implemented here
if not l10n"country_name_list" then
	table.insert(no_country_calendar, wiki)
	table.insert(no_country_victories, wiki)
	table.insert(no_country_classification, wiki)
end
--Note about WDlink_on
--On some wikipedia small wikidata flag are displayed after all data coming from wikidata
--to enable that set WDlink_on on true
local no_roll_startlist={'fr','da','no','ar','ru','de'}
local display_language_in_riderinfobox={'ru'}
local display_flag_in_riderinfobox={'ru'}
local display_birthnameastitle_in_riderinfobox={'ru'}
local display_noweight_in_riderinfobox={'fr','pl'}
local display_noage_in_riderinfobox={'pl'}
local display_nonickname_in_riderinfobox={'pl'}
local display_cm_in_riderinfobox={'pl'}
local silver_theme_countries={'da', 'pl'}
local backgroundColor="#FFDF80"
local backgroundColorLight="#FFF7DF"
for _, value in pairs(silver_theme_countries) do -- get data if country should be printed in this wiki
	if value == wiki then 
		backgroundColor="var(--background-color-neutral, #eaecf0)" 
		backgroundColorLight="var(--background-color-neutral-subtle, #f8f9fa)"
	end
end
local arwiki_totemplate = false
local artemp_module
if wiki == "ar" then
	local totemplate = mw.getCurrentFrame():getParent().args"totemplate" or mw.getCurrentFrame().args"totemplate"
	if (totemplate and totemplate ~= "") then arwiki_totemplate = true end
	if arwiki_totemplate then
		artemp_module = require("Module:Cycling race/artemp")
	end
end
local dark_mode_countries={'ca', 'pl'}
local picto_track=" 35px"
local picto_road=" 35px" 
for _, value in pairs(dark_mode_countries) do 
	if value == wiki then 
		picto_track=" class=skin-invert"
		picto_road=" class=skin-invert" 
	end
end
local function istrue(x)
if x and (x == 1 or x == "1" or x == "true") then return true end
return nil
end
--== II) Translation**
local function translate(func_name_short, index, w_race, title)
	if index==1000 then --code for some custom function
		return title
	else
		if func_name_short then
			local func_name
			if w_race then
				func_name=func_name_short.."_women_translate"
				if l10nfunc_name and l10nfunc_nameindex then 
					return l10nfunc_nameindex
				end
			end
			func_name=func_name_short.."_translate"
			if l10nfunc_nameindex then 
				return l10nfunc_nameindex
			end
			return "translation for "..func_name.." index ".. tostring(index).." not found"
		else 
			error('func_name found')
		end
	end
end
local function plural(num)
	local plural=false --latin language
	local gen_singular=false --for slavic language
	local gen_plural=false --for slavic language
	if num then
		if num > 1 then
			plural=true
			if num  20 then
				local modulo = math.fmod( num, 10)
				--modulo==1 --> nothing, it is singular
				if modulo>1 and modulo4 then
					gen_plural=true
				end
			else
				gen_plural=true
			end
		end
	end
	
	return plural, gen_singular, gen_plural
end
local function black_list( Label)
	local black_list=l10n.black_list
	-- List of Wikipedia articles with the same lemma as the non existing rider article. Those lemmas are printed
		as text "black" in the tables, not "blue" or "red". This way there will be no false wikilinks at the WhatLinksHere entry.
		List should be updated maybe once a year. 
	return black_listLabel
end
local function country_name_from_list(countryID)
	if l10n"country_name_list" and l10n"country_name_list"countryID then
		return l10n"country_name_list"countryID
	end
	return nil
end
local function stageLink(x, a, b) -- x= 10a: a = 10, b = a. x = 5: a = 5, b = ""
	local word1 
	local word2=translate("func_prologue",2) --stage
	local word=word2
	if wiki=="ar" then return word2 .. " " .. ( a or "" ) , "#" .. word2 .. " " .. ( a or "" ) end
-- fr:  étape,  étape
	if wiki=="fr" then
		if b == "" then -- series_ordinal without character
			if a == "1" then word1 = "1re "..word else word1 = a.."e "..word end -- table text =  étape,  é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 = "1re "..b.." "..word else word1 = a.."e "..b.." "..word end -- table text =  étape,  é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 =  etapa,  etapa,
			if a == "1" or a == "3" then word2 = "#"..a.."ᵉʳ "..b.." "..word else word2 = "#"..a.."ª"..b.." "..word end --text of section header = #1ᵉʳ etapa, #2ª etapa
			return word1, word2
		end
	end
	-- default
	word1 = x                  -- table text = 1, 2a, 3
	word2 = "#"..word.." ".. x -- text of section header = #Etappe 2a, #Stage 4
	return word1, word2
end
local function typeofstage(x, typ, noborder)
	-- plain, hilly, inter, ... must be "" or "any text"
	-- l10nDef"" = {plain = "", hilly="", inter=, mount=, time_prologue=, time_team=, time_indiv=, uphill=, rest=}
	local l10n=l10n"type_of_stage_translate"
	local border
	if noborder then border="" else border="|border|right" end
local stages = {
"plain stage" = ""..l10n.plain.."",
"hilly stage" = ""..l10n.hilly.."",
"intermediate stage" = ""..l10n.inter.."",
"mountain stage" = ""..l10n.mount.."",
"uphill time trial stage" = ""..l10n.uphill.."",
"rest day" = ""..l10n.rest..""
}
	if arwiki_totemplate then
		return artemp_module.arwiki_typeofstage(x, typ)
	end
	if stagesx then
		return stagesx
	end
	if x=='time trial stage' then
		if noborder then border="" else border="|right" end
		local stages2 = {
			"Q2348250" = ""..l10n.time_team.."",
			"Q2266066" = ""..l10n.time_indiv.."",
			"Q485321" = ""..l10n.time_prologue..""
		}
		if stages2typ then
			return stages2typ
		end
	end
end
local function typeofstagelogo(stageID, noborder)
	local sType
	p = mw.wikibase.getBestStatements(stageID, 'P31') -- P31 is 'instance of'
	local stages = {
		"Q20646667" = {"plain stage", nil},
		"Q20646670" = {"hilly stage", nil},
		"Q20680270" = {"intermediate stage", nil},
		"Q20646668" = {"mountain stage", nil},
		"Q485321" = {"time trial stage", "Q485321"}, -- prologue
		"Q2266066" = {"time trial stage", "Q2266066"}, -- individual time trial
		"Q2348250" = {"time trial stage", "Q2348250"}, -- team time trial
		"Q20679712" = {"uphill time trial stage", nil}
	}
	for _, t in pairs(p) do
		if t.mainsnak.snaktype == 'value' then
			local iOf = t.mainsnak.datavalue.value.id
			if stagesiOf then
				sType = typeofstage(stagesiOf1, stagesiOf2, 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.valuefield or s.mainsnak.datavalue.value
			end
		end
	else
		return nil
	end
end
-- Go from season of a team to the team 
local function getParentID(teamID)
	return firstValue(teamID, 'P5138', 'id') -- P361 is 'part of'
		or firstValue(teamID, 'P361', 'id') -- P5138 is 'season of club or team'
end
-- Get a label in any of the languages in the fallback list of language codes 
local function getLabelFallback(itemID, fallback)
	local label
	if fallback==nil then --default
		fallback=lang_priority
	end
	for _, lang in ipairs(fallback) do
		label = mw.wikibase.getLabelByLang(itemID, lang)
		if label then break end
	end
	return label
end
-- Get a sitelink from the local wiki or from the fallback list of language codes 
local function getSitelinkFallback(itemID, fallback)
	local link = mw.wikibase.getSitelink(itemID)
	if link then return link end
	for _, lang in ipairs(fallback) do
		link = mw.wikibase.getSitelink(itemID, lang .. 'wiki')
		if link then return link end
	end
	return nil
end
local function get_lf(frame)
	local lf = frame
	if string.match(frame:getParent():getTitle(), '%P+') == mw.site.namespaces.Template.name then
		lf = frame:getParent()
	end
	-- if wiki == "ar" then lf = frame:getParent() or frame end
	return lf
end
local function get_and_checkID(frame)
	local lf = get_lf(frame)
	local entityID = mw.text.trim(lf.args1)
	entityID= string.gsub(entityID, "%c", "") --probably redundant
	if type(entityID) ~= 'string' then error('parameter must be a string') end
	if not entityID:match('Q%d+') then error('parameter must be a valid Wikidata item (ex: Q42)') end
	return entityID, lf
end
local function make_IllWD2_link(q, arlabel, enlabel, text)
	local argse = { "المعرف" = q, target='en'}
	if arlabel and arlabel ~=  then 
		argse.label = arlabel
	elseif enlabel and enlabel ~=  then
		argse.enlabel = enlabel
	end	
	if text and text ~= "" then
		argse.text = text 
	end
	local final = ""
	if arwiki_totemplate then
		final = ""
else
	argse.nocat = "t"
	final = mw.getCurrentFrame():expandTemplate{ title = 'Ill-WD2', args = argse }
end
	return final
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 = statei
		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 = statei
		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.qualifiersPID or {}, 0
end
local function qualifieramount(element, property)
	local result
	for _, q in qualifiers(element, property) do
		result = tonumber(q.value.amount)
		break
	end
	return result
end
local function dispmoney(amount, unit)
	if amount and unit then
		local cost = contentLanguage:formatNum(tonumber(amount))
		if wiki == 'fo' then cost = string.gsub(cost, "%.", ",") end
		if unit == "http://www.wikidata.org/entity/Q4916" then 
			cost = cost .. ' €'
		elseif unit == "http://www.wikidata.org/entity/Q4917" then 
			cost = cost .. ' $'
		end
		return cost
	end
	return nil
end
--== IV) Functions less basic called from other functions**
--=== A) Time functions**
-- Get a Wikidata statement for an entity and property valid at the given timevalue 
local function checktime(s,q, time)
	local start, startPrecision, END, endPrecision, timePrecision
	if not q or not time then
		return s
	end
	local _, _, _, m, _ = string.find(time, "(%d+)%p(%d+)%p(%d+)")
	if m=="00" then
		timePrecision=9
	end
	if q.P580 and q.P5801 and q.P5801.snaktype == 'value' then -- P580 is start time
		start = q.P5801.datavalue.value.time
		startPrecision = q.P5801.datavalue.value.precision
		if startPrecision == 9 or timePrecision==9 then -- precision is years
			start = string.sub(start, 1, 5) -- Cut of everything after year
		elseif startPrecision == 10 then -- precision is months
			start = string.sub(start, 1, 8) -- Cut of everything after month
		end
	end
	if q.P582 and q.P5821 and q.P5821.snaktype == 'value' then -- P582 is end time
		END = q.P5821.datavalue.value.time
		endPrecision = q.P5821.datavalue.value.precision
	end
	if not start or start = time then
			return s
		end
	end
	return nil
end
local function getStatementForTime(ID, property, time)
	local temp
	for _, s in statements(ID, property) do
		temp =checktime(s, s.qualifiers, time)
		if temp then return temp end
	end
	return nil
end
--Display date interval in a natural way: 
--long:
--4-5 January 2020 
--4 January - 2 February 2020
--4 January 2020 - 2 February 2021
--small is the same with short month names
--Does not work properly if the precision is not sufficient
local function getStartEndTime(sTime, eTime, mode)
	-- Note: Add the 4formats to "formats" and use funcDate
	local lang = contentLanguage
	local starttime, endtime
	
	--local format = formatswiki or formats
	if mode==nil then mode='long' end
	-- Timevalues is like "+2015-07-04T00:00:00Z"
	local y, m = string.match(sTime, "(%d+)-(%d+)-%d+")
	local y2, m2 = string.match(eTime, "(%d+)-(%d+)-%d+")
	
	if m=='00' then --manage the 30 November issue
		if  mode=='long' or mode=="verylong" then
			starttime =lang:formatDate( "Y", sTime )
		else
			starttime ='-'
		end
	else
		if y ~= y2 then
			if mode=='long' or mode=="verylong" then
				starttime = lang:formatDate( "j F Y", sTime )
			else
				starttime = lang:formatDate( "j M Y", sTime )
			end
		elseif m ~= m2 then
			if mode=='long' or mode=="verylong" then
				starttime = lang:formatDate( "j F", sTime )
			else
				starttime = lang:formatDate( "j M", sTime )
			end
		else
			starttime = lang:formatDate( "j", sTime )
		end
	
		if wiki == "ar" then
			if y ~= y2 then starttime = lang:formatDate( "d F Y", sTime )
			elseif m ~= m2 then starttime = lang:formatDate( "d F", sTime )
			else starttime = lang:formatDate( "d ", sTime ) end
		elseif wiki == "br" then
			if y ~= y2 then starttime = lang:formatDate( "j", sTime ) .." a viz ".. lang:formatDate( "F Y", sTime )
			elseif m ~= m2 then starttime = lang:formatDate( "j", sTime ) .." a viz ".. lang:formatDate( "F", sTime )
			else starttime = lang:formatDate( "j", sTime ) .." "
			end
		elseif wiki == "ca" or wiki == "es" or wiki == "ast" then
			if y ~= y2 then
				starttime = lang:formatDate( "j", sTime ) .." de ".. lang:formatDate( "F", sTime ) .." de ".. lang:formatDate( "Y", sTime )
			elseif m ~= m2 then
				starttime = lang:formatDate( "j", sTime ) .." de ".. lang:formatDate( "F", sTime )
			else starttime = lang:formatDate( "j", sTime ) .." "
			end
		elseif wiki == "cs" then
			if y ~= y2 then starttime = lang:formatDate( "j. xg Y", sTime )
			elseif m ~= m2 then starttime = lang:formatDate( "j. xg", sTime )
			else starttime = lang:formatDate( "j", sTime )
			end
		elseif wiki == "de" or wiki == "da" or wiki == "fo" or wiki == "lb" or wiki == "no" then
			if y ~= y2 then starttime = lang:formatDate( "j. F Y", sTime )
			elseif m ~= m2 then starttime = lang:formatDate( "j. F", sTime )
			else starttime = lang:formatDate( "j.", sTime )
			end
		elseif wiki == "fi" then
			if y ~= y2 then starttime = lang:formatDate( 'j. F"ta" Y', sTime )
			elseif m ~= m2 then starttime = lang:formatDate( 'j. F"ta"', sTime )
			else starttime = lang:formatDate( "j.", sTime )
			end
		elseif wiki == "eo" then
			if y ~= y2 then starttime = lang:formatDate( "j", sTime ) .."-a de ".. lang:formatDate( "F Y", sTime )
			elseif m ~= m2 then starttime = lang:formatDate( "j", sTime ) .."-a de ".. lang:formatDate( "F", sTime )
			else starttime = lang:formatDate( "j", sTime ) .."-a "
			end
		elseif wiki == "eu" then
			if y ~= y2 then starttime = lang:formatDate( "Y", sTime ) ..".eko ".. lang:formatDate( "F", sTime ) .."k ".. lang:formatDate( "j", sTime )
			elseif m ~= m2 then starttime = lang:formatDate( "F", sTime ) .."k ".. lang:formatDate( "j", sTime )
			else starttime = lang:formatDate( "F", sTime ) .."k ".. lang:formatDate( "j", sTime )
			end
		elseif wiki == "hu" then
			starttime = lang:formatDate( "Y. F j.", sTime)
		elseif wiki == "ja" then
			if y ~= y2 then starttime = lang:formatDate( "Y年m月d日", sTime )
			elseif m ~= m2 then starttime = lang:formatDate( "Y年m月d日", sTime )
			else starttime = lang:formatDate( "Y年m月d日", sTime )
			end
		elseif wiki == "lv" then
			if m ~= m2 then starttime = lang:formatDate( "Y. \\g\\a\\d\\a j. F", sTime )
			else starttime = lang:formatDate( "Y. \\g\\a\\d\\a j.", sTime )
			end
		elseif wiki == "pl" then
			if y ~= y2 then starttime = lang:formatDate( "j xg Y", sTime )
			elseif m ~= m2 then starttime = lang:formatDate( "j xg", sTime )
			else starttime = lang:formatDate( "j", sTime )
			end
		end
	end
	
	if m2=='00' then --manage the 30 November issue
		if  mode=='long' or mode=="verylong" then
			endtime= lang:formatDate( "Y", eTime )
		else
			endtime= '-'
		end
	else
		if (mode=='long' and y ~= y2) or mode=="verylong" then
			endtime = lang:formatDate("j F Y", eTime)
		elseif y ~= y2 then --small
			endtime = lang:formatDate("j M Y", eTime)
		elseif mode=='long' then
			endtime = lang:formatDate("j F", eTime)
		else
			endtime = lang:formatDate("j M", eTime)	
		end
		if wiki == "ar" then
			if mode=='long' or mode=="verylong" or y ~= y2 then endtime = lang:formatDate( "d F Y", eTime )
			elseif m ~= m2 then endtime = lang:formatDate( "d F Y", eTime )
			else endtime = lang:formatDate( "d F Y", eTime )
			end
		elseif wiki == "br" then endtime = lang:formatDate( "j", eTime ) .." a viz ".. lang:formatDate( "F Y", eTime )
		elseif wiki == "ca" or wiki == "es" or wiki == "ast" then
			if mode=='long' or mode=="verylong" or y ~= y2 then
				endtime = lang:formatDate( "j", eTime ) .." de "..
				lang:formatDate( "F", eTime ) .." de ".. lang:formatDate( "Y", eTime )
			else
				endtime = lang:formatDate( "j", eTime ) .." de "..
				lang:formatDate( "F", eTime )
			end
		elseif wiki == "cs" then endtime = lang:formatDate( "j. xg Y", eTime )
		elseif wiki == "de" or wiki == "da" or wiki == "fi" or wiki == "fo" or wiki == "lb" or wiki == "no" then
			if mode=='long' or mode=="verylong" or y ~= y2 then
				endtime = lang:formatDate( "j. F Y", eTime )
			else
				endtime = lang:formatDate( "j. M", eTime )
			end
		elseif wiki == "eo" then endtime = lang:formatDate( "j", eTime ) .."-a de ".. lang:formatDate( "F Y", eTime )
		elseif wiki == "eu" then endtime = lang:formatDate( "Y", eTime ) ..".eko ".. lang:formatDate( "F", eTime ) .."k "..
			lang:formatDate( "j", eTime )
		elseif wiki == "fi" then endtime = lang:formatDate('j F"ta" Y', eTime)
		elseif wiki == "hu" then
			if y ~= y2 then endtime = lang:formatDate( "Y. F j.", eTime )
			elseif m ~= m2 then endtime = lang:formatDate( "F j.", eTime )
			else endtime = lang:formatDate( "j.", eTime )
			end
			--endtime = lang:formatDate( "Y", eTime ) ..". ".. lang:formatDate( "F j", eTime ) .."."
		elseif wiki == "ja" then
			if y ~= y2 then endtime = lang:formatDate( "Y年m月d日", eTime )
			elseif m ~= m2 then endtime = lang:formatDate( "m月d日", eTime )
			else endtime = lang:formatDate( "d日", eTime )
			end
		elseif wiki == "lv" then
			if y ~= y2 then endtime = lang:formatDate( "Y. \\g\\a\\d\\a j. F", eTime )
			else endtime = lang:formatDate( "j. F", eTime )
			end
		elseif wiki == "pl" then endtime = lang:formatDate( "j xg Y", eTime )
		end
	end
	return starttime, endtime
end
local formats = data.formats 
-- Display the date, the mode changes the format
local function funcDate(date, mode)
	-- local date = '+2016-05-20'
	-- local mode = 'small'
	local format = formatswiki or formats
local lang = contentLanguage

	--handle problems with lack of precision
	local dispDate = date
	if date and string.sub(date,7,8)=='00' then	-- lack of month
		dispDate= string.sub(date,1,6).."01-01"..string.sub(date,12)
		if mode == 'long' or mode == 'onlyyear' or mode == 'monthly' then
			mode = 'onlyyear'
		else
			mode = 'nodate'
		end
	elseif date and string.sub(date,10,11)=='00' then -- lack of day
		dispDate= string.sub(date,1,9).."01"..string.sub(date,12)
		if mode == 'long' then
			mode = 'monthly'
		elseif mode == 'small' then
			mode = 'onlymonth'
		elseif mode == 'onlyday' then
			mode = 'nodate'
		end
	end
	if formatmode == nil then mode = 'nodate' end
	
	return contentLanguage:formatDate(formatmode, dispDate)
end
-- get the year for a race as a string, or an empty string
local function getYear(raceID)
	local year = firstValue(raceID, 'P580', 'time') or -- P580 is 'start time'
		firstValue(raceID, 'P585', 'time') -- P585 is 'point in time'
	if year then
		return string.sub(year, 2, 5)
	end
	return 
end
local function isdisqualified(p,q) --disqualification can use deprecated or P1534
	local cancelled=""
	local disqualified=false
	
	if p and p.rank=='deprecated' then
		cancelled='text-decoration:line-through;'
		disqualified=true
	else
		if q and q.P1534 and q.P15341.snaktype == 'value' then
			local tempdsq=q.P15341.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= strictLangwiki or strict
local correcttime, best, name, nametemp
local wantedLanguages = {}

	for i, lang in ipairs(lang_priority) do
		wantedLanguageslang = i
	end
--case one, one official name / period overloaded with other languages as qualifier
--for instance https://www.wikidata.org/wiki/Q195833
best = 999
	for _, p1448 in statements(teamID, 'P1448') do
		correcttime=true
		if timeOfRace and timeOfRace ~= then
			correcttime =checktime(p1448, p1448.qualifiers, timeOfRace)
		end
		if correcttime then 
			if p1448.qualifiers and p1448.qualifiers.P1448 then
				local q = p1448.qualifiers.P1448
			    best = 999
				for _, l in pairs(q) do
					if l.snaktype == 'value' then
						local lang = l.datavalue.value.language
						if wantedLanguageslang and wantedLanguageslang  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= strictLangwiki
	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 strictLanglanguage==nil and not officialname then
						--normally all "latin" languages use the same name, except for cyrillic translation
						local russianLabel= wikibase.getLabelByLang(riderID, "ru")
						if russianLabel then
							local russianEnd=string.sub(russianLabel, -3)
							if russianEnd~="вна" and russianEnd~="вич" then --otherwise rejected
								name=officialnametemp 
								correctlanguage=false
							end
						else -- no russian label, it is most probably not a cyrillic translation
							name=officialnametemp --any language latin
							correctlanguage=false
						end
					end
				end
				if startOfSeason~= nil then
					local q = p1813.qualifiers
					if q then
						local temp = checktime(name,q,startOfSeason)
						if temp then officialname = name end--if the time is correct than it is finished
					else
						officialname = name
					end
				else
					officialname = name
				end
			end
		end
	end
	if sitelink and officialname then --if there is an official name, then use it
		return checksitelink(sitelink, officialname), correctlanguage
	else
		if officialname then return officialname end
		if sitelink then
			if wiki == "de" then
				local label = wikibase.getLabelByLang(riderID, wiki)
				if label then
					local p27 = wikibase.getBestStatements(riderID, 'P27') -- P27 is country of citizenship
					if p271 and p271.mainsnak.snaktype == 'value' then
						local c = p271.mainsnak.datavalue.value.id
						if c=="Q159" or c=="Q184" or c=="Q212" or c=="Q232" then -- Q159, Q184, Q212, Q232 is Russia, Belarus, Ukraine, Kazakhstan
							return checksitelink(sitelink, label), correctlanguage
						end
					end
				end
			end
			if wiki == 'ru' then
				local label = revertfirstlast(mw.text.trim(string.gsub(sitelink, "%b()", ""), " "))
				return checksitelink(sitelink, label), correctlanguage
			else
				return checksitelink(sitelink, mw.text.trim(string.gsub(sitelink, "%b()",""), " ")), correctlanguage
			end
		end
		-- No WP article. Display label, and make it a red link if no other article uses the title
		local link
		local label = wikibase.getLabelByLang(riderID, wiki)
		if label then
			if wiki == 'ar' then
				link = make_IllWD2_link(riderID, label)
			else
				if wiki=='ru' then
					label=revertfirstlast(label)
				end
				if black_list( label) then
					link = label
				else
					local title = mw.title.new(label)
					if title and title.exists then
						link = label
					else
						link = "" .. label.. ""
					end
				end
			end
			return link, correctlanguage
		end
		-- No label in the local language. Try other languages, but don't link.
		correctlanguage=false
		if wiki == 'ar' then
			link = make_IllWD2_link(riderID)
		else
			link = getLabelFallback(riderID)
			if link then
				link = string.gsub(link, "%b()", "")
			else
				link = "(label missing)"
			end
		end
		return link, correctlanguage
	end
end
-- Get the countryID, return a single one, not a list
local function getCountryID(entityID, timeOfRace)
	local countryID
	
	if entityID then
		local stm = getStatementForTime(entityID, 'P1532', timeOfRace) -- P1532 is country for sport
		if stm == nil then
			stm = getStatementForTime(entityID, 'P17', timeOfRace) -- P17 is country
		end
		if stm then countryID = stm.mainsnak.datavalue.value.id end
	end
	return countryID
end
-- Get the name of a country 
local function getCountryName(countryID)
	local name = country_name_from_list(countryID)
	if name == nil then
		local label, lang = wikibase.getLabelWithLang(countryID)
		-- Uses standard language fallback. Should not return nil, nil, as all countries have English labels. 
		if lang == wikilang then
			name = label
		elseif lang then
			name = label .. ' (' .. lang .. ')'
		end
	end
	return name or 
end
-- Get sitelink with no wiki no formating 
local function getRawTeamLink(teamID)
	local sitelink
	local parentID = getParentID(teamID)
	if parentID then -- try parent team first
		sitelink = mw.wikibase.getSitelink(parentID)
	end
	if not sitelink then
		sitelink = mw.wikibase.getSitelink(teamID)
	end
	return sitelink
end
-- Get sitelink, categoryID and maybe country for a team.
	Returns sitelink, team category ID, countryID (only countryID if country arg is true 
local function getTeamLinkCat(teamID, timeOfRace, country, forceParentlink)
	local name, sitelink, catID, countryID, p31
	local parentID = getParentID(teamID)
	local season=false
	-- Find team category
	--Hypothesis, it is a season, look in P2094
	for _, p2094 in statements(teamID, 'P2094') do
		if checktime(p2094, p2094.qualifiers, timeOfRace) then
			if data.teamCatsp2094.mainsnak.datavalue.value.id then
				catID = p2094.mainsnak.datavalue.value.id
				season=true
				break
			end
		end
	end	
	--check if season
	if season==false then --otherwise already clear
		for _, p in statements(teamID, 'P31') do
			local natureID = p.mainsnak.datavalue.value.id
			if natureID=="Q53534649" then
				season=true
				break
			end
		end
	end
	--look by the parent, then P31 is used for the category
	if (not catID and parentID and season) then
		p31 = getStatementForTime(parentID, 'P31', timeOfRace)
	elseif not season then --it is the team look in the team directly
		p31 = getStatementForTime(teamID, 'P31', timeOfRace)
	end
	if p31 and data.teamCatsp31.mainsnak.datavalue.value.id then 
		catID = p31.mainsnak.datavalue.value.id 
	end
	-- Find country if needed
	if country or data.natTeamCatscatID then
		countryID = getCountryID(teamID, timeOfRace)
	end
	if countryID and data.natTeamCatscatID then
		if countryID=='Q145' then
			name = getCountryName('Q23666')
		else --to solve the United-Kingdom/Great Britain problem by national team
			name = getCountryName(countryID)
		end
		local t={Q20738667=34, Q54555994=35, Q99658502=36}
		if tcatID then --add U23, U19, B, (note: why "B" and not B)
			name = name ..' '..translate("headoftableIII",tcatID)
		end
		sitelink = getRawTeamLink(teamID)
	else
		-- It is not a national cycling team
		local isLocal
		if season and not forceParentlink then
			sitelink = wikibase.getSitelink(teamID)
			name, isLocal = getOfficialName(teamID, timeOfRace,true) --problem here is that the label will be used if no official name, official name of the parent would actually be better...
			if not sitelink and parentID then
				sitelink = wikibase.getSitelink(parentID)
			end
		else
			if parentID then -- try parent team first
				sitelink = wikibase.getSitelink(parentID)
				name, isLocal = getOfficialName(parentID, timeOfRace)
			end
			if not sitelink then
				sitelink = wikibase.getSitelink(teamID)
			end
		end

		if not name or (not isLocal and l10n"lang_priority") then
			local partName, partIsLocal = getOfficialName(teamID, timeOfRace)
			if partName and (not name or partIsLocal) then
				name = partName
			end
		end
	end
	if sitelink then
		if name then
			sitelink =  .. name .. 
		else
			sitelink =  .. sitelink .. 
		end
	else
if wiki == "ar" then
			local arlabel = mw.wikibase.getLabelByLang((parentID or ), 'ar') or ""
local texte = mw.wikibase.getLabelByLang(teamID, 'ar') or ""
sitelink = make_IllWD2_link((parentID or teamID), arlabel, name, texte)
else
if name then
sitelink = name
else
sitelink = (parentID and wikibase.getLabel(parentID)) or
wikibase.getLabel(teamID) or 'No name'
end
end
	end
	return sitelink, catID, countryID
end
local function getTeamCodeCat(teamID, timeOfRace)
	-- Find team category
	local codeUCI
	local p1998 =getStatementForTime(teamID, 'P1998', timeOfRace)
	if p1998 then
		codeUCI = p1998.mainsnak.datavalue.value
	else
		local parentID = getParentID(teamID)
		if parentID then
			p1998 =getStatementForTime(parentID, 'P1998', timeOfRace)
			if p1998 then
				codeUCI = p1998.mainsnak.datavalue.value
			end
		end
	end
	return codeUCI
end
local function getReference(lf,statement, outputLocal)
	local function formatRefDate(date, precision)
		if precision == 9 then -- Precision is year
			return string.sub(date, 2, 5)
		elseif precision == 10 then -- Precision is month
			return contentLanguage:formatDate("F Y", string.sub(date, 2, 8))
		elseif precision >= 11 then -- Precision is day (or less)
			return funcDate(date, 'long')
		end
	end
	local ref = statement.references
	if not ref or not ref1 then
		return nil
	end
	ref = ref1.snaks
	if ref.P854 and ref.P8541 and ref.P8541.snaktype == 'value' then -- P854 is 'reference URL'
		local refURL = ref.P8541.datavalue.value
		local refTitle = 
		local refDate = 
		local refRetrieved = 
		local refLang = 
		if ref.P1476 and ref.P14761 and ref.P14761.snaktype == 'value' then -- P1476 is 'title URL'
			refTitle = ref.P14761.datavalue.value.text
			local lang = ref.P14761.datavalue.value.language
			if lang ~= wikilang then
				refLang = '(' .. lang .. ')'
if wiki == 'ar' then refLang = lang end
end
		end
		if ref.P577 and ref.P5771 and ref.P5771.snaktype == 'value' then -- P577 is 'publication date'
			local value = ref.P5771.datavalue.value
			refDate = formatRefDate(value.time, value.precision)
			if (wiki == 'ar') then refDate = refDate
			else refDate = ', ' .. refDate
			end
		end
		if ref.P813 and ref.P8131 and ref.P8131.snaktype == 'value' then -- P813 is 'retrieved'
			local value = ref.P8131.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 = 
elseif wiki == "fr" then
-- fr: "(en) « Lloyd Mondory ... EPO », sur velonews.competitor.com (consulté le 30 april 2016), 30 octobre 2015."
			local sur = ', sur  ' .. domain .. 
			refText = refLang .. ' « '.. refURL .. ' '.. refTitle .. ' »' .. sur .. refRetrieved .. refDate .. '.'
		elseif wiki == "de" then
			local In = ' In: ' .. domain .. 
			refText = .. refURL.. ' '.. refTitle.. '. ' ..
				In .. refDate .. refRetrieved ..'.'
		else
			local at = ',  ' .. domain .. 
			refText = refLang .. ' ' .. refURL .. ' ' .. refTitle ..  .. at .. refDate .. '.' .. refRetrieved
		end
		if outputLocal==1 then
			return refText
		else
local refargs = {}
if wiki ~= "ar" then 
refargs.name = refText
end
			return lf:extensionTag('ref', refText, refargs)
		end
	end
end
--Some wikipedia, like WP:ar, don't use model like
--Q123
--But have the module included in another module
--