وحدة:Cycling race

من ويكيبيديا، الموسوعة الحرة
اذهب إلى التنقل اذهب إلى البحث

وحدة:Cycling race هي "وحدة سوبر" مستضافة على ويكي بيانات، وتُطور بشكل أساسي في ويكيبيديا الفرنسية بالإضافة إلى ويكي بيانات.

الوظائف الأساسية[عدل]

قوالب {{سباق الدراجات}} الفرعية:            عدل

قوائم
  • {{سباق الدراجات/قائمة الفائزين}}، listofwinners، يستخدم لسرد قائمة بالفائزين خلال سنوات السباق.
  • listofwinnersChamp
  • listofwinnersChampfirstpart
  • listofwinnersChampsecondpart
  • listofwinnersfirstpart
  • listofwinnerssecondpart
  • listofmountainwinners
  • listofpointswinners
  • listofyoungwinners
  • {{سباق الدراجات/startlist}} ، startlist
مقالة السباق الرئيسي
مقالات مواسم
مقالات المراحل
مقالات الفرق
الدراجون


تحديث الوحدة[عدل]

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

-- == 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

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

--== I) Classes declared as global ==
-- Class of a cycling race. Class is: 1.UWT, 2.UWT, 1.HC, ... add new classes, no problem

--Data that requires # functions and cannot be called with mw.loadData
local class = {
    "Q60669124",  -- Am (Q60669124)
    "Q22231118",  -- CC (Q22231118)
    "Q23015458",  -- CDM (Q23015458)
    "Q22231119",  -- CN (Q22231119)
    "Q60181400",  -- NE (Q60181400)
    "Q23005601",  -- 1.WWT (Q23005601)      
    "Q23005603",  -- 2.WWT (Q23005603)
    "Q22231106",  -- 1.UWT (Q22231106)
    "Q22231107",  -- 2.UWT (Q22231107)
    "Q74275170",  -- 1.Pro (Q74275170)
    "Q74275176",  -- 2.Pro (Q74275176)
    "Q101069484", -- 1.PT (Q101069484) 
    "Q101052547", -- 2.PT (Q101052547)
    "Q22231108",  -- 1.HC (Q22231108)
    "Q22231109",  -- 2.HC (Q22231109)
    "Q22231110",  -- 1.1 (Q22231110)
    "Q22231111",  -- 1.2 (Q22231111)
    "Q30336909",  -- 1.3 (Q30336909)
    "Q30339152",  -- 1.4 (Q30339152)
    "Q98686837",  -- 1.5 (Q98686837)
    "Q60669131",  -- 1.7.1 (Q60669131)
    "Q22231112",  -- 2.1 (Q22231112)
    "Q22231113",  -- 2.2 (Q22231113)
    "Q101052391", -- 2.3 (Q101052391)
    "Q101052353", -- 2.4 (Q101052353)
    "Q29866603",  -- 2.5 (Q29866603)
    "Q101049923", -- 2.6 (Q101049923)
    "Q22231116",  -- 1.2U (Q22231116)
    "Q22231117",  -- 2.2U (Q22231117)
    "Q22231114",  -- 1.Ncup (Q22231114)
    "Q22231115"  -- 2.Ncup (Q22231115)
    }

local class_without2x = { 
    "Q23005601",  -- 1.WWT (Q23005601)      
    "Q22231106",  -- 1.UWT (Q22231106)
    "Q74275170",  -- 1.Pro (Q74275170)
    "Q101069484", -- 1.PT (Q101069484)
    "Q22231108",  -- 1.HC (Q22231108)
    "Q22231110",  -- 1.1 (Q22231110)
    "Q22231111",  -- 1.2 (Q22231111)
    "Q30336909",  -- 1.3 (Q30336909)
    "Q30339152",  -- 1.4 (Q30339152)
    "Q98686837",  -- 1.5 (Q98686837)
    "Q60669131",  -- 1.7.1 (Q60669131)
    "Q22231116",  -- 1.2U (Q22231116)
    "Q22231114"  -- 1.Ncup (Q22231114)
    }

local class_champ = { 
    "Q22231118", 
    "Q22231119", 
    "Q23015458"
    }
local stages = {
    'Q18131152', 
    'Q20646667', 
    'Q20646670', 
    'Q20680270', 
    'Q20646668', 
    'Q20679712', 
    'Q2348250', 
    'Q2266066', 
    'Q485321'
    }
local UCI_Circuits = {
    'Q1194340', -- Europa
    'Q1063423', -- Asia
    'Q1063430', -- America
    'Q268357', -- Africa
    'Q1039648', -- Oceania
    'Q1329578', -- ProTour
    'Q12270097', -- World Calendar
    'Q635366', -- World Tour
    'Q21075974', -- Wonen World Tour
    'Q1693153', -- Women's Road World Rankings
    "Q71580493"-- ProSeries
    }
local class_2x = {
    "Q23005603",  -- 2.WWT (Q23005603)
    "Q22231107",  -- 2.UWT (Q22231107)
    "Q74275176",  -- 2.Pro (Q74275176)
    "Q101052547", -- 2.PT (Q101052547)
    "Q22231109",  -- 2.HC (Q22231109)
    "Q22231112",  -- 2.1 (Q22231112)
    "Q22231113",  -- 2.2 (Q22231113)
    "Q101052391", -- 2.3 (Q101052391)
    "Q101052353", -- 2.4 (Q101052353)
    "Q29866603",  -- 2.5 (Q29866603)
    "Q101049923", -- 2.6 (Q101049923)
    "Q22231117",  -- 2.2U (Q22231117)
    "Q22231115"  -- 2.Ncup (Q22231115)          
    }

--dictionnaries
local classes=data.classes 
local class_sort=data.class_sort
local bg_color_table = data.bg_color_table

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 standardtablecss=data.standardtablecss_part1..textalign..data.standardtablecss_part2

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

backgroundColor="#FFDF80"
for _, value in pairs(silver_theme_countries) do -- get data if country should be printed in this wiki
    if value == wiki then backgroundColor="#EAECF0" end
end

--== II) Translation ==
local function translate(func_name_short, index, 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=func_name_short.."_translate"		
            if l10n[func_name]['ar'][index] then 
                return l10n[func_name]['ar'][index]
            elseif l10n[func_name][index] then 
                return l10n[func_name][index]
            end
        else 
            return "error: no func_name found"
        end
    end	 
    return ''
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
 
    if x=='plain stage' then return "[[File:Plainstage.svg"..border.."|20px|"..l10n.plain.."]]" end
    if x=='hilly stage' then return "[[File:Hillystage.svg"..border.."|20px|"..l10n.hilly.."]]" end
    if x=='intermediate stage' then return "[[File:Mediummountainstage.svg"..border.."|20px|"..l10n.inter.."]]" end
    if x=='mountain stage' then return "[[File:Mountainstage.svg"..border.."|20px|"..l10n.mount.."]]" end
    if x=='uphill time trial stage' then return "[[File:Mountain Time Trial Stage.svg"..border.."|20px|"..l10n.uphill.."]]" end
    if x=='rest day' then return "[[File:Stage rest day.svg"..border.."|20px|"..l10n.rest.."]]" end
    if x=='time trial stage' then
        if noborder then border="" else border="|right" end
        if typ==2348250 then return "[[File:Team Time Trial Stage.svg"..border.."|20px|"..l10n.time_team.."]]" end
        if typ==2266066 then return "[[File:Time Trial.svg"..border.."|20px|"..l10n.time_indiv.."]]" end
        if typ==485321  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['numeric-id']
            if iOf == 20646667 then sType = typeofstage('plain stage', nil, noborder) break end
            if iOf == 20646670 then sType = typeofstage('hilly stage', nil,moborder) break end
            if iOf == 20680270 then sType = typeofstage('intermediate stage', nil,noborder) break end
            if iOf == 20646668 then sType = typeofstage('mountain stage',nil, noborder) break end
            if iOf == 485321 then sType = typeofstage('time trial stage', 485321, noborder) break end -- prologue
            if iOf == 2266066 then sType = typeofstage('time trial stage', 2266066, noborder) break end -- individual time trial
            if iOf == 2348250 then sType = typeofstage('time trial stage', 2348250, noborder) break end -- team time trial
            if iOf == 20679712 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, label)
    return mw.getCurrentFrame():expandTemplate{ title = 'Ill-WD2', args = {id= q ,target='en',label = label } }
end

--[[ Iterator to get all statements for an entity and property which are not deprecated and have a value]]
local function nextStatement(state, i)
    local s
    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)
    local q
    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

--== 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

--[[ Get start time of race as a timevalue ('+2016-01-01T00:00:00Z') or nil ]]
local function getTimeOfRace(raceID)
    local timeOfRace
    local p580 = mw.wikibase.getBestStatements(raceID, "P580") -- P580 is start time
    if p580[1] and p580[1].mainsnak.snaktype == 'value' then
        timeOfRace = p580[1].mainsnak.datavalue.value.time
    else
        local p585 = mw.wikibase.getBestStatements(raceID, "P585") -- P585 is point in time
        if p585[1] and p585[1].mainsnak.snaktype == 'value' then
            timeOfRace = p585[1].mainsnak.datavalue.value.time
        else
            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
    return timeOfRace, '> Wikidata is missing data about start time (P580) or point in time (P582)'
end

local function getStartEndTime(sTime, eTime, mode)
    -- Note: Add the 4formats to "formats" and use funcDate
    local lang = contentLanguage
    local starttime, endtime
    --local format = formats[wiki] or formats['']
    if mode==nil then mode='long' end
    -- Timevalues is like "+2015-07-04T00:00:00Z"
    local y, m = string.match(sTime, "(%d+)-(%d+)-%d+")
    local y2, m2 = string.match(eTime, "(%d+)-(%d+)-%d+")
    
    if m=='00' then --manage the 30 November issue
        if  mode=='long' 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
            local date_pl = {"stycznia", "lutego", "marca", "kwietnia", "maja", "czerwca", "lipca", "sierpnia", "września", "października", "listopada", "grudnia"}
            if y ~= y2 then starttime = lang:formatDate( "j ", sTime ) .. date_pl[tonumber(lang:formatDate( "n", sTime ))] .. lang:formatDate( " Y", sTime )
            elseif m ~= m2 then starttime = lang:formatDate( "j ", sTime ) .. date_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' or y ~= y2 then
            endtime = lang:formatDate("j F Y", 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
            local date_pl = {"stycznia", "lutego", "marca", "kwietnia", "maja", "czerwca", "lipca", "sierpnia",
                "września", "października", "listopada", "grudnia"}
            endtime = lang:formatDate( "j ", eTime ) .. date_pl[tonumber(lang:formatDate( "n", eTime ))] ..
            lang:formatDate( " Y", eTime )
        end
    end
    return starttime, endtime
end

local formats = data.formats 

local function funcDate(date, mode)
    -- local date = '+2016-05-20'
    -- local mode = 'small'
    local format = formats[wiki] or formats['']
    local lang = contentLanguage

    --handle problems with lack of precision
    local 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
        return contentLanguage:formatDate(format[mode], date)
    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)
                return string.sub(contentLanguage:formatDate(format[mode], newdate), 3) --cut the day
            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) -- for team
    --return officialName, isLocal
    local slavicWikis = {mk = true, ru = true}
    local wikiIsSlavic = slavicWikis[wiki]

    local p1448 = getStatementForTime(teamID, 'P1448', timeOfRace) -- P1448 is official name
    if p1448 then
        if available_lang_priority and p1448.qualifiers and p1448.qualifiers.P1448 then
            local q = p1448.qualifiers.P1448
            local wantedLanguages = {}
            local best = 999
            local name
            for i, lang in ipairs(translations.lang_priority) do
                wantedLanguages[lang] = i
            end
            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
        lang=p1448.mainsnak.datavalue.value.language
        if not wikiIsSlavic and slavicWikis[lang]==nil then
            return p1448.mainsnak.datavalue.value.text, false --then prefer label
        end
    end
    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 slavicWikis = {mk = true, ru = true}
    local sitelink = wikibase.getSitelink(riderID)
    local officialname,officialnametemp, language, name
    local wikiIsSlavic = slavicWikis[wiki]
    local correctlanguage=true
    local listOfProperty={'P1813','P1448'}

    for _, prop in ipairs(listOfProperty) do
        for _, p1813 in statements(riderID, prop) do
            if not officialname then
                language = p1813.mainsnak.datavalue.value.language
                officialnametemp = p1813.mainsnak.datavalue.value.text
                if wikiIsSlavic then
                    if wiki==language then
                        name=officialnametemp --only exact language
                    end
                else
                    if wiki==language then --exact language --> ok
                        name=officialnametemp
                    elseif slavicWikis[language]==nil 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 
                            end
                        else -- no russian label, it is most probably not a cyrillic translation
                            name=officialnametemp --any language latin
                        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
                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['numeric-id']
                        if c==159 or c==184 or c==212 or c==232 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)
            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
    -- Find team category
    local teamCats = {
        Q6154783 = true, Q20638319 = true, Q382927 = true, Q1756006 = true, Q23726798 = true,
        Q20738667 = true, Q28492441 = true, Q20639848 = true, Q20639847 = true, Q20652655 = true,
        Q20653563 = true, Q20653564 = true, Q20653566 = true, Q2466826 = true, Q26849121 = true,
        Q78464255 = true, Q80425135=true, Q54660600=true, Q54555994=true, Q99658502=true, 
        Q20653570=true
    }
    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

    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
        countryID = firstValue(teamID, 'P1532', 'id') -- P17 is country for sport
        if countryID == nil then
            countryID = firstValue(teamID, 'P17', 'id') -- P17 is country
        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
        name = getCountryName(countryID)
        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 = ' "B"'
            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 name then
            sitelink = name
        else
            sitelink = (parentID and wikibase.getLabel(parentID)) or
                wikibase.getLabel(teamID) or 'No name'
        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(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 .. ')'
            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 == "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
            return localframe:extensionTag('ref', refText, {name=refText})
        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)
    local sitelink = wikibase.getSitelink(placeID)
    if sitelink then
        -- Delete " (...)" form e.g. "Unley (South Australia)"
        return '[[' .. sitelink .. '|' .. string.gsub(sitelink, ' %b()', '') .. ']]'
    end
    local label = wikibase.getLabel(placeID) or ''
    if wiki == 'ar' then
        return make_IllWD2_link( placeID,label)
            -- '[[' .. label.. ']]'
    end
    return contentLanguage:ucfirst(label)
end

-- ClassID --> ClassLink
-- some WPs use a unique article for this case
local function classLinkFn(class)
    local link 
    if wiki~="fr" then --not used
        link= wikibase.getSitelink('Q22348500') -- Q22348500 is 'cycling race class'
    end
    local label = getLabelFallback(class, {wikilang, 'en', 'fr', 'de'})
    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 , "")
    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
        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
    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 = 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 = getTeamLinkCat(teamID, timeOfRace)
                    end
                end
            end
        end
    end
    return link, teamID
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)
    return "[[File:Wikidata-logo S.svg|12px|link=d:" .. id .. "]]"
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
        link = make_IllWD2_link(Qnumber , 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.title) 
    if s.header_1 == 19 and wiki == "ar" then title = title .. " " .. s.year 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:tag('span'):cssText('float:left; margin: 0 5px'):wikitext('[[File:Wikidata-logo S.svg|12px|link=d:'.. s.item.. '#'.. s.property..']] '.. error_message)
    caption:wikitext(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))
            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))
            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.5em 0;"..
                "background-color: rgb(255, 255, 255); padding: 5px; float: left;"..
                "clear: left; ; text-align: left; vertical-align: top; font-size: 85%; line-height: 1.8em;"
    local wdLink = '[[File:Wikidata-logo S.svg|12px|link=d:'.. s.item.. '#'.. s.property..']] '.. error_message
    
    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:tag('span'):cssText('float:' .. floattable):wikitext(wdLink)
        tSpan:wikitext(title)
        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','4')
        :cssText(cssTable)
        tCell = tTable:tag('tr'):tag('th')
        :css("background-color",backgroundColor)
        :attr('colspan','3'):attr('align','center')
        tCell:tag('span'):cssText('float:left'):wikitext(wdLink)
        tCell:wikitext(translate("startlist",1))
        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'}},
        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'}},
        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'}},
        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'}},
    }

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
    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
        return '[[File:' .. file .. '|border|' .. flagpxSize ..'|' .. IOC .. ']]'
    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
            return '[[File:' .. p41[1].mainsnak.datavalue.value .. '|border|' .. flagpxSize ..'|(Wikidata:' .. countryID .. ')]]' .. trackingCategory
        end
    else
        -- Search flag for specific date
        local p41 = getStatementForTime(countryID, "P41", date) -- P41 is flag image
        if p41 then
            return '[[File:' .. p41.mainsnak.datavalue.value .. '|border|' .. flagpxSize ..'|(Wikidata:' .. countryID .. ')]]' .. trackingCategory
        end
    end
    return 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> '
        else
            return ''
        end
    else
        return ''
    end
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', 'Q24645383', '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', 'Q24645383', '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', 'Q24645383', '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', 'Q24645383'}, -- 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', 'Q24645383'}, -- 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', 'Q24645383'}, -- 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', 'Q24645383'}, -- 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 ''
    if item then
    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
    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 = 'зелёная майка лидера очковой классификации'
        },
    ['Q24645383'] = {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['numeric-id'] == 5 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['numeric-id'] == 6256 or iOf.mainsnak.datavalue.value['numeric-id'] ==15634554 or iOf.mainsnak.datavalue.value['numeric-id'] ==779415) then
                isCountry = true
                break
            end
        end
    end
    return isCountry
end

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

    if riderId then
        if isHuman(riderId) then
            riderLink = getRiderLink(riderId, timeOfRace)
            local p27 = getStatementForTime(riderId, 'P27', timeOfRace) --P27 is country of citizenship
            if p27 then
                countryID = p27.mainsnak.datavalue.value.id
            end
            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
                                        local p27 = getStatementForTime(wID, 'P27', timeOfRace) --P27 is country of citizenship
                                        if p27 then
                                            countryID = p27.mainsnak.datavalue.value.id
                                        end
                                    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 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[1]=timeOfRace
    outTable[2]=tostring(tCell)
    outTable[3]=sortkey
    return outTable
end

local function fn_country(entityID, timeOfRace,countrybool, fn_racetable)
    -- This function gives countries where the race take place
    -- parentID taken from fn_race, optional
    
    --outTable[1] is the cell
    --outTable[2] is the name of the country
    --outTable[3] is the flag
    local country, countryname, outTable= {}, {}, {}
    local countryID, parentID, raceSitelink
    
    if fn_racetable~=nil then
        raceSitelink = fn_racetable[1] --only for country false
        parentID=fn_racetable[3]
    end
    
    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[3]=flag(countryID, timeOfRace)
                    end
                end
            end
        end
    end

    if countryID == nil then outTable[3]="no flag" end
    if countryname[1] then tCell:attr('data-sort-value',countryname[1]) end
    if countrybool==false then
        tCell:wikitext(country[1].." "..(raceSitelink or ''))
        outTable[2]=''
    else
        if countryname[1] then
            outTable[2]=countryname[1]
            if country[1] then tCell:wikitext(country[1]) end
        else
            outTable[2]=''
        end
        
    end
    outTable[1]=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[1]=stageNumber..comma
    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[2]=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
    
    Sitelink=wikibase.getSitelink(entityID)
    prefix=''; postfix='' --general classification
    listOfProperty={'P2561','P1448'}
    
    --system with P3450 and P2094
    instanceOf=firstValue(entityID, 'P3450', 'id')
    if instanceOf==nil then
        for _, p31 in statements(entityID, 'P31') do
            instanceOfTemp = p31.mainsnak.datavalue.value.id
            isclass=false
            for _,thisClass in ipairs(class) do--we don't want the class, but the main race
                if instanceOfTemp == thisClass then isclass=true end
            end     
            if isclass==false then
                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
                            end
                        end
                    end
                end
            end
        end

        if label==nil then
            label=wikibase.label(instanceOf)
            if not label then
                label = getLabelFallback(entityID, {'en', 'fr', 'de'}) or ''
            end
        end
        if Sitelink==nil then --only if no link to the race direct
            Sitelink=wikibase.getSitelink(instanceOf)
        end
        if Sitelink==nil and entity_type=='champ' then --only for champ
            local temp=firstValue(instanceOf, 'P361','id')
            if temp then Sitelink= wikibase.getSitelink(temp) end
        end
    end
    --affect the label
    if label==nil then
        label=wikibase.label(entityID)
        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[1]
        postfix=commaTable[2]
    end

    if Sitelink == nil then
        return prefix..label..postfix
    else
        return prefix..'[['..Sitelink..'|'..label..']]'..postfix
    end
end

local function fn_getClassInfo(entityID,instanceOf, displayed_class) --get the class of the race
    --with only P31, it is necessary to check if the entityID is a class, with P2094, it is not necessary
    
    local display=false
    local outTable={}
    local entity_type, classText, sortkey_class, classID
    
    if displayed_class==nil then
        display=true
    else
        for _, thisClass in ipairs(displayed_class) do
            if instanceOf ==thisClass then 
                display=true break 
            end
        end
    end
    listOfClassesList = {class_champ,class_2x, class_without2x}
    listOfClassesName = {'champ', '2','1'}
    
    classID=firstValue(entityID, 'P2094', 'id')
    if classID==nil then 
        classIDs={instanceOf} 
    else
        classIDs={classID, instanceOf} --try the first and then the second 
    end
    
    for _, class_id in ipairs(classIDs) do
        for ii, thisClassesList in ipairs(listOfClassesList) do
            if entity_type==nil then --break
                for _, thisClass in ipairs(thisClassesList) do
                    if class_id == thisClass then
                        entity_type = listOfClassesName[ii]
                        classText = mw.wikibase.label(thisClass)
                        sortkey_class = class_sort[thisClass]
                    end
                end
            end
        end
    end

    if entity_type==nil then entity_type = 'nada' end--to allow display of race without class...

    if display~=false then
        outTable[1]=entity_type
        outTable[2]=classText
        outTable[3]=sortkey_class
        outTable[4]=instanceOf --save the class
    end
    return outTable
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, classText, child, q) 
    local displayedCircuitID, circuitID, classLink, circuitLink, circuitLinkFull
    
    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
                        for i=1,#UCI_Circuits do
                            if parentCircuitID == UCI_Circuits[i] then  --Yes it is
                                displayedCircuitID=circuitID
                                break
                            end
                        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
        
        if wikibase.getSitelink('Q22348500') and wiki~="fr" then --for the WP that use this element
            classLink = classLinkFn(classID)
        end
    end
    
    if displayedCircuitID~=nil then
        circuitLink = wikibase.getSitelink(displayedCircuitID) --we display the circuit of the year
        circuitLinkFull=WPlinkpure(displayedCircuitID)  
        if circuitLink ~= nil and not classLink then --do not erase  Q22348500
            if classText ~= nil then 
                classLink = '[['..circuitLink..'|'..classText..']]' 
            else
                classLink = '[['..circuitLink .. ']]' 
            end
        end
    elseif not classLink and classText~=nil then
        classLink=classText
    end
    return classLink, circuitLinkFull
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 getPeriod(q, brackets)
    local sTime, startTime, eTime, endTime

    sTime, eTime = getStartEndfromQuali(q)
    if sTime then startTime= funcDate(sTime,'Y') end
    if eTime then endTime =funcDate(eTime,'Y') end

    local period
    if sTime and eTime then
        period=startTime .. '-'..endTime
    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

local function getClass(entityID)
    local classLink, circuitLink, SiteLink
    local classTable={}

    for ii, p279 in statements(entityID, 'P279') do
        if p279 and p279.mainsnak.snaktype == 'value' then
            temp = p279.mainsnak.datavalue.value.id
            classID=nil
            for jj=1,#class do -- #class = number of elements in class
                if temp == class[jj] then 
                    classID=temp
                    classText = wikibase.label(temp) 
                    break 
                end
            end
            if classID then 
                classLink, circuitLink=classToCircuit(classID, entityID, classText, false,p279.qualifiers) 
                if classLink then
                    local period, sTime=getPeriod(p279.qualifiers, true)
                    local classStr = classLink .. " <small>"..period.."</small>"
                    table.insert(classTable, {sTime, classStr, circuitLink})
                end
            end
        end
    end
    
    table.sort(classTable, function(a, b) return a[1] < b[1] end)
    for _, class in pairs(classTable) do
        if not str then str='' else str=str..'<br>' end
        str=str..class[2]
        circuitLink=class[3]
    end

    return str, circuitLink, #classTable
end

local function fn_race(entityID,displayed_class,displayclass,timeOfRace, functionName,country)--return link to the race and class
    --first function read from victory main
    
    --outTable[1] is the cell with the race, or sitelink if country is false
    --outTable[2] is the cell with the class
    
    local Sitelink,instanceOf,instanceOfTemp,circuitID,parentCircuitID
    local classLink, entity_type, classID, classText
    local inputtable, outTable={}, {}
    local display=true -- should be true to work, bypassed
    local sortkey_class = ''
    local stageID=entityID

    for _, p31 in statements(entityID, 'P31') do
        instanceOf = p31.mainsnak.datavalue.value.id
        for i=1,#stages do --is it a stage?
            if instanceOf == stages[i] then
                entity_type = 'stage'  --then the class is one stage above!
                local parentID = getParentID(entityID)
                entityID = parentID
                outTable[3] = parentID --as we read it here, no need to read it afterwards
                display = true
                for _, p31bis in statements(parentID, 'P31') do
                    local instanceOfbis = p31bis.mainsnak.datavalue.value.id
                    inputtable=fn_getClassInfo(parentID, instanceOfbis,displayed_class)
                    if inputtable[1]~=nil and inputtable[1]~='nada' then
                        classText =inputtable[2]
                        sortkey_class=inputtable[3]
                        classID=inputtable[4]
                    end
                end
            end
        end

        if entity_type==nil then  --bypass if stage
            inputtable=fn_getClassInfo(entityID,instanceOf,displayed_class) --if a P2094 is present, the instanceOf does not matter
            if inputtable[1]==nil then
            elseif inputtable[1]=='nada' then --no display="inputtable[1]==nil" inputtable[1]=='nada'--> display but empty
                display=true
            else
                display=true
                entity_type=inputtable[1]
                classText =inputtable[2]
                sortkey_class=inputtable[3]
                classID=inputtable[4]
            end
        end
    end
    --Now we have the class and know the type of race it is
    if display then
        if entity_type == 'stage' then
            Sitelink=getMainRaceLink(entityID,entity_type,stageID, functionName,timeOfRace)
        else
            Sitelink=getMainRaceLink(entityID,entity_type,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[1]=tostring(tCell)
        else
            outTable[1]=Sitelink --already opened
        end
        
        if displayclass == true then
            classLink, _ =classToCircuit(classID, entityID, classText, true, nil) 
            if not classLink then classLink="" end
                
            local tCell=mw.html.create('td')
            :attr('data-sort-value',sortkey_class)
            :cssText("text-align:center;padding:0 0.5em")
            :wikitext(classLink)
            
            outTable[2]=tCell
        end
    end

    return outTable
end

local function fn_rider(entityID,timeOfRace,displayteam,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, displayteam, 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)
    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 = 'Q'..p527.mainsnak.datavalue.value['numeric-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

    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' 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

    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
    evaluateWinnerMax(t)

    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 slavicWikis = {mk = true, ru = true}
    local officialname,officialnametemp, language
    local wikiIsSlavic = slavicWikis[wiki]
    local correctlanguage=true
    local listOfProperty={PID}

    for _, prop in ipairs(listOfProperty) do
        for _, p1813 in statements(itemID, prop) do
            officialname=nil
            language = p1813.mainsnak.datavalue.value.language
            officialnametemp = p1813.mainsnak.datavalue.value.text
            if wikiIsSlavic then
                if wiki==language then
                    officialname=officialnametemp --only exact language
                end
            else
                if slavicWikis[language]==nil then
                    officialname=officialnametemp --any language latin
                end
            end

            local period, sTime=getPeriod( p1813.qualifiers)
            if officialname then
                table.insert(listOfNames,{sTime, period, officialname, language})
            end
        end
    end
    if #listOfNames > 0 then 
	    table.sort(listOfNames, function(a, b) return a[1] < b[1] end)
	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 km
    if wiki == "ar" then km = 'كجم'
    elseif wiki == "mk" then km = 'kg'
    elseif wiki == "ru" then km = 'kg'
    elseif wiki == "ja" then km = ''
    else km = 'kg' end
    return km
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'
    if not p[1] then
        p = mw.wikibase.getBestStatements(raceID, 'P2043') -- P2043 is 'length'
    end
    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 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)..' m'
        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=="" 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_sing = (direction == 'ltr') and '&#x25C0;' or '&#x25B6;'
    local next_sing = (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_sing .. this_label .. ']]</span>'
        else
            previousText = '<span style="color:#3366CC">' .. previous_sing .. '</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_sing .. ']]</span>'
        else
            nextText = this_label .. ' <span style="color:#3366CC">' .. next_sing .. '</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)
    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)
    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)
    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['numeric-id']
            if location == 529711 then -- Q529711 is 'beginning'
                if not details[index].content then details[index].content = amount end -- participants at start
            elseif location == 12769393 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
        if  cellpadding then 
            cellpadding=tostring(cellpadding)
        else
            cellpadding='4'
        end
        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, commons_cat)
    local tCell=tab:tag('tr'):tag('td')
    local tC
    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
    tC:cssText('text-align:right; border-top:3px solid '..backgroundColor..'; font-size:75%')
    :wikitext("[[" .. s .. "|" .. translation .. "]] [[File:Wikidata-logo S.svg|12px|link=d:".. ID .."]]")
end

local function listWPlink(details, index, entityID, PID)
    local org={}
    for _, p in statements(entityID, PID) do 
        if p and p.mainsnak.snaktype == 'value' then
            table.insert(org,WPlinkpure(p.mainsnak.datavalue.value.id))
        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

-- == 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)
    ----- function to display calendar of any competition -----
    local function getargs(frame, fieldname, headertemp, tempdic)
        local argindex=tempdic[fieldname][1]

        if frame.args[argindex] ~= nil and tonumber(frame.args[argindex]) ==1 then
            tempdic[fieldname][3]= tempdic[fieldname][4]
            table.insert(headertemp, tempdic[fieldname][2])
        end
        return headertemp, tempdic
    end
    
    -- position in args,  header_column, default value,other value
    local headertemp={2} --date
    local tempdic = {
        ['numbering']={2, 3, false, true},
        ['displayclass']={4, 6, false, true},
        ['displayleader']={6, 10, false, true}
    }

    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

    headertemp, tempdic= getargs(frame, 'numbering', headertemp, tempdic)
    if tempdic['numbering'][3] then countrycolumn=3 else countrycolumn=2 end

    local no_countrytemp={}
    if frame.args[3] ~= nil and tonumber(frame.args[3]) ==1 then no_countrytemp={wiki} end
    -- country --
    table.insert(headertemp, 5)
    --race--
    table.insert(headertemp, 4)

    headertemp, tempdic= getargs(frame, 'displayclass', headertemp, tempdic)
    
    local onlywinnertemp =1
    if frame.args[5] ~= nil and tonumber(frame.args[5]) ==1 then
        onlywinnertemp =0
    end
    table.insert(headertemp, 7) --winner
    if onlywinnertemp==0 then
        table.insert(headertemp, 8)
        table.insert(headertemp, 9)
    end
    headertemp, tempdic= getargs(frame, 'displayleader', headertemp, tempdic)   

    local displayteamtemp =false
    if frame.args[7] ~= nil and tonumber(frame.args[7]) ==1 then displayteamtemp =true end

    local data_typetemp={}
    for ii=1,#headertemp do
        table.insert(data_typetemp,'')
    end

    local titletemp=wikibase.getLabel(calendarID)
    local displayed_all = nil
    local ddi = frame.args["displayed_all_class"] or frame.args.displayed_all_class
    if ddi and ddi  ~= "" then
        displayed_all  = true
    end
    
    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 = headertemp,-- 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 = countrycolumn,
        data_sort_type = data_typetemp, -- see https://meta.wikimedia.org/wiki/Help:Sorting
        item = calendarID,
        property = 'P527',
        no_country = no_countrytemp,
        only_winner = onlywinnertemp,
        numbering =  tempdic['numbering'][3],
        error_message = 0,
        displayed_class =nil,
        displayteam=displayteamtemp,
        displayclass= tempdic['displayclass'][3],
        leadercolumn= tempdic['displayleader'][3],
        displayed_all_class = displayed_all,
        offset = frame.args["offset"],
        limit = frame.args["limit"],
        frame=frame
    }
    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,
        numbering=true,
        displayteam=false,
        displayclass=false,
        leadercolumn=true
    }   
    local tempdic2 = {
        header_2 =   {2, 5, 4, 6, 7},
        only_winner =1,
        numbering=false,
        displayteam=true,
        displayclass=true,
        leadercolumn=false
    }

    for key, v in pairs(UCI) do
        if (calendarID == "" or 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
            if wiki == "ar" and frame.args["code"] and frame.args["code"] ~= "" then
                display_code = 1
            end
        end
    end
    if wiki == "ar" and calendarID == "" and ( frame.args["test"] or frame.args.test) then
        calendarID = frame.args["test"]  or frame.args.test
    end
    if not calendarID or calendarID == "" then return "" end
    if display_code == 1 then
        tempdic=tempdic1
    else
        tempdic=tempdic2
    end

    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,
        numbering = tempdic.numbering,
        error_message = 0,
        displayed_class = {
            "Q23005603", --
            "Q22231110", -- 1.1
            "Q22231109", -- 2.HC
            "Q22231111", -- 1.2
            "Q22231108", -- 1.HC
            "Q22231106", -- 1.UWT
            "Q74275170", -- 1.Pro
            "Q22231107", -- 2.UWT
            "Q22231113", -- 2.2
            "Q22231112", -- 2.1
            "Q22231113", -- 2.2
            "Q22231109", -- 2.HC
            "Q74275176", -- 2.Pro
            "Q22231118", -- CC
            },
        displayteam=tempdic.displayteam,
        displayclass=tempdic.displayclass,
        leadercolumn=tempdic.leadercolumn,
        frame=frame
    }
    return calendar_main(s, tableA(s))
end

function calendar_main(s, resultTable)--Display the UCI women calendar of one year
    localframe=s.frame
    local displayed_all_class =  s.displayed_all_class
    local limit = tonumber(s.limit) or 250
    local offset = tonumber(s.offset) or 0
    local offset_limit = offset + limit
    local count,kk = 0,0
    local calendarID=s.item
    local sortkey
    local t_Body, fn_racetable,fn_datetable, fn_countrytable = {}, {}, {},{}
    local displayed_class=s.displayed_class

    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
        count = count + 1
        if ( count <= offset_limit and count >= offset ) -- to display statement with limit
         then 
        local RaceID = p527.mainsnak.datavalue.value.id
        ---- Create a row ----
        fn_datetable = fn_date(RaceID)
        local timeOfRace = fn_datetable[1]
        fn_racetable=fn_race(RaceID,displayed_class,s.displayclass,timeOfRace,nil,country)

        if fn_racetable[1]~=nil then --otherwise the class is not display
            fn_countrytable=fn_country(RaceID,timeOfRace,country,fn_racetable) 
            
            local tRow = mw.html.create('tr'):cssText( "line-height: 1.8em; padding: 5px;")
            tRow:node(fn_datetable[2])
            sortkey = fn_datetable[3]
            if s.numbering == true then
                tRow:tag('td'):cssText("text-align:center;padding:0 0.5em"):wikitext(tostring(kk))
            end
            
            tRow:node(fn_countrytable[1])
            if country then
                tRow:node(fn_racetable[1])
            end
            if fn_racetable[2] then tRow:node(fn_racetable[2]) end --class
            tRow:node(fn_rider(RaceID,timeOfRace,s.displayteam,s.only_winner))
            if s.leadercolumn==true then
                tRow:node(fn_rider(RaceID,timeOfRace,s.displayteam,3))
            end
            ---- Add the row to the table
            t_Body[#t_Body + 1] = {sortkey, tRow}
        end 
    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 UCIroad, UCIITT = {},{}

    UCIroad["women"] = {
        ['2020']='Q78466304', ['2019'] = 'Q66362617',
        ['2018'] = 'Q66762475', ['2017'] = 'Q66762546', ['2016'] = 'Q66762540',
        ['2015'] = 'Q66762534', ['2014'] = 'Q66762524', ['2013'] = 'Q66762521',
        ['2012'] = 'Q66762511', ['2011'] = 'Q66762500', ['2010'] = 'Q66762491'
    }
    
    UCIITT["women"] = {
        ['2020'] = 'Q78466572', ['2019'] = 'Q66736271',
        ['2018'] = 'Q66762631', ['2017'] = 'Q66762614', ['2016'] = 'Q66762604',
        ['2015'] = 'Q66762597', ['2014'] = 'Q66762592', ['2013'] = 'Q66762584',
        ['2012'] = 'Q66762578', ['2011'] = 'Q66762569', ['2010'] = 'Q66762562'
    }
    
    UCIroad["men"] = UCIroad["women"]
    UCIITT["men"] = UCIITT["women"]
    
    local listOfCalendar={UCIroad, UCIITT}

    for ii, thisCalendar in pairs(listOfCalendar) do --road/ITT
        for key, v in pairs(thisCalendar) do --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 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,
        displayteam = true,
        displaycountrylink = true,
        frame = frame
    }
    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[2], 'É', 'E') --case États Unis

                --create the table
                if tableChamp[sortkey]==nil then 
                    tableChamp[sortkey]={}
                    tableChamp[sortkey]['countryname']=fn_countrytable[2] --raw
                    tableChamp[sortkey]['roadwinner']='<td></td>'
                    tableChamp[sortkey]['ITTwinner']='<td></td>'
                    --look for sitelink to championship
                    sitelink=nil --reinit
                    if s.displaycountrylink 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[3]
                end
                
                --fill the table
                tRace, thereisawinner=fn_rider(thisID,timeOfRace,s.displayteam,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 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 = frame.args[1],
        property = 'P2522',
        no_country = no_country_victories,
        error_message = 0,
        frame=frame
    }
    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, fn_countrytable, fn_datetable, fn_racetable = {}, {}, {}, {}

    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')
        local timeOfRace = fn_datetable[1]
        sortkey=fn_datetable[2]
        
        fn_racetable=fn_race(RaceID,nil ,true,timeOfRace, 'victory',country)--displayed_class=nil
        
        if fn_racetable[1]~= nil then --otherwise class not to be displayed
            fn_countrytable=fn_country(RaceID,timeOfRace,country,fn_racetable)
            
            tRow:node(fn_datetable[2])
            if country==true then
                tRow:node(fn_racetable[1])  --race site link is in fn_countrytable
            end
            tRow:node(fn_countrytable[1]) --country
            tRow:node(fn_racetable[2]) --class
            tRow:node(fn_rider(RaceID,timeOfRace,false,1))
            t_Body[#t_Body + 1] = {sortkey, tRow}
        end --no winner
    end --end list of key
    
    return sortAndConcat(t_Body, resultTable)
end

--== D) Stage infobox
function p.stageinfobox(frame)
    local details = {
        { name = translate("stageinfobox",2)}, -- course / not used
        { name =  translate("stageinfobox",2)}, -- competition
        { name = translate("stageinfobox",3), name_plural = translate("infobox",4)}, -- stage type 
        { name = translate("stageinfobox",4), name_plural = translate("infobox",7)}, -- date
        { name = translate("stageinfobox",6)}, -- distance
        { name = translate("stageinfobox",7), name_plural = translate("infobox",10)}, -- country
        { name = translate("stageinfobox",9)}, -- start place
        { name = translate("stageinfobox",10)}, -- endplace
        { name = translate("stageinfobox",11)}, -- participants at start
        { name = translate("stageinfobox",12)}, -- participants at end
        { name = translate("stageinfobox",13)}, -- speed
        { name = translate("stageinfobox",44)}, -- elevation
        { name = translate("infobox",32), special = true}, -- special 1
        { name = translate("infobox",33), special = true}, -- special 2
    }
    local others = {
        { name = translate("infobox",29)}, -- picture
        { name = translate("infobox",30)}, -- caption
        { name = translate("infobox",31)}, -- map
        { name = 'sectional'},             -- sectional
        { name = translate("infobox",30)}, -- caption map
        { name = translate("infobox",30)}, -- caption sectional
    }
            --begin of the function
    local t_P642 = {
            [20882747]={'results', 'first'}, 
            [20882748]={'results', 'second'}, 
            [20882749]={'results', 'third'}, 
            [21686770]={'results', 'winner_fighting'},
            [2250962]={'results', 'cima_coppi'}, 
            [10452933]={'results', 'cima_pantani'},
            [20882763]={'gen', 'leader'}, 
            [20882764]={'gen', 'deuxieme'}, 
            [20882765]={'gen', 'troisieme'},
            [20883213]={'annex', 'montagne'}, 
            [20883140]={'annex', 'jeune'}, 
            [20883008]={'annex', 'points'},
            [20883329]={'annex', 'sprints'}, 
            [20893984]={'annex', 'super_combatif'}, 
            [20965880]={'annex', 'combine'},
            [27104688]={'annex', 'stage_volantes'}, 
            [27104684]={'annex', 'regularite'}, 
            [20882922]={'annex', 'equipe'},
            [27104271]={'annex', 'equipe_points'},
            [20882667]={'gen', 'leader'}, 
            [20882668]={'gen', 'deuxieme'}, 
            [20882669]={'gen', 'troisieme'},
            [20883212]={'annex', 'montagne'}, 
            [20883139]={'annex', 'jeune'}, 
            [20883007]={'annex', 'points'},
            [20883328]={'annex', 'sprints'}, 
            [20893983]={'annex', 'super_combatif'}, 
            [20893979]={'annex', 'combine'},
            [27067359]={'annex', 'stage_volantes'}, 
            [27067170]={'annex', 'regularite'},
            [27907747]={'annex', 'azzurri_ditalia'}, 
            [27907748]={'annex', 'azzurri_ditalia'},
            [27907714]={'annex', 'breakaway'}, 
            [27907715]={'annex', 'breakaway'},
            [20882921]={'annex', 'equipe'}, 
            [27104269]={'annex', 'equipe_points'}
    }
    
    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 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)
    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['numeric-id']
                    if qual~=nil and deprecated~='deprecated' and t_P642[qual] then
                        if qual==21686770 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==27104271 and t_s.annex.equipe_points['link']==nil then
                            t_s.annex.equipe_points['link']=riderId 
                        end
                        if qual==20882922 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))

-- 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))

            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)..')'
                        end
                    end
                    if v['points'] then
                        if v['points'] > 1 then 
                            temp=translate("unit",7)
                        else 
                            temp=translate("unit",6) 
                        end 
                        v['points'] = v['points']..temp
                    end
                    local title, k = string.gsub(translate("stageinfobox",v['translation']), " ", "&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']))
                            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), 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 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,12}, -- national cycling team "B"
        ["Q20738667"] = {12,13,12}, -- national cycling team U23
        ["Q54555994"] = {12,13,12}, -- national cycling team U19        
        ["Q28492441"] = {12,13,13}, -- national cycling team with sponsor name
        ["Q20652655"] = {18,19,14}, -- amateur cycling team
        ["Q26849121"] = {30,31,14}, -- Women's amateur cycling team
        ["Q20639848"] = {14,15,15}, -- club and region cycling team
        ["Q20653570"] = {14,15,15}, -- 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) -- singular name
                    else
                        header_label = translate("headoftableIII",33) -- plural name
                    end
                    done=true
                end
            end
            
            if done==false then
                if count == 1 then
                    header_label = translate("headoftableIII",teamCats[CatID][1]) -- singular name
                else
                    header_label = translate("headoftableIII",teamCats[CatID][2]) -- 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 tableFooter1=mw.html.create('tr')
    tCell=tableFooter1:tag('td')
    :addClass('navigation-only')
    :attr('colspan',2)
    :cssText('border-top: 2px '..backgroundColor..' solid; font-size: 80%;')
    tCell:tag('span'):css("float",floattable)
    :wikitext('[[File:Wikidata-logo S.svg|12px|link=d:' ..raceID .. '#P1923]]')
    
    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
        displayteam=false
        }
    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], "%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
        }
    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
    }
    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
        }
    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
        }
    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
        }
    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
        }
    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
    }
    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
    }
    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], "%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
        }
    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], "%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
        }
    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], "%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
        }
    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], "%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
        }
    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], "%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
        }
    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], "%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
        }
    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], "%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
        }
    return new_classification(frame, s)
end

function p.custompointsclassification(frame)
    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], "%c", ""),
        property = string.gsub(frame.args[2], "%c", ""), -- 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
        }
    return new_classification(frame, s)
end

function p.customtimeclassification(frame)
    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], "%c", ""),
        property = string.gsub(frame.args[2], "%c", ""), -- 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
        }
    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

    --[=[ 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

    if s.header_1_text ==nil then s.header_1_text=translate(s.header_function,s.header_1) end --for custom title

    local tableBody = mw.html.create('table')
        :addClass('sortable')
        :attr('cellpadding', '0')
        :attr('cellspacing', '0')
        :css('border' , '0')

    local thisspan= mw.html.create('span'):cssText('float:left;'):wikitext('[[File:Wikidata-logo S.svg|12px|link=d:'.. raceID .. '#' .. s.property..']]')
    tableBody:tag('tr'):tag('th')
    :attr('colspan', tostring(tableHeader2_size + 1)):cssText("padding:2px 2px; text-align:center; background-color:"..backgroundColor)
    :wikitext(tostring(thisspan)..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 head=header:tag('th'):wikitext(translate(s.header_function,k))
            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)--"HD","NP","DQ"
                    elseif dnf=='Q54881674' or dnf=='Q7113430' then riderDNF =translate("startlist",7)
                    elseif dnf=='Q1210382' then riderDNF =translate("startlist",8)
                    elseif dnf=='Q1229261' then riderDNF =translate("startlist",9)
                    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)
                local p27 = getStatementForTime(riderID, 'P27', timeOfRace) --P27 is country of citizenship
                if p27 then
                    countryID = p27.mainsnak.datavalue.value.id
                end
            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
                if wiki == "ca" then bg_color_table["Q24257763"] = "lightpink" end
                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.displayteam~=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.displayteam~=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)
                        else
                            temp2=translate("unit",6)
                        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)
                    else
                        temp2=translate("unit",6)
                    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))
                end
            end
            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
    
    tableBody=sortAndConcat(t_Body, tableBody)
    local tableFooter1,tableFooter2
    if s.display_ref == 1 then
        tableFooter1=mw.html.create('tr')
        tCell=tableFooter1:tag('td')
        :addClass('navigation-only')
        :attr('colspan',tostring(tableHeader2_size + 1))
        :cssText('border-top: 2px '..backgroundColor..' solid; font-size: 80%;')
        tableFooter2=mw.html.create('tr')
        tCell=tableFooter2:tag('td')
        :attr('colspan',tostring(tableHeader2_size + 1))
        :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
    
    if selector==0 then --normal infobox
        details = {
            { name = translate("infobox",2)}, -- course
            { name = translate("infobox",3), name_plural = translate("infobox",4)}, -- competition
            { name = translate("infobox",5)}, -- stages
            { name = translate("infobox",6), name_plural = translate("infobox",7)}, -- date
            { name = translate("infobox",8)}, -- distance
            { name = translate("infobox",9), name_plural = translate("infobox",10)}, -- country
            { name = translate("infobox",11)}, -- start place
            { name = translate("infobox",12)}, -- endplace
            { name = translate("infobox",13)}, -- teams
            { name = translate("infobox",14)}, -- participants at start
            { name = translate("infobox",15)}, -- participants at end
            { name = translate("infobox",16)}, -- speed
            { name = translate("infobox",43)}, -- elevation
            { name = translate("infobox",17)}, -- cost
            { name = translate("infobox",32), special = true}, -- special 1
            { name = translate("infobox",33), special = true}, -- special 2
        }
    elseif selector==1 then  --season infobox
        details = {
            { name = translate("infobox",46)}, -- edition (1)
            { name = translate("infobox",3), name_plural = translate("infobox",4)}, -- competition (2)
            { name = translate("infobox",6), name_plural = translate("infobox",7)}, -- date (3)
            { name = translate("infobox",45)}, -- rasing (4)        
            { name = translate("infobox",47), name_plural = translate("infobox",48)}, -- location (country) (5)
            { name = translate("infobox",49), name_plural = translate("infobox",50)}, -- organizer (6)
            { name = translate("infobox",63), name_plural = translate("infobox",63)}, -- team class (7) 
            { name = translate("infobox",32), special = true}, -- special 1
            { name = translate("infobox",33), special = true}, -- special 2
        }
    else  --champ
         details = {
            { name = translate("infobox",46)}, -- edition (1)
            { name = translate("infobox",6), name_plural = translate("infobox",7)}, -- date (2)
            { name = translate("infobox",9), name_plural = translate("infobox",10)}, -- country (3) 
            { name = translate("infobox",67), name_plural = translate("infobox",68)}, -- location (city) (4)
            { name = translate("infobox",61), name_plural = translate("infobox",62)}, -- arena / stadion (5)
            { name = translate("infobox",60)}, -- medals (6)
            { name = translate("infobox",13)}, -- team (7)          
            { name = translate("infobox",49), name_plural = translate("infobox",50)}, -- organizer (8)
            { name = translate("infobox",32), special = true}, -- special 1
            { name = translate("infobox",33), special = true}, -- special 2
        }
    end
    
    others = {  --same for 3 infobox
        { name = translate("infobox",29)}, -- picture
        { name = translate("infobox",30)}, -- caption
        { name = translate("infobox",31)}, -- map
        { name = 'sectional'},             -- sectional
        { name = translate("infobox",30)}, -- caption map
        { name = translate("infobox",30)}, -- caption sectional
    }

    if selector==0 then
         winners = {
            { name = translate("infobox",19), QID = 'Q20882667' }, -- first
            { name = translate("infobox",20), QID = 'Q20882668' }, -- second
            { name = translate("infobox",21), QID = 'Q20882669' }, -- third
            { name = translate("infobox",22), QID = 'Q20883007' }, -- points
            { name = translate("infobox",23), QID = 'Q20883212' }, -- mountains
            { name = translate("infobox",24), QID = 'Q20883328' }, -- sprints
            { name = translate("infobox",25), QID = 'Q20883139' }, -- youth
            { name = translate("infobox",26), QID = 'Q20893983' }, -- combativity
            { name = translate("infobox",35), QID = 'Q27067359' }, -- volantes
            { name = translate("infobox",36), QID = 'Q27067170' }, -- regularity
            { name = translate("infobox",27), QID = 'Q20893979' }, -- combination
            { name = translate("infobox",38), QID = 'Q27907715' }, -- breakaway
            { name = translate("infobox",39), QID = 'Q27907747' }, -- azzurri
            { name = translate("infobox",40), QID = 'Q28092831' }, -- rookie
            { name = translate("infobox",28), QID = 'Q20882921' }, -- teams
            { name = translate("infobox",37), QID = 'Q27104269' }, -- teamspoints
            { name = translate("infobox",41), QID ='Q61976850' },-- amateur
            { name = translate("infobox",42), QID ='Q61976872' } --nationality
        }
    elseif selector==1 then
         winners = {
            { name = translate("infobox",52), QID = 'Q20882667' }, -- individual (first)
            { name = translate("infobox",53), QID = 'Q20883139' }, -- youth
            { name = translate("infobox",54), QID = 'Q27104269' }, -- team (teamspoints)
            { name = translate("infobox",55), QID = 'Q98959152' }, -- team GS-I
            { name = translate("infobox",56), QID = 'Q98959153' }, -- team GS-II
            { name = translate("infobox",57), QID = 'Q98959155' }, -- team GS-III
            { name = translate("infobox",58), QID = 'Q72068715' }, -- country
            { name = translate("infobox",59), QID = 'Q72068724' }  -- country U23
        }
    end --Champ has no 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 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', 'numeric-id') == 3609) 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
        --system with P2094 and P3450
        local classID = firstValue(entityID, 'P2094', 'id')
        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 classes[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 classes[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)
    
        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
                local unit = cost.unit
                cost = contentLanguage:formatNum(tonumber(cost.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
                details[14].content = cost
            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') --org
        end
        if not details[7].content then -- organizer sitelink
            listWPlink(details, 7, entityID,'P2670') --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') 
        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') --org
        end
    end

    tab = infoInitTab("300px", name, icon)
    infoFillOthersDetails(tab, others, details,translate("infobox",1))
    
    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))
            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), 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 details = {
        { name = translate("raceinfobox",4)}, -- sport
        { name = translate("raceinfobox",5)}, -- creation date
        { name = translate("raceinfobox",6)}, -- disparition date
        { name = translate("raceinfobox",7)}, -- number of editions
        { name = translate("raceinfobox",8)}, -- periodicity
        { name = translate("raceinfobox",9)}, -- type , name_plural = translate("infobox",10)
        { name = translate("victories",5)},                                                     --country
        { name = translate("raceinfobox",10), name_plural = translate("raceinfobox",11)}, -- place
        { name = translate("raceinfobox",12), name_plural = translate("raceinfobox",13)}, --org
        { name = translate("raceinfobox",27), name_plural = translate("raceinfobox",28)}, --race director
        { name = translate("raceinfobox",14)}, -- official web site
        { name = translate("raceinfobox",15), name_plural = translate("raceinfobox",16)}, -- Cat
        { name = translate("raceinfobox",17)}, -- circuit
    }
    
    local others = {
        { name = translate("infobox",29)}, -- picture
        { name = translate("infobox",30)}, -- caption
        { name = translate("infobox",31)}, -- map
        { name = 'sectional'},             -- sectional
        { name = translate("infobox",30)}, -- caption map
        { name = translate("infobox",30)}, -- caption sectional
    }

    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 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) .. " "..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
        listWPlink(details, 9, entityID,'P644') --organiser
    end
    
    if not details[10].content then
        listWPlink(details, 10, entityID,'P488') --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),"260px")
    if not listOfNamesAtBottom then
        if listOfNames and #listOfNames>1 then
            tab:node(addATitle(translate("raceinfobox",18)))  
            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),"260px")

    if listOfNamesAtBottom then
        if listOfNames and #listOfNames>1 then
            tab:node(addATitle(translate("raceinfobox",18)))  
            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)))
        if (tRace.lastWinner and tRace.lastWinner~='') then
            tab:node(addARow(translate("raceinfobox",21),tRace.lastWinner))
        end
        if (tRace.maxWinner and tRace.maxWinner~='') then
            tab:node(addARow(translate("raceinfobox",22),tRace.maxWinner))
        end
    end

    if tRace.nextLink or tRace.lastLink then
        tab:node(addATitle(translate("raceinfobox",23)))
        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)..
            ":<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)..
            ":<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), 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 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..')'
                        end
                    end
                end
            end
        end
        --get the country
        local countryID
        local p27 = getStatementForTime(riderID, 'P27', timeOfRace) --P27 is country of citizenship
        if p27 then
            countryID = p27.mainsnak.datavalue.value.id
        end
        if countryID then
            pays = getCountryName(countryID)
            flags = flag(countryID, timeOfRace)
        end
        --save
        local tRider={
                sortkey=sortkey, 
                riderName=riderName, 
                riderBirthday=riderBirthday, 
                riderTeam=riderTeam, 
                timeTeam=timeTeam,
                riderStart=riderStart, 
                riderEnd=riderEnd, 
                riderPosition=riderPosition, 
                riderReason=riderReason, 
                riderRef=riderRef, 
                errortext=errortext, 
                pays=pays,
                flags=flags
                }
        
        if correctlanguage == true then
            table.insert(riderTablecorrect,tRider )
        else
            table.insert(riderTablenotcorrect, tRider)
        end
    end

    -- sorting names
    if sort == true then
        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 outTable = mw.html.create('table')
                            :addClass('sortable')
                            :attr('cellpadding', '2')
                            :attr('cellspacing', '0')
                            :css('border' , '1px solid rgb(200,200,200)')
                            :css('padding', '3px')
    outTable:tag('tr'):css('line-height','1.8em')
        :css('background-color',backgroundColor)
        :tag('th'):attr('colspan', 4):cssText('text-align:center;white-space:nowrap')
        :wikitext('<span style="float:left">[[File:Wikidata-logo S.svg|12px|link=d:'.. frame.args[1].. '#P527]]</span>')
        :wikitext(translate("getSquadTableColumn",7))
    local header = outTable:tag('tr')
    header:tag('th'):cssText('text-align:center;padding:2px 20px 2px 2px;white-space:nowrap'):wikitext(translate("getSquadTableColumn",1))
    header:tag('th'):cssText('text-align:center;padding:2px 20px 2px 2px;white-space:nowrap'):wikitext(translate("getSquadTableColumn",2))
    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))
    end
    header:tag('th'):cssText('text-align:center;padding:2px 20px 2px 2px;white-space:nowrap'):wikitext(translate("getSquadTableColumn",3))

    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)..']]'
                if wiki == "ar" then
            		note = '، [[#tr_'..i..frame.args[1]..' | ملاحظة ]]' 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)..']]'.. ')')
        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
            tCell=tRow:tag('td'):cssText("padding:0 0.5em; text-align:left")
        end
        if v['riderTeam'] then
            tCell:wikitext(v['riderTeam'].. v['timeTeam']..v['errortext'])
        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)..': '.. v['riderName'].. temp
            else
                tableEndText = tableEndText.. '<span style="color:white">'.. translate("getSquadTableColumn",5)..': </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',4)
    :cssText("border-top: 2px "..backgroundColor.." solid; font-size: 80%;")
    :tag('tr')
    :tag('td'):attr('colspan',4)
    :attr('data-sort-value','zzz')
    :cssText("text-align:right")
    :tag('small'):wikitext(translate("race_reference", 1).."["..UCIlink..' UCI]')
    
    return tostring(outTable)..tableEndText
end

--== J) List of winners ==
function p.listofwinners(frame)
    local winnersProperty = {'Q20882667','Q20882668','Q20882669'}
    local displayteamtemp = false -- display of a rider without a team
    if tonumber(frame.args[5]) ==1 then displayteamtemp = 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]),
        displayteam=displayteamtemp,        
        winnersProperty=winnersProperty,
        custom=false
    }
    return listofwinners_main(frame, s)
end

function p.listofwinnersyoung(frame)
    local winnersProperty = {'Q20883139','Q72099969','Q72099972'}
    local displayteamtemp = false -- display of a rider without a team
    if tonumber(frame.args[4]) ==1 then displayteamtemp = 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]),
        displayteam=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,
        displayteam = 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 displayteamtemp = false -- display of a rider without a team
    if tonumber(frame.args[5]) ==1 then displayteamtemp = 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]),
        displayteam=displayteamtemp, -- 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 displayteamtemp = false -- display of a rider without a team
    if tonumber(frame.args[5]) ==1 then displayteamtemp = 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]),
        displayteam=displayteamtemp, -- 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 displayteamtemp = false -- display of a rider without a team
    if tonumber(frame.args[5]) ==1 then displayteamtemp = 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]),
        displayteam=displayteamtemp, -- 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 displayteamtemp = false -- display of a rider without a team
    if tonumber(frame.args[5]) ==1 then displayteamtemp = 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]),
        displayteam=displayteamtemp, -- 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 displayteamtemp = false -- display of a rider without a team
    if tonumber(frame.args[5]) ==1 then displayteamtemp = 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]),
        displayteam=displayteamtemp, -- 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 displayteamtemp = false -- display of a rider without a team
    if tonumber(frame.args[5]) ==1 then displayteamtemp = 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]),
        displayteam=displayteamtemp, -- 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 displayteamtemp = false -- display of a rider without a team
    if tonumber(frame.args[5]) ==1 then displayteamtemp = 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]),
        displayteam=displayteamtemp, -- 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
    -- 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]),
        displayteam = 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
    
    if s.custom then
        titletable={
        [ 'Q20882667' ]=translate("listofwinners",2), -- winner
        [ 'Q20882668' ]=translate("listofwinners",3), -- second     
        [ 'Q20882669' ]=translate("listofwinners",4), -- third      
        [ 'Q20883007' ]=translate("listofwinners",5), -- points  
        [ 'Q20883212' ]=translate("listofwinners",6), -- mountains
        [ 'Q20883328' ]=translate("listofwinners",7), -- sprints
        [ 'Q20883139' ]=translate("listofwinners",8), -- youth
        [ 'Q20893983' ]=translate("listofwinners",9), -- combativity
        [ 'Q20893979' ]=translate("listofwinners",10), -- combination
        [ 'Q20882921' ]=translate("listofwinners",11), -- teams
        [ 'Q27067359' ]=translate("listofwinners",12), -- volantes
        [ 'Q27067170' ]=translate("listofwinners",13), -- regularity
        [ 'Q27104269' ]=translate("listofwinners",14), -- teamspoints
        [ 'Q27907715' ]=translate("listofwinners",15), -- breakaway
        [ 'Q27907747' ]=translate("listofwinners",16), -- azzurri
        [ 'Q28092831' ]=translate("listofwinners",17), -- rookie
        [ 'Q61976850' ]=translate("listofwinners",18), -- amateur
        [ 'Q61976872' ]=translate("listofwinners",19), -- nationality
        [ 'Q72068715' ]=translate("listofwinners",23), -- winner country
        [ 'Q72068724' ]=translate("listofwinners",24), -- winner countryU23
    }
    else --main
         titletable={
-- winner:
        [ 'Q20882667' ]=translate("listofwinners",2), -- winner
        [ 'Q20883007' ]=translate("listofwinners",2), -- points  
        [ 'Q20883212' ]=translate("listofwinners",2), -- mountains
        [ 'Q20883328' ]=translate("listofwinners",2), -- sprints
        [ 'Q20883139' ]=translate("listofwinners",2), -- youth (time or point)
        [ 'Q20893983' ]=translate("listofwinners",2), -- combativity
        [ 'Q20893979' ]=translate("listofwinners",2), -- combination
        [ 'Q20882921' ]=translate("listofwinners",2), -- team (time)
        [ 'Q27067359' ]=translate("listofwinners",2), -- volantes
        [ 'Q27067170' ]=translate("listofwinners",2), -- regularity
        [ 'Q27104269' ]=translate("listofwinners",2), -- teampoints
        [ 'Q27907715' ]=translate("listofwinners",2), -- breakaway
        [ 'Q27907747' ]=translate("listofwinners",2), -- azzurri
        [ 'Q28092831' ]=translate("listofwinners",2), -- rookie
        [ 'Q61976850' ]=translate("listofwinners",2), -- amateur
        [ 'Q61976872' ]=translate("listofwinners",2), -- nationality
        [ 'Q72068715' ]=translate("listofwinners",2), -- winner country
        [ 'Q72068724' ]=translate("listofwinners",2), -- winner countryU23
        [ 'Q98959152' ]=translate("listofwinners",2), -- winner team GS-I
        [ 'Q98959153' ]=translate("listofwinners",2), -- winner team GS-II
        [ 'Q98959155' ]=translate("listofwinners",2), -- winner team GS-III     
-- 2 place:
        [ 'Q20882668' ]=translate("listofwinners",3), -- second     
        [ 'Q72065970' ]=translate("listofwinners",3), -- second teampoints
        [ 'Q72099969' ]=translate("listofwinners",3), -- youth (time or point)      
        [ 'Q72068718' ]=translate("listofwinners",3), -- second country
        [ 'Q72068725' ]=translate("listofwinners",3), -- second countryU23
        [ 'Q98959192' ]=translate("listofwinners",3), -- second team GS-I
        [ 'Q98959194' ]=translate("listofwinners",3), -- second team GS-II
        [ 'Q98959195' ]=translate("listofwinners",3), -- second team GS-III     
-- 3 place:
        [ 'Q20882669' ]=translate("listofwinners",4), -- third  
        [ 'Q72065977' ]=translate("listofwinners",4), -- third teampoints   
        [ 'Q72099972' ]=translate("listofwinners",4), -- youth (time or point)      
        [ 'Q72068721' ]=translate("listofwinners",4), -- third country
        [ 'Q72068729' ]=translate("listofwinners",4), -- third countryU23
        [ 'Q98959196' ]=translate("listofwinners",4), -- third team GS-I
        [ 'Q98959197' ]=translate("listofwinners",4), -- third team GS-II
        [ 'Q98959198' ]=translate("listofwinners",4), -- 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.displayteam,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')
    if WDlink_on == false then
        tCell:tag('span'):css("float","left")
        :wikitext("[[File:Wikidata-logo S.svg|12px|link=d:"..raceID .. "#P527]]")
    end
    tCell:wikitext(translate("listofwinners",1)) --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
--[=[ 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)

            p = mw.wikibase.getBestStatements(stageID, 'P585') -- P585 is 'point in time'
            local timeOfRace = p[1] and p[1].mainsnak.snaktype == 'value' and p[1].mainsnak.datavalue.value.time
                or ''
            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 ''
            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

            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 ''
            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)
    
    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))
    tRow:tag('th'):wikitext(translate("headoftable",2))
    tRow:tag('th'):wikitext(translate("headoftable",3))
    tRow:tag('th'):css('color',backgroundColor):wikitext("type")
    tRow:tag('th'):wikitext(translate("headoftable",4))
    if thereiselevation then 
        tRow:tag('th'):wikitext(translate("headoftable",7))
    end
    tRow:tag('th'):wikitext(translate("headoftable",5))
    tRow:tag('th'):wikitext(translate("headoftable",6))

    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
    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

--[[ 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


local function champtitle(h) --!h is h.jersey
    local road, ITT, result
    local hcountry, hnotcountry = {},{}
    
    --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
    local womenRoadtable= {Q934877=true, Q50064341=true,Q50061750=true,Q31271454=true,Q54315111=true,Q30894544=true,
    Q66082905=true,Q65965631=true,Q45083914=true,Q31271492=true,Q43286073=true,Q55185740=true,Q65371835=true,
    Q31094517=true,QQ27043949=true, Q30332924=true,Q30349395=true,Q53869580=true,Q31505332=true,Q30349364=true,
    Q31271605=true,Q43745198=true,Q30332844=true,Q30332239=true,Q30349468=true, Q30332737=true,Q55221006=true,
    Q32161692=true,Q33083546=true,Q30332988=true,Q30556990=true,Q32604159=true,Q30557561=true,Q64624273=true,
    Q30333102=true, Q31271010=true,Q31276622=true,Q45084873=true,Q32609249=true,Q31271644=true,Q31298588=true,
    Q45171831=true,Q30332625=true,Q30349432=true,Q31092105=true,Q30577809=true,Q30349499=true, Q45172931=true
    }
    local womenITTtable={Q2630733=true,Q50063172=true,Q50062728=true,Q31271381=true,Q54314912=true,Q30894543=true,
    QQ31093255=true,Q31271615=true,Q29642128=true,Q30349411=true,Q53869589=true,
    Q31506358=true,Q30349371=true,Q31271315=true,Q43745136=true,Q30332806=true,
    Q30332311=true,Q30349480=true,Q30332699=true,Q55220999=true,Q32163348=true,
    Q33083817=true,Q30333018=true,Q30556121=true,Q32603438=true,Q30557504=true,
    Q64624304=true,Q30333137=true,Q31271024=true,Q30456396=true,Q45084954=true,
    Q32611136=true,Q31272638=true,Q31300263=true,Q45171898=true,Q30332486=true,
    Q30349441=true,Q30584268=true,Q30577837=true,Q30349507=true,Q45172978=true
    }
    local menRoadtable={Q13603535=true,Q30894537=true,Q23069702=true,Q23889469=true,
    Q66250756=true, Q22284173=true, Q30967435=true, Q24617852=true, Q27043944=true,
    Q24628140=true,Q27056312=true,Q62024698=true,Q26960669=true,Q22951216=true,
    Q27048382=true,Q27133468=true,Q26971246=true,Q24621530=true,Q27048391=true,
    Q27048399=true,Q27681895=true,Q27681898=true,Q27055629=true,Q26976092=true,
    Q26985335=true,Q27048419=true,Q27043957=true,Q27055631=true,Q24050070=true,
    Q26973043=true,Q27133456=true,Q26834056=true,Q27043924=true,Q27048374=true,
    Q26972921=true,Q27043324=true,Q27056303=true,Q27042502=true,Q27042790=true,
    Q27133451=true,Q27056305=true,Q24731826=true,Q27230607=true,Q22680990=true,
    Q27043353=true,Q27048408=true,Q22303186=true,Q27042375=true,Q27133460=true,
    Q27133465=true,Q22680842=true,Q27230606=true,Q27230610=true,Q26972715=true,
    Q24718413=true,Q3754283=true,Q27230604=true,Q27043932=true,Q27230611=true,
    Q24733085=true,Q27055624=true,Q24731406=true,Q27056308=true
    }
    local menITTtable={Q2557477=true,Q33315723=true,Q22284183=true, Q31023710=true,
    Q24618030=true, Q27043945=true,Q24628162=true,Q27056389=true,Q26960674=true,
    Q5147941=true,Q27048383=true,Q27133626=true,Q26971248=true,Q24621627=true,
    Q27793536=true,Q27048400=true,Q27793536=true,Q27793496=true,Q27055699=true,
    Q26976108=true, Q26985336=true, Q27048421=true,Q27043958=true,Q27055700=true,
    Q26973044=true,Q27133617=true,Q26834055=true,Q27043925=true,Q24050074=true,
    Q27048375=true,Q26972922=true,Q27043325=true,Q27056383=true,Q27042506=true,
    Q17319607=true,Q27133615=true,Q17005940=true,Q24731829=true,Q27235634=true,
    Q22680998=true,Q3754388=true,Q27048410=true,Q22303252=true,Q27042376=true,
    Q27133620=true,Q27133623=true,Q22680863=true,Q7382088=true,Q27235638=true,
    Q26972716=true,Q24718416=true,Q27043341=true,Q27230443=true,Q27043933=true,
    Q27235639=true,Q24733090=true,Q27055696=true,Q24731482=true,Q27056386=true
    }

    if type(h) == 'table' and h[1] then
        for _, v in ipairs(h) do
            roadtemp=false
            ITTtemp=false
            if womenRoadtable[v] or menRoadtable[v] then
                 road = true
                 roadtemp=true
            elseif womenITTtable[v] or menITTtable[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).." "..translate("startlist",12).." "..translate("startlist",11)..")</small>"
    elseif road then
        result = "<small>("..translate("startlist",10)..")</small>"
    elseif ITT then
        result = "<small>("..translate("startlist",11)..")</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 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, combinedname
    if thisGT then
        if thisGT=='Q33881' then
            Sitelink = wikibase.getSitelink('Q2267539')
            if Sitelink then overallname="[["..Sitelink .."|"..translate("headoftableII",9).."]]" end
            Sitelink = wikibase.getSitelink('Q175399')
            if Sitelink then pointsname="[["..Sitelink .."|"..translate("infobox",22).."]]" end
            Sitelink = wikibase.getSitelink('Q927157')
            if Sitelink then mountainname="[["..Sitelink .."|"..translate("infobox",23).."]]" end
            Sitelink = wikibase.getSitelink('Q641662')
            if Sitelink then youngname="[["..Sitelink .."|"..translate("infobox",25).."]]" end
            Sitelink = wikibase.getSitelink('Q1436680')
            if Sitelink then teamname="[["..Sitelink .."|"..translate("infobox",28).."]]" end
            Sitelink = wikibase.getSitelink('Q2094179')
            if Sitelink then combativityname="[["..Sitelink .."|"..translate("infobox",26).."]]" end
            Sitelink = wikibase.getSitelink('Q1835362')
            if Sitelink then combinedname="[["..Sitelink .."|"..translate("infobox",27).."]]" end
        elseif thisGT=='Q33861' then
            Sitelink = wikibase.getSitelink('Q1164275')
            if Sitelink then overallname="[["..Sitelink .."|"..translate("headoftableII",9).."]]" end
            Sitelink = wikibase.getSitelink('Q641083')
            if Sitelink then pointsname="[["..Sitelink .."|"..translate("infobox",22).."]]" end
            Sitelink = wikibase.getSitelink('Q641060')
            if Sitelink then mountainname="[["..Sitelink .."|"..translate("infobox",23).."]]" end
            Sitelink = wikibase.getSitelink('Q641662')
            if Sitelink then youngname="[["..Sitelink .."|"..translate("infobox",25).."]]" end
        else
            Sitelink = wikibase.getSitelink('Q2532554')
            if Sitelink then overallname="[["..Sitelink .."|"..translate("headoftableII",9).."]]" end
            Sitelink = wikibase.getSitelink('Q2241695')
            if Sitelink then pointsname="[["..Sitelink .."|"..translate("infobox",22).."]]" end
            Sitelink = wikibase.getSitelink('Q1118296')
            if Sitelink then mountainname="[["..Sitelink .."|"..translate("infobox",23).."]]" end
            Sitelink = wikibase.getSitelink('Q2330008')
            if Sitelink then combinedname="[["..Sitelink .."|"..translate("infobox",27).."]]" end
        end
    end

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

    local winnersgen = {
        { QID = 'Q20882667' }, -- overall
        { QID = 'Q20883007' }, -- points
        { QID = 'Q20883212' }, -- mountains
        { QID = 'Q20883328' }, -- sprints
        { QID = 'Q20883139' }, -- youth
        { 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
        ['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 ii = 1, #stages+1 do
                t[ii] = { {}, {}, {} }  -- leader, first stage, number of stages consecutive (for rowspan)
            end
            columntable[v.QID] = t
        end
    end
    local function itercolumns(columntable)
        local keys = {}
        for k, v in pairs(columntable) do
            keys[v.key] = k
        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+)(.*)')
            if not sNumber then sNumber = '' end
            if not sLetter then sLetter = '' end

            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 sTime = firstValue(stageID, 'P580', 'time') -- P580 is 'start time'
            local eTime = firstValue(stageID, 'P582', 'time') -- P582 is 'end time'
            if sTime and eTime then
                timeOfRace = eTime
            else
                -- This function give a format to dates when P585 (date) is used in a single day race.
                local pTime = firstValue(stageID, 'P585', 'time') -- P585 is 'point in time'
                if pTime then
                    timeOfRace = pTime
                end
            end

            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)
            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][1]=win[v.QID]
                    if ii==1 then --first stage
                        columntable[v.QID][ii][2]=1  --start at row 1
                        columntable[v.QID][ii][3]=1  --1 consecutive stage
                    elseif columntable[v.QID][ii-1][1]==win[v.QID] then --same winner as past stage
                        local initialstage=columntable[v.QID][ii-1][2]
                        columntable[v.QID][ii][2]=initialstage --no change of the first stage
                        columntable[v.QID][initialstage][3]=columntable[v.QID][initialstage][3]+1 --one more consecutive stage
                        columntable[v.QID][ii][3]=0
                    else --new winner
                        columntable[v.QID][ii][2]=ii --start at this row/stage
                        columntable[v.QID][ii][3]=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][1]=win[v.QID]
            columntable[thiskey][#stages+1][2]=#stages+1
            columntable[thiskey][#stages+1][3]=1
            --#stages is the last stage
            if type(columntable[thiskey][#stages][1])~="string"  --combativity is not extrapolated
            and thiskey~='Q20893984'
            then --check nil actually, but it is a table..
                columntable[thiskey][#stages][1]= win[v.QID] --extrapolate the winner
                if type(columntable[thiskey][#stages-1][1])=="string" and 
                win[v.QID]==columntable[thiskey][#stages-1][1]
                then --if there is a leader at forelast stage
                    local initialstage=columntable[thiskey][#stages-1][2]
                    columntable[thiskey][#stages][2]=initialstage
                    columntable[thiskey][initialstage][3]=columntable[thiskey][initialstage][3]+1
                    columntable[thiskey][#stages][3]=0
                else
                    columntable[thiskey][#stages][2]=#stages
                    columntable[thiskey][#stages][3]=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), 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))
    
    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)
        
        tCell=tRow:tag('td')
        if ii==#stageinfotable then --general row
            tCell:cssText('font-weight:bold; border-top: 2px black solid;')
        end
        if displaytypeofstage == true then
            if v.sType then
                tCell:wikitext(v.sType)
            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][1])=="string" and type(y[ii][3])=="number" then --actually check nil but it is a table
                    style=""
                    if y[ii][3]~=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][3])):cssText(style):wikitext(y[ii][1])
                    elseif (columntable['Q20882747']==y) then --no rowspan for stages
                        tRow:tag('td'):wikitext(y[ii][1])
                    end
                else
                    tCell=tRow:tag('td')
                    if ii~=#stageinfotable and v.somewinner==true then
                        tCell:wikitext(translate("listofstagesclassification",1)) --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)) --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 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
    }

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

local function startlist_sub(p710, timeOfRace,  WDlink_on, istable)
    local h, resultTable= {}, {}
    local tBody = '' --row in our case
    local riderID, riderTeamLink, riderTeamID, riderDossard, riderLink, riderRank, q, gender, riderTeamCode, riderDNF, DSQ

    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)--"HD","NP","DQ"
            elseif dnf=='Q54881674' or dnf=='Q7113430' then riderDNF =translate("startlist",7)
            elseif dnf=='Q1210382' then riderDNF =translate("startlist",8)
            elseif dnf=='Q1229261' then riderDNF =translate("startlist",9)
            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 p27 = getStatementForTime(riderID, 'P27', timeOfRace) --P27 is country of citizenship
    if p27 then
        local countryID = p27.mainsnak.datavalue.value.id
        if countryID then
            if wiki ~= "ar" then 
                riderLink = riderLink .. uciCodeCountry(countryID)
            end
            riderLink = flag(countryID, timeOfRace) ..' '.. riderLink 
        end
    end
    
    if h.jersey[1] then
        riderLink=riderLink..champtitle(h.jersey) -- champtitle manages also the jersey
    end
    
    riderTeamLink, riderTeamID = getTeam(riderID, timeOfRace, q)
    riderTeamID=seasonToTeamID(riderTeamID)
    riderTeamCode= getTeamCode(riderID, timeOfRace, q)
    
    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)
    if istable then
        tBody:tag('td'):cssText("text-align:right;padding:0 0.5em"):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 fn_datetable=fn_date(s.item)
    local timeOfRace=fn_datetable[1]

    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)
        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))
        tSubtitle:tag('td'):attr('width','200px')
        :css("align:right;text-align:right")
        :wikitext(translate("startlist",3))
        tSubtitle:tag('td'):attr('width','85px')
        :css("align:right;text-align:right")
        :wikitext(translate("startlist",4))
    else
        tSubtitle=mw.html.create('tr')
        tSubtitle:tag('td'):attr('width','30px'):wikitext(translate("startlist",2))
        tSubtitle:tag('td'):attr('width','250px'):wikitext(translate("startlist",3))
        tSubtitle:tag('td'):attr('width','35px'):wikitext(translate("startlist",4))
    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) 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).." "..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 thisDS=v.DSLink break 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).." "..thisDS)
        end
        tag:node(thisTableRow)

        return resultTable
    end
end

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

    fn_datetable=fn_date(s.item)
    local timeOfRace=fn_datetable[1]

    for _, p710 in statements(s.item, 'P710') do -- P710 is participants
        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], "%c", ""),
    }
    return riderranking_main(frame, s)
end


function riderranking_main(frame,s)
    local thisCompetition, rank, thisyear, sitelink, q, gender
    local resultTable, listofcalendar, UCI, UCImaster={},{},{}, {}
    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
    
    UCImastername={
        ["women"]=translate("riderranking",2), ['WWT']=translate("riderranking",3), 
        ['WWC']=translate("riderranking",4), ["UWT"]= translate("riderranking",5),
        ["europe"]=translate("riderranking",6), ["asia"]=translate("riderranking",7),
        ["oceania"]=translate("riderranking",8),["america"]=translate("riderranking",9) ,
        ["africa"]=translate("riderranking",10)
    }
    
    local listofwomencalendar={"women","WWC",  "WWT"} --"women" is in fact UCIwomen 
    local listofmencalendar={"UWT","europe","asia","america","oceania","africa","Pro"}
    
    local gender=getGenderCode(s.item, 'm')
    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)
                else
                    rank= nil
                end
                if rank then
                    resultTable[thisyear][calendar]["rank"]=tostring(rank)
                    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))

        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 ii=minmaxyear.minimum,minmaxyear.maximum,1 do
                    thisyear=tostring(ii)
                    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)
                        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
                    else
                        tRow:tag('td'):wikitext(' - ')
                    end
                end
            end
        end

        local UCIlink
        if wiki=="fr" then
            UCIlink="https://www.uci.org/fr/route/classements"
        else
            UCIlink="https://www.uci.org/road/rankings"
        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%;")
        :tag('tr')
        :tag('td'):attr('colspan',tostring(tableyearsize))
        :cssText("text-align:right")
        :tag('small'):wikitext(translate("race_reference", 1).."["..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)
    --first we have to read P54 of the rider
    local riderteam={}
    local stagiaire

    for ii, p54 in statements(itemID, 'P54') 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)
    --get the nature and name of the team for the date mm,yy
    local amateurTeam
    mm=tostring(mm)
    yy=tostring(yy)
    dd=tostring(dd)
    if mw.ustring.len(mm)==1 then mm='0'..mm end
    
    thistime='+'..yy.."-"..mm.."-"..dd.."T00:00:00Z"
    local sitelink, teamNature=getTeamLinkCat(teamId, thistime, false) 
    local amateurcat={Q20639848=true,Q20652655=true,Q26849121=true}

    if amateurcat[teamNature] then --club
        amateurTeam=true--amateur
    else
        amateurTeam=false--pro
    end
    return amateurTeam, sitelink
end

local function analyzeTeam(teamRider, initialYear,finalYear, dis)
    local teamOut={}
    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)
                                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,1)
                                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,30)
                                    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 listOfTeamTable(itemID, initialYear,finalYear)
    local teamRider = listofTeam(itemID, initialYear,finalYear)--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)
    local birthDate=firstValue(entityID, 'P569', 'time')
    local deathDate=firstValue(entityID, 'P570', 'time')
    local temp2, temp3, birth, death, initialYear, finalYear, age

    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) end

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

        if not deathDate 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) 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)
            elseif gen_plural then
                ans=translate("riderinfobox",49)
            else
                ans=translate("riderinfobox",50)
            end
            temp2=' ('..tostring(age)..' '..ans..')<br/>'
        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 

local function dispArrayLabel(details, index, entityID, PID)
        if not details[index].content then
        for _, p in statements(entityID, PID) do
            if p and p.mainsnak.snaktype == 'value' then
                local label=wikibase.getLabelByLang(p.mainsnak.datavalue.value.id, wiki)
                if label then
                    if not details[index].content then
                        details[index].content=label
                    else
                        details[index].content=details[index].content..'<br/>'..label
                        if details[index].name_plural then
                            details[index].name = details[index].name_plural
                        end
                    end
                end
            end
        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 details = {
        { name = translate("riderinfobox",1), name_plural =translate("riderinfobox",2)}, -- birth name
        { name = translate("riderinfobox",3), name_plural =translate("riderinfobox",4)}, -- nick name
        { name = translate("riderinfobox",5), name_plural =translate("riderinfobox",6)}, -- official name
        { name = translate("riderinfobox",7), name_plural =translate("riderinfobox",8)}, -- official name
        { name = translate("riderinfobox",9) }, -- birth translate("riderinfobox",9)
        { name = translate("riderinfobox",10)}, -- death
        { name = translate("riderinfobox",11), name_plural =translate("riderinfobox",12)}, -- country
        { name = translate("riderinfobox",13), name_plural =translate("riderinfobox",14)}, -- present team
        { name = translate("riderinfobox",15), name_plural =translate("riderinfobox",16)}, -- speciality
        { name = translate("riderinfobox",17) }, -- lateralisation
        { name = translate("riderinfobox",18) }, -- blood group
        { name = translate("riderinfobox",19) },  -- height
        { name = translate("riderinfobox",20) }, -- weight
        { name = translate("riderinfobox",21), name_plural =translate("riderinfobox",22)}, -- awards
    }
    
    local teams = {
        { name = translate("riderinfobox",23), name_plural =translate("riderinfobox",24)}, -- directed teams
        { name = translate("riderinfobox",25)}, -- directed years
        { name =  translate("riderinfobox",26), name_plural =translate("riderinfobox",27)}, -- amateur names  
        { name = translate("riderinfobox",28)}, -- amateur periods
        { name = translate("riderinfobox",29), name_plural =translate("riderinfobox",30)}, -- nonUCI names
        { name = translate("riderinfobox",31)}, -- nonUCI periods
        { name = translate("riderinfobox",32), name_plural =translate("riderinfobox",33)}, -- pro names
        { name = translate("riderinfobox",34)}, -- pro periods
        { name = translate("riderinfobox",35), name_plural =translate("riderinfobox",36)}, -- UCI names
        { name = translate("riderinfobox",37)}, -- UCI periods
        }

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

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

    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 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
    
    local commons_cat=firstValue(entityID, 'P373', 'id')
    
    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

    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)
    
    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

    if not details[7].content then
        local listOfProperty={'P1532','P27'}
        local countryID
        local countryList={}
    
        for _, prop in ipairs(listOfProperty) do
            if #countryList==0 then --if P1532 is used P17 is not used
                for _, p1532 in statements(entityID, prop) do
                    countryID = p1532.mainsnak.datavalue.value.id
                    local period, sTime=getPeriod( p1532.qualifiers, true)
                    if not sTime then sTime="+"..initialYear.."-01-01T00:00:00Z" end --first
                    local temp
                    if display_flag then
                        temp= flag(countryID, sTime).." "..getCountryName(countryID)
                    else
                        temp=getCountryName(countryID)
                    end
                    table.insert(countryList,{sTime, period,temp})
                end
            end
        end
        table.sort(countryList, function(a, b) return a[1] < b[1] end)
        
        if countryList and #countryList==1 then
            details[7].content=countryList[1][3]
        elseif countryList then
            details[7].name = details[7].name_plural
            details[7].content=''
            for _, v in pairs(countryList) do
                details[7].content= details[7].content..v[3] ..' <small>'..v[2]..'</small><br/>'
            end
        end
    end

    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
    dispArrayLabel(details, 9, entityID, 'P413')

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

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

    --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
    --  dispArrayLabel(details, 14, entityID, 'P166')
    --end

    local amateurTeam, nonUCITeam, proTeam, UCITeam --local data
    local amateurWD=true
    local proWD=true
    local teamAmateur,teamPro, teamMountainBike, teamCycloCross, teamTrack=listOfTeamTable(entityID, initialYear, finalYear)
    local managedTeam, managedTeam_names, managedTeam_periods, amateurTeam_names, amateurTeam_periods
    local nonUCITeam_names, nonUCITeam_periods, proTeam_names, proTeam_periods
    local UCITeam_names, UCITeam_periods

    if teams[1].content then
        managedTeam_names=teams[1].content
        managedTeam_periods=teams[2].content
    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 

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

    --managed teams
    if teams[1].content then
        localTeamTable(tab,managedTeam_names, managedTeam_periods,translate("riderinfobox",23), translate("riderinfobox",24))
    end
    
    if victories[1].content then
        tab:node(addATitle(translate("riderinfobox",38))) 
        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))) 
        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), entityID,commons_cat)
    return tab
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
        return getOfficialName(argu[2],argu[3],argu[4])
    elseif function_name=='getRiderLink' then
        temp=getRiderLink(argu[2],argu[3]) --only first arg returned
        return temp
    elseif function_name=='funcDate' then
        return funcDate(argu[2],argu[3])
    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=='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]))
    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
        return tostring(getMainRaceLink(argu[2],argu[3],argu[4], arg5,argu[6]))
    elseif function_name=='fn_getClassInfo1' then
        local temp= fn_getClassInfo(argu[2],argu[3],nil)
        return temp[1]
    elseif function_name=='fn_getClassInfo2' then
        local temp= fn_getClassInfo(argu[2],argu[3],nil)
        return temp[2]
    elseif function_name=='fn_getClassInfo4' then
        local temp= fn_getClassInfo(argu[2],argu[3],nil)
        return temp[4]  
    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=='commaStage' then
        temp =commaStage(argu[2],argu[3])
        return temp[1]
    elseif function_name=='number' then
        return number(argu[2],tonumber(argu[3]), argu[4])
    elseif function_name=='classToCircuit1' then
        temp, temp2= classToCircuit(argu[2], argu[3], argu[4], toboolean(argu[5]), nil) 
        return temp
    elseif function_name=='classToCircuit2' then
        temp, temp2= classToCircuit(argu[2], argu[3], argu[4], toboolean(argu[5]), nil) 
        return temp2
    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
    end
end

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

    if function_name=='class' then
        return tostring(class[tonumber(argu[2])])
    elseif function_name=='class_2x' then
        return tostring(class_2x[tonumber(argu[2])])
    elseif function_name=='class_without2x' then
        return tostring(class_without2x[tonumber(argu[2])])
    elseif function_name=="class_sort" then
        return tostring(class_sort[argu[2]])
    elseif function_name=='classes' then
        return tostring(classes[argu[2]])
    elseif function_name=='stages' then 
        return tostring(stages[tonumber(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