Die Dokumentation für dieses Modul kann unter Modul:SkinData/Doku erstellt werden

-- <pre>
local p = {}

local skinData  = mw.loadData('Module:SkinData/data')
local lib       = require('Module:Feature')
local color     = require('Module:Color')
local FN        = require('Module:Filename')
local IL        = require('Module:ImageLink')
local userError = require('Dev:User error')

-- Input: "skins" Tabelle eines Champs in Modul:SkinData/data
-- Output: Iterator über nach Skin-ID sortierte Tabelle mit 3 nutzbaren return values:
    -- k, v, i -> Key, Value -> Iterationszähler i -> Bsp Ahri: Standard Ahri   table   1
        -- table ist die Tabelle aus "skins" hinter dem Key ["Standard Ahri"]
    -- Nutzungsmögl.: for k, v, i in skinIter(t) - for k, v in skinIter(t) - for k in skinIter(t)
    -- entfernte skins werden aktuell übersprungen (sollte vllt an und ausschaltbar sein)
function skinIter(t)
    local keys = {}
    for k in pairs(t) do
        if t[k]['id'] ~= nil then
            keys[#keys+1] = k
        end
    end

    table.sort(keys, function(a,b)
        return (t[a]['custom_sort_id'] or t[a]['id']) < (t[b]['custom_sort_id'] or t[b]['id'])
    end)

    -- return the iterator function
    local i = 0
    return function()
        i = i + 1
        if keys[i] then
            return keys[i], t[keys[i]], i
        end
    end
end

function p.skinscount()
    local s           = ""
    local resulttable = {}
    local prices      = {}
    local limited     = 0
    local rare        = 0
    local total       = 0
    local cost        = 0

    for championname in pairs(skinData) do
        local t = skinData[championname]["skins"]
        for skinname in pairs(t) do
            if skinname ~= "Standard "..championname and t[skinname]["id"] ~= nil and t[skinname]["release"] ~= "N/A" and t[skinname]["availability"] ~= "Kommend" then
                if t[skinname]["availability"] == "Limitiert" then
                        limited = limited + 1
                        total   = total   + 1
                else
                    local price = t[skinname]["cost"]
                    if price == 10 or price == 100 or price == "Speziell" then
                        price = 2450
                    end
                    
                    if t[skinname]["looteligible"] == false then
                        rare  = rare  + 1
                        total = total + 1
                    else
                        if resulttable[price] == nil then
                            resulttable[price] = 0
                            table.insert(prices, price)
                        end
                        resulttable[price] = resulttable[price] + 1
                        total = total + 1
                        cost  = cost + price
                    end
                end
            end
        end
    end
    table.sort(prices)
    
    s = '<table class="wikitable sortable">'
    s = s .. '  <tr><th data-sort-type="number">Preis</th><th>Anzahl</th></tr>'
    for _, price in pairs(prices) do
        s = s ..'  <tr><td data-sort-value="' .. price .. '" style="text-align:right">' .. price .. '</td><td style="text-align:right">' .. resulttable[price] .. '</td></tr>'
    end
    
    s = s .. '  <tr><td data-sort-value="50000" style="text-align:right">Selten</td><td style="text-align:right">' .. rare .. '</td></tr>'
    s = s .. '  <tr><td data-sort-value="60000" style="text-align:right">Limitiert</td><td style="text-align:right">' .. limited .. '</td></tr>'
    s = s .. '</table>'
    s = s .. 'Gesamt: ' .. total ..' Skins (Gesamt: ' .. cost .. ' RP)'
    
    return s
end

function p.splashartistpage()
    local searchstring = mw.title.getCurrentTitle().text

    local championtable = {}
    for championname in pairs(skinData) do
        table.insert(championtable, championname)
    end
    table.sort(championtable)

    local resulttable = {}
    for _, championname in pairs(championtable) do
        local skintable  = {}
        for championname in pairs(skinData[championname]["skins"]) do
            table.insert(skintable, championname)
        end
        table.sort(skintable)

        for _, skinname in pairs(skintable) do
            local t = skinData[championname]["skins"][skinname]
            
            if t.splashartist ~= nil then
                for _, splashartistname in pairs(t.splashartist) do
                    if splashartistname == searchstring then
                        table.insert(resulttable, {championname, skinname, t.formatname, t.splashartist})
                    end
                end
            end
        end
    end
    
    if #resulttable == 0 then
        return userError("Kein Ergebnis für " .. searchstring, "LuaError")
    end
    
    -- Drei zufällige Bilder mit Beispielen
    math.randomseed(os.time())
    local hash = {}
    local rnd  = 0
    local s1   = ""
    
    for i = 1, 3 do
        rnd = math.random(#resulttable)
        if hash[rnd] ~= true then
            s1 = s1 .. "[[File:" .. FN.skin({resulttable[rnd][1], resulttable[rnd][2]}) .. "|thumb|200px|Arbeitsbeispiel.]]"
        end
        hash[rnd] = true
    end
    
    -- Splash Art list
    local s2 = "<dl><dt>Splash-Art</dt></dl><ul><li>"
    local tempval = ""
    for i, val in pairs(resulttable) do
        local championname = val[1]
        local skinname     = val[2]
        local formatname   = val[3]
        local splashartist = val[4]
        
        if tempval == championname then
            s2 = s2 .. ", "
        else
            if i ~= 1 then
                s2 = s2 .. "</li><li>"
            end
            tempval = championname
        end
        s2 = s2 .. tostring(IL.skin{
            ["champion"] = championname,
            ["skin"] = skinname,
            ["link"] = championname .. "#tab-Skins",
            ["text"] = (skinname:find("Standard") and championname or skinname),
            ["circle"] = "true"
        })
        
        count = 0
        for i, val in pairs (splashartist) do
            if val ~= searchstring then
                if count == 0 then
                    s2 = s2 .. " <small>(Kollaboration mit "
                else
                    s2 = s2 .. ", "
                end
                s2 = s2 .. splashartist[i]
                count = count + 1
            end
        end
        if count ~= 0 then
            s2 = s2 .. ")</small>"
        end
    end
    s2 = s2 .. "</li></ul>"
    
    return s1 .. s2
end

function p.chromapartner(frame)
    local s = ''
    
    s = s .. '<div id="chromaexhibition" style="position:relative">'
    s = s .. '<b>Partnerprogramm-Chromas</b>'
    s = s .. '<div class="chroma-gallery" style="width:718px; text-align:center"><div class="base">[[File:Partner Program LoL Logo.png|150px]]</div>'
    
    local championtable = {}
    for x in pairs(skinData) do
        table.insert(championtable, x)
    end
    table.sort(championtable)
    
    local resulttable = {}
    for _, championname in pairs(championtable) do
        local skintable  = {}
        for championname in pairs(skinData[championname]["skins"]) do
            table.insert(skintable, championname)
        end
        table.sort(skintable)
 
        for _, skinname in pairs(skintable) do
            local chromatable = {}
            local t           = skinData[championname]["skins"][skinname]
            local formatname  = t.formatname
            
            if t.chromas ~= nil then
                t = t.chromas
                for chromaname in pairs(t) do
                    if t[chromaname].distribution == "Partnerprogramm" then
                        s = s .. '<div class="skin-icon" data-character="' .. championname .. '" data-skin="' .. skinname .. '"><div class="chroma partner-border">[[File:' .. FN.chroma({championname, skinname, chromaname}) .. '|100px|border|link=]]</div> <div class="chroma-caption">[[File:' .. FN.championcircle({championname, skinname}) .. '|20px|link=' .. championname .. ']] [[' .. championname .. '|' .. lib.ternary(formatname, formatname, skinname) .. ']]</div></div>'
                    end
                    
                end
            end
        end
    end
    s = s .. '</div>'
    
    return s
end


function p.chromagallery(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2] or "Standard "..champname
    local variant   = args['variant'] or args[3]
    
    local t = skinData[champname].skins[skinname]
    if t == nil or t.chromas == nil then
        return userError("Keine Chromas für den Skin ''" .. skinname .. "'' im Modul:SkinData/data hinterlegt", "LuaError")
    end
    t = t.chromas
    
    local header = "Chromas"
    local headerpre = ""
    if variant ~= nil then
        headerpre = "Alte "
    end
    local frame = mw.getCurrentFrame()
    
    if skinData[champname].skins[skinname].forms ~= nil then
        header = "Formen"
    end
    
    local chromatable  = {}
    local chromastring = args['chromas'] or "true"
    if chromastring == "true" then
        for chromaname in pairs(t) do
            table.insert(chromatable, chromaname)
        end
    else
        chromatable = lib.split(chromastring, ",")
    end
    table.sort(chromatable)
    
    local formatname = skinData[champname].skins[skinname].formatname
    local key        = args["key"] or "true" 
    local imagewidth = "100px"
    local s = ''
    s = s .. '<div id="chromaexhibition" style="position:relative"><b>' .. headerpre .. lib.ternary(formatname, formatname, skinname) .. " " .. header .. "</b>"
    
    if key == "true" then
        s = s .. "<div class='tip-tooltip icon' data-tip='Chroma-Ausstellung' style='position:absolute; top:5px; right: 5px; z-index:20;'>[[File:Information.svg|30px|link=]]</div>"
    end
    
    if #chromatable > 8 then
        imagewidth = "80px"
        s = s .. '<div class="chroma-gallery-large" style="width:718px; text-align:center">'
    else
        s = s .. '<div class="chroma-gallery" style="width:718px; text-align:center">'
    end
    
    s = s .. '<div class="base">[[File:' .. FN.chroma({champname, skinname, variant = variant}) .. '|183px]]</div>'
    
    for i, chromaname in pairs(chromatable) do
        if skinData[champname].skins[skinname].chromas[chromaname] == nil then
            return userError("Chroma ''" .. chromaname .. "'' nicht hinterlegt im Modul:SkinData/data für " .. lib.ternary(formatname, formatname, skinname), "LuaError")
        end
        
        local availability = skinData[champname].skins[skinname].chromas[chromaname].availability or "Verfügbar"
        
        if availability ~= "Verworfen" then
            s = s .. "<div><div class='chroma " .. string.lower(availability) .. "-border'>[[File:" .. FN.chroma({champname, skinname, chromaname, variant = variant}) .. "|" .. imagewidth .. "|border]]</div> <div class='chroma-caption'>" .. chromaname .. "</div></div>"
        end
    end
    
    s = s .. '</div></div>'
    
    return frame:preprocess(s)
end


-- TODO: Mobile, inline css <=> Wikia.css, Urfwick text
function p.skinpage(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
    local champname = lib.validateName(args['champion'] or args[1] or mw.title.getCurrentTitle().rootText)
    if skinData[champname] == nil then
        return userError("Champion ''" .. champname .. "'' existiert nicht im Modul:SkinData/data", "LuaError")
    end
    local t = skinData[champname]["skins"]
    local standardizedname = string.lower(champname:gsub("[' ]", ""))
        if standardizedname == "wukong" then
            standardizedname = "monkeyking"
        end
    
    local container = mw.html.create('div'):addClass('lazyimg-wrapper')
    local navContainer = mw.html.create('div')
        :addClass('skinviewer-nav')
        :addClass('hidden')
        :css({
            ['display'] = 'flex',
            ['justify-content'] = 'center',
            ['margin-bottom'] = '10px',
        })
    local tabContainer = mw.html.create('div'):addClass('skinviewer-tab-container')
    
    for k,v,i in skinIter(t) do
        local releaseSplit = mw.text.split(v['release'], '%D')
        local cost
        if type(v['cost']) ~= 'number' then
            cost = '<div class="skinviewer-price" title="'.. (v['distribution'] and v['distribution'] or 'Dieser Skin konnte nur auf besondere Art und Weise erhalten werden.') ..'">Speziell</div>'
        elseif v['cost'] == 10 then
            cost = '<div class="skinviewer-price" title="Dieser Skin kann mit Edelsteinen in der Hextech-Werkstatt hergestellt werden.">[[Datei:Edelstein Symbol.png|20px]] 10</div>'
        elseif v['cost'] == 100 then
            cost = '<div class="skinviewer-price" title="Dieser Skin kann mit Prestige-Punkten in der Hextech-Werkstatt hergestellt werden.">[[Datei:Prestige-Punkte_Währung.png|20px]] 100</div>'
        elseif v['cost'] == 150000 then
            cost = '<div class="skinviewer-price" title="Limitierte Skins sind Skins, welche nur für einen bestimmten Zeitraum (z.B. ein Event) verfügbar waren und danach nicht mehr erhältlich sind.">Limitiert ([[Datei:BE_Saison_8.png|20px|link=Championskin#Limitierte Skins]] 150000)</div>' 
        else
            cost = '<div class="skinviewer-price" title="Dieser Skin kann mit Riot Points erworben werden.">[[Datei:RpPoints.png|20px]] '.. v["cost"] ..'</div>'
        end
        
        navContainer
            :tag('span')
                :attr('id', i)
                :addClass('show')
                :css({
                    ['position'] = 'relative',
                    ['width'] = '52px',
                    ['height'] = '52px'
                })
                :wikitext(v['chromas'] and '[[Datei:Chromaskins.png|x52px||link=]]' or '')
                :tag('span')
                    :css({
                        ['position'] = 'absolute',
                        ['top'] = 0,
                        ['left'] = 0,
                        ['right'] = 0,
                        ['bottom'] = 0,
                        ['z-index'] = 100,
                        ['padding'] = '2px'
                    })
                    :attr('title', k)
                    :wikitext(string.format('[[Datei:%s||link=|x48px]]', FN.championcircle({ champname, k })))
                    :done()
                :done()
        tabContainer
            :tag('div')
                :addClass('skinviewer-tab-content')
                :addClass(i==1 and 'skinviewer-active-tab' or '')
                :attr('id', 'item-'..i)
                :css('display', i~=1 and 'none' or 'block')
                :tag('div')
                    :addClass('skinviewer-tab-skin')
                    :css('position', 'relative')
                    :css('font-family', 'BeaufortLoL')
                    :wikitext(string.format('[[Datei:%s||link=]]', FN.skin({ champname, k })))
                    :wikitext(cost)
                    :tag('div')
                        :css({
                            ['position'] = 'absolute',
                            ['bottom'] = 0,
                            ['left'] = 0,
                            ['right'] = 0,
                            ['z-index'] = '100',
                            ['display'] = 'flex',
                            ['justify-content'] = 'space-between',
                            ['align-items'] = 'flex-end',
                            ['background-color'] = 'rgba(0,0,0,0.6)',
                            ['border-top'] = '1px solid rgba(0,0,0,0.25)',
                            ['border-left'] = '1px solid rgba(0,0,0,0.25)',
                            ['border-right'] = '1px solid rgba(0,0,0,0.25)',
                            ['border-radius'] = '6px 6px 0 0',
                            ['height'] = '24px',
                            ['line-height'] = '24px',
                            ['font-size'] = '20px'
                        })
                        :tag('div')
                            :css({
                                ['flex'] = '1 1 0px',
                                ['text-align'] = 'left'
                            })
                            :wikitext('[[Datei:3DButton.png|x24px|link=https://teemo.gg/model-viewer?model-type=champions&skinid='.. standardizedname ..'-'.. (v['id'] or 0) ..']]')
                            :wikitext('[[Datei:ZumBildButton.png|x24px|link=File:', FN.skin({ champname, k }), ']]')
                            :done()
                        :tag('div')
                            :css({
                                ['flex'] = '2 1 0px',
                                ['text-align'] = 'center',
                                ['color'] = '#d3c7aa',
                                ['font-weight'] = 700
                            })
                            :wikitext(k)
                            :done()
                        :tag('div')
                            :css({
                                ['flex'] = '1 1 0px',
                                ['text-align'] = 'right',
                                ['color'] = '#c9aa71',
                                ['font-size'] = 'smaller',
                                ['padding-right'] = '2px'
                            })
                            :wikitext(mw.ustring.format('%s.%s.%s', releaseSplit[3], releaseSplit[2], releaseSplit[1]))
                            :done()
                        :done()
                    :done()
                :tag('div')
                    :addClass('skinviewer-info')
                    :css({
                        ['padding'] = '15px',
                        ['background-color'] = 'rgba(10, 24, 39, 0.9)',
                        ['font-family'] = 'BeaufortLoL',
                        ['font-size'] = '14px'
                    })
                        :tag('div')
                            :addClass('skinviewer-info-lore')
                            :wikitext(lib.ternary(v['lore'] ~= nil, '<div style="line-height: 1.6em; text-align: center; font-size: 15px;">' .. tostring(v['lore']) .. '</div>', ''))
                            :done()
                        :tag('div')
                            :addClass('skinviewer-info-kleine-bilder')
                            :css({
                                ['display'] = 'flex',
                                ['justify-content'] = 'center'
                            })
                            :wikitext(lib.ternary(p.getVoiceactor{champname, k} ~= nil, '<div style="padding-right:1em; text-align:center;">[[File:Actor.png|20px|link=]]' .. tostring(p.getVoiceactor{champname, k}) .. '</div>', ''))
                            :wikitext(lib.ternary(p.getSplashartist{champname, k} ~= nil, '<div style="padding-right:1em; text-align:center;">[[File:Artist.png|20px|link=]]' .. tostring(p.getSplashartist{champname, k}) .. '</div>', ''))
                            :wikitext(lib.ternary(p.getSet{champname, k} ~= nil, '<div style="padding-right:1em; text-align:center;">[[File:Set piece.png|20px|link=]]' .. tostring(p.getSet{champname, k}) .. '</div>', ''))
                            :wikitext(lib.ternary(v['looteligible'] ~= false, '<div style="padding-right:1em; text-align:center;">[[File:Loot eligible.png|20px|link=]] Über Beute erhältlich</div>', ''))
                            :wikitext(lib.ternary(v['looteligible'] == false, '<div style="padding-right:1em; text-align:center;">[[File:Loot ineligible.png|20px|link=]] Nicht über Beute erhältlich </div>', ''))
                            :done()
                        :tag('div')
                            :addClass('skinviewer-info-grosse-bilder')
                            :css({
                                ['display'] = 'flex',
                                ['justify-content'] = 'center',
                                ['padding-top'] = '5px'
                            })
                            :wikitext(v['availability'] == 'Limitiert' and '<div style="padding:0 1em; text-align:center;"><div>[[File:Limited skin.png|50px|link=]]</div><div>Limitierte Edition</div></div>' or (v['availability'] == 'Legacy' and '<div style="padding:0 1em; text-align:center;"><div>[[File:Legacy skin.png|50px|link=]]</div><div>Klassisch</div></div>' or ''))
                            :wikitext(lib.ternary(v['filter'] ~= nil, '<div style="padding:0 1em; text-align:center;"><div>[[File:Voice filter.png|50px|link=]]</div><div>Sprachfilter</div></div>', ''))
                            :wikitext(lib.ternary(v['newquotes'] ~= nil, '<div style="padding:0 1em; text-align:center;"><div>[[File:Additional quotes.png|50px|link=]]</div><div>Zusätzliche Sprüche</div></div>', ''))
                            :wikitext(lib.ternary(v['newvoice'] ~= nil, '<div style="padding:0 1em; text-align:center;"><div>[[File:New voice.png|50px|link=]]</div><div>Neue Stimme</div></div>', ''))
                            :wikitext(lib.ternary(v['neweffects'] ~= nil, '<div style="padding:0 1em; text-align:center;"><div>[[File:New effects.png|50px|link=]]</div><div>Neue SFX/VFX</div></div>', ''))
                            :wikitext(lib.ternary(v['newanimations'] ~= nil, '<div style="padding:0 1em; text-align:center;"><div>[[File:New animations.png|50px|link=]]</div><div>Neue Animationen</div></div>', ''))
                            :wikitext(lib.ternary(v['transforming'] ~= nil, '<div style="padding:0 1em; text-align:center;"><div>[[File:Transforming.png|50px|link=]]</div><div>Transformierend</div></div>', ''))
                            :wikitext(lib.ternary(v['extras'] ~= nil, '<div style="padding:0 1em; text-align:center;"><div>[[File:Includes extras.png|50px|link=]]</div><div>Enthält Extras</div></div>', ''))
                            :wikitext(lib.ternary(v['chromas'] ~= nil, '<div style="padding:0 1em; text-align:center;"><div>[[File:Chromas available.png|50px|link=]]</div><div>Chromas</div></div>', ''))
                            :done()
                        :tag('div')
                            :addClass('skinviewer-info-variantof')
                            :css('text-align', 'center')
                            :wikitext(lib.ternary(p.getVariant{champname, k} ~= nil, '<div>Dieser Skin ist eine Variante von ' .. tostring(IL.skin{champion = champname, skin = p.getVariant{champname, k}, circle = "true", link = '*none*', text = p.getVariant{champname, k}}) .. '.</div>', ''))
                            :done()
                    :done()
                :tag('div')
                    :addClass('skinviewer-tab-chroma')
                    :wikitext(v['chromas'] and p.chromagallery{champname, k} or '')
                    :done()
    end
    
    return container:node(navContainer):node(tabContainer)
    
end

function p.getAllchampionskins(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])

    return skinData[champname]
end

function p.getChampionskin(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Standard "..champname]
end

function p.getFormatname(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinname or "Standard "..champname
end

function p.getAvailability(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Standard "..champname].availability
end

function p.getDistribution(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Standard "..champname].distribution
end

function p.getCost(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Standard "..champname].cost
end

function p.getRelease(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Standard "..champname].release
end

function p.getRetired(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Standard "..champname].retired
end

function p.getEarlysale(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Standard "..champname].earlysale
end

function p.getSet(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    local t = skinData[champname].skins[skinname or "Standard "..champname].set
    
    if t == nil then
        return nil
    end
    
    for i, setname in ipairs(t) do
        if i ~= 1 then
            s = s .. ", " .. setname:gsub("% ", "&nbsp;")
        else
            s = setname
        end
    end

    return s
end

function p.getSetlist(frame)
    local championtable = {}
    local sets = {}
    local hash = {}
    local setList = mw.html.create('ul')
    
    setList:newline()
    
    for x in pairs(skinData) do
        table.insert(championtable, x)
    end
    table.sort(championtable)

    for _, championname in pairs(championtable) do
        local skintable  = {}
        for championname in pairs(skinData[championname]["skins"]) do
            table.insert(skintable, championname)
        end
        table.sort(skintable)

        for _, skinname in pairs(skintable) do
            local t = skinData[championname]["skins"][skinname]
            
            if t.set ~= nil then
                for _, value in pairs(t.set) do
                    if (not hash[value]) then
                        table.insert(sets, value)
                        hash[value] = true
                    end
                end
            end
        end
    end
    
    table.sort(sets)
    
    for _, setname in pairs(sets) do
        setList
            :tag('li')
                :wikitext('[[' .. setname .. ']]')
                :done()
            :done()
            :newline()
    end
 
    return setList
end

function p.getSetskins(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
 
    local skinList = mw.html.create('ul')
    local championtable = {}
    local result = false
    
    skinList:newline()
    
    for x in pairs(skinData) do
        table.insert(championtable, x)
    end
    table.sort(championtable)
 
    for _, championname in pairs(championtable) do
        local skintable  = {}
        
        for championname in pairs(skinData[championname]["skins"]) do
            table.insert(skintable, championname)
        end
        table.sort(skintable)
        
        for _, skinname in pairs(skintable) do
            local hit = false
            local t = skinData[championname]["skins"][skinname]
            
            if t.set ~= nil then
                for _, subset in pairs(t.set) do
                    if subset == args[1] then
                        hit = true
                        result = true
                    end
                end
            end
            if hit == true then
                skinList
                    :tag('li')
                        :tag('div')
                            :addClass('skin-icon')
                            :attr('data-character', championname)
                            :attr('data-skin', skinname)
                            :wikitext('[[File:' .. FN.championcircle({championname, skinname}) .. '|20px|link=' .. championname .. ']] [[' .. championname .. '|' .. lib.ternary(t["formatname"] ~= nil, t["formatname"], skinname) .. ']]')
                        :done()
                    :done()
                    :newline()
            end
        end
    end

    if result == false then 
        skinList
            :tag('li')
                :wikitext('Kein Ergebnis für ' .. args[1] .. ' gefunden.')
            :done()
            :newline()
    end
 
    return skinList
end

function p.getNeweffects(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Standard "..champname].neweffects
end

function p.getNewrecall(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Standard "..champname].newrecall
end

function p.getNewanimations(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Standard "..champname].newanimations
end

function p.getTransforming(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Standard "..champname].transforming
end

function p.getFilter(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Standard "..champname].filter
end

function p.getNewquotes(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Standard "..champname].newquotes
end

function p.getNewvoice(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Standard "..champname].newvoice
end

function p.getExtras(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Standard "..champname].extras
end

function p.getLore(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Standard "..champname].lore
end

function p.getLootEligible(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Standard "..champname].looteligible
end

function p.getChromas(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Standard "..champname].chromas
end

function p.getChromacount(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    local t = skinData[champname].skins[skinname or "Standard "..champname].chromas
    local s = ""
    
    local chromatable  = {}
    for chromaname in pairs(t) do
        table.insert(chromatable, chromaname)
    end
    
    return #chromatable or "N/A"
end

function p.getChromanames(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    local t = skinData[champname].skins[skinname or "Standard "..champname]
    if t == nil or t.chromas == nil then
        return ""
    end
    t = t.chromas
    
    local chromatable  = {}
    for chromaname in pairs(t) do
        table.insert(chromatable, chromaname)
    end
    table.sort(chromatable)

    local s = ""
    for i, chromaname in pairs(chromatable) do
        if i ~= 1 then
            s = s  .. ", " .. chromaname
        else
            s = s .. chromaname
        end
    end
    
    return s
end

function p.getForms(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Standard "..champname].forms
end

function p.getFormnames(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    local t = skinData[champname].skins[skinname or "Standard "..champname].forms
    local s = ""
    
    local formtable  = {}
    for formname in pairs(t) do
        table.insert(formtable, formname)
    end
    table.sort(formtable)

    for i, formname in pairs(formtable) do
        if i ~= 1 then
            s = s  .. ", " .. formname
        else
            s = s .. formname
        end
    end
    
    return s
end

function p.getFormicon(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Standard "..champname].formicon
end

function p.getVu(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    return skinData[champname].skins[skinname or "Standard "..champname].vu
end

function p.getSplashartist(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    local t = skinData[champname].skins[skinname or "Standard "..champname].splashartist
    local s = ""
    
    if t == nil then
        return "Unbekannter Künstler"
    end
    
    for i, splashartistname in ipairs(t) do
        if i ~= 1 then
            s = s .. ", " .. splashartistname:gsub("% ", "&nbsp;")
        else
            s = splashartistname
        end
    end
    return s
end

function p.getArtistlist(frame)
    local championtable = {}
    local artists = {}
    local hash = {}
    local artistList = mw.html.create('ul')
    
    artistList:newline()
    
    for x in pairs(skinData) do
        table.insert(championtable, x)
    end
    table.sort(championtable)

    for _, championname in pairs(championtable) do
        local skintable  = {}
        for championname in pairs(skinData[championname]["skins"]) do
            table.insert(skintable, championname)
        end
        table.sort(skintable)

        for _, skinname in pairs(skintable) do
            local t = skinData[championname]["skins"][skinname]
            
            if t.splashartist ~= nil then
                for _, value in pairs(t.splashartist) do
                    if (not hash[value]) then
                        table.insert(artists, value)
                        hash[value] = true
                    end
                end
            end
        end
    end
    table.sort(artists)
        
    for _, artist in pairs(artists) do
        artistList
            :tag('li')
                :wikitext('[[' .. artist .. ']]')
                :done()
            :done()
            :newline()
    end
    
    return artistList
end

function p.getVariant(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    local searchid = skinData[champname].skins[skinname or "Standard"..champname].variant
    local skintable = {}
    
    if searchid == nil then
        return nil
    end
    
    for skinname, data in pairs(skinData[champname]["skins"]) do
        if data.id == searchid then
            return skinname
        end
    end

    return nil
end

function p.getVoiceactor(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
        
    local champname = lib.validateName(args['champion'] or args[1])
    local skinname  =                  args['skin']     or args[2]
    
    local t = skinData[champname].skins[skinname or "Standard"..champname].voiceactor
    local s = ""
    
    if t == nil then
        return "Unbekannter Sprecher"
    end
    
    for i, voiceactorname in ipairs(t) do
        if i ~= 1 then
            s = s .. ", " .. voiceactorname:gsub("% ", "&nbsp;")
        else
            s = voiceactorname
        end
    end

    return s
end

function p.skinlist(frame)
    local lang = mw.language.new( "de" )
    local sdtable = mw.html.create('table')
    
    sdtable
        :addClass('sortable article-table nopadding sticky-header')
        :css('width','100%')
        :css('text-align','center')
        :newline()
        :tag('tr')
            :tag('th')
                :css('width','26px')
            :done()
            :newline()
            :tag('th')
                :wikitext('Skin')
            :done()
            :newline()
            :tag('th')
                :tag('span')
                    :attr('title','Verfügbarkeit')
                    :wikitext('[[File:Availability.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :tag('span')
                    :attr('title','Veröffentlichung')
                    :wikitext('[[File:Release.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :tag('span')
                    :attr('title','Kosten')
                    :wikitext('[[File:RpPoints.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','Sprachfilter')
                    :wikitext('[[File:Voice filter.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','Zusätzliche/einmalige Sprüche')
                    :wikitext('[[File:Additional quotes.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','Neues Voiceover')
                    :wikitext('[[File:New voice.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','Neue visuelle und/oder Soundeffekte')
                    :wikitext('[[File:New effects.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','Neue Animationen und/oder Rückrufanimationen')
                    :wikitext('[[File:New animations.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','Erscheinung kann im Spiel umgeschaltet werden [z.B. STRG + 5], oder der Skin "entwickelt" sich im Verlaufe des Spiels auf eine Weise, die nicht den Grundmechaniken des Champions entspricht.')
                    :wikitext('[[File:Transforming.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','Teil einer Sammlung')
                    :wikitext('[[File:Set piece.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('span')
                    :attr('title','Enthält Geschichte')
                    :wikitext('[[File:Mission icon.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('div')
                    :attr('title','Chromas')
                    :css('width','30px')
                    :css('height','30px')
                    :css('padding','5px')
                    :wikitext('[[File:Chromaskins.png|30px|link=|]]')
                :done()
            :done()
        :done()
        :newline()
        
        
        -- START
        local championtable = {}
        for x in pairs(skinData) do
            table.insert(championtable, x)
        end
        table.sort(championtable)
        
        local availablenode = mw.html.create('span')
        availablenode
            :css('color', 'green')
            :css('font-size', 'x-large')
            :css('vertical-align', 'text-top')
            :wikitext("✔")
            
        local legacynode = mw.html.create('span')
        legacynode
            :css('color', 'yellow')
            :css('font-size', 'x-large')
            :css('font-weight', '600')
            :css('vertical-align', 'text-top')
            :wikitext("‒")
            
        local limitednode = mw.html.create('span')
        limitednode
            :css('color', 'red')
            :css('font-size', 'x-large')
            :css('vertical-align', 'text-top')
            :wikitext("✘")
        local rarenode = mw.html.create('span')
        rarenode
            :css('color', 'orange')
            :css('font-size', 'x-large')
            :css('vertical-align', 'text-top')
            :wikitext("⭐")
        
        
        for _, championname in pairs(championtable) do
            local skintable  = {}
            for championname in pairs(skinData[championname]["skins"]) do
                table.insert(skintable, championname)
            end
            table.sort(skintable)
    
            for _, skinname in pairs(skintable) do
                if (
                    championname == "Akali"      and skinname == "Blutrote Akali" 
                    or 
                    championname == "Amumu"      and skinname == "Chaospuppe-Amumu"
                    or
                    championname == "Blitzcrank" and skinname == "Chaospuppe-Blitzcrank"
                    or
                    championname == "Ryze"       and skinname == "Menschlicher Ryze"
                ) then
                    -- skip
                else
                    local t = skinData[championname]["skins"][skinname]
                    local sdnode = mw.html.create('tr')
                    local temp = ""
                    
                    -- Skincircle
                    if (skinname == "Standard"..championname) then
                        temp = "!" .. t["release"]
                    else 
                        temp = t["release"]
                    end
                    
                    sdnode
                        :tag('td')
                            :addClass('character-icon')
                            :attr('data-sort-value', championname .. temp)
                            :attr('data-character', championname)
                            :attr('data-skin', skinname)
                            :wikitext('[[File:' .. FN.championcircle({championname, skinname}) .. '|20px|link=' .. championname .. ']]')
                        :done()
                    
                    -- Skinname
                    sdnode
                        :tag('td')
                            :addClass('skin-icon')
                            :attr('data-character', championname)
                            :attr('data-skin', skinname)
                            :css('text-align', 'left')
                            :wikitext(lib.ternary(t["formatname"] ~= nil, t["formatname"], skinname))
                        :done()
                    
                    -- Availability
                    astring = '<span style="color: cornflowerblue;font-size: large;font-weight: 600;">⭘</span>'
                    if (t["availability"] == "Verfügbar") then
                        astring = tostring(availablenode)
                    end
                    if (t["availability"] == "Klassisch") then
                        astring = tostring(legacynode)
                    end
                    if (t["availability"] == "Limitiert") then
                        astring = tostring(limitednode)
                    end
                    if (t["availability"] == "Selten") then
                        astring = tostring(rarenode)
                    end
                    sdnode
                        :tag('td')
                            :tag('span')
                                :attr('title', t["availability"] or 'Kommend')
                                :wikitext(astring)
                        :done()
                    
                    -- Release
                    local y, m, d = t["release"]:match("(%d+)-(%d+)-(%d+)")
                    if y == nil or m == nil or d == nil then
                        sdnode
                            :tag('td')
                                :attr('data-sort-value', t["release"])
                                :wikitext(t["release"])
                            :done()
                    else
                        sdnode
                            :tag('td')
                                :attr('data-sort-value', t["release"])
                                :wikitext(lang:formatDate('d-M-Y', t["release"]))
                            :done()
                    end
                    
                    -- Cost
                    local image = ""
                    if (tostring(t["cost"]) == "150000") then
                        image = "[[File:BE_Saison_8.png|20px|link=]]"
                    end 
                    if (tostring(t["cost"]) == "100") then
                        image = "[[File:Hextech Crafting Prestige token.png|20px|link=]]"
                    end
                    if (tostring(t["cost"]) == "10") then
                        image = "[[File:Rare Gem.png|20px|link=]]"
                    end
                    sdnode
                        :tag('td')
                            :attr('data-sort-value', lib.ternary(tostring(t["cost"]) == "10" or tostring(t["cost"]) == "100", "2450", t["cost"]))
                            :tag('span')
                                :css('color', color.skin({t["cost"] .. ""}))
                                :wikitext(image .. t["cost"])
                            :done()
                        :done()
                    
                    -- Filter
                    sdnode
                        :tag('td')
                            :attr('data-sort-value', lib.ternary(type(t["filter"]) ~= "nil", 1, 0))
                            :wikitext(lib.ternary(type(t["filter"]) ~= "nil", tostring(availablenode), ""))
                        :done()
                        
                    -- Newquotes
                    sdnode
                        :tag('td')
                            :attr('data-sort-value', lib.ternary(type(t["newquotes"]) ~= "nil", 1, 0))
                            :wikitext(lib.ternary(type(t["newquotes"]) ~= "nil", tostring(availablenode), ""))
                        :done()
                        
                    -- Newvoice
                    sdnode
                        :tag('td')
                            :attr('data-sort-value', lib.ternary(type(t["newvoice"]) ~= "nil", 1, 0))
                            :wikitext(lib.ternary(type(t["newvoice"]) ~= "nil", tostring(availablenode), ""))
                        :done()
                        
                    -- Neweffects
                    sdnode
                        :tag('td')
                            :attr('data-sort-value', lib.ternary(type(t["neweffects"]) ~= "nil", 1, 0))
                            :wikitext(lib.ternary(type(t["neweffects"]) ~= "nil", tostring(availablenode), ""))
                        :done()
                        
                    -- Newanimations
                    sdnode
                        :tag('td')
                            :attr('data-sort-value', lib.ternary(type(t["newanimations"]) ~= "nil", 1, 0))
                            :wikitext(lib.ternary(type(t["newanimations"]) ~= "nil", tostring(availablenode), ""))
                        :done()
                        
                    -- Transforming
                    sdnode
                        :tag('td')
                            :attr('data-sort-value', lib.ternary(type(t["transforming"]) ~= "nil", 1, 0))
                            :wikitext(lib.ternary(type(t["transforming"]) ~= "nil", tostring(availablenode), ""))
                        :done()
                    
                    -- Set
                    local multiset = false
                    if (type(t["set"]) ~= "nil") then
                        local s = ""
                        
                        for i, setname in pairs(t["set"]) do
                            if i == 1 then
                                s = setname
                            else
                                multiset = true
                                s = s .. ", " .. setname
                            end
                        end
                        
                        if multiset == true then
                            sdnode
                                :tag('td')
                                    :attr('data-sort-value', '1 Multiple')
                                    :tag('span')
                                        :attr('title', s)
                                        :wikitext(tostring(availablenode))
                                    :done()
                                :done()
                        else
                            sdnode
                                :tag('td')
                                    :attr('data-sort-value', s)
                                    :tag('span')
                                        :attr('title', s)
                                        :wikitext(tostring(availablenode))
                                    :done()
                                :done()
                        end
                    else
                        sdnode
                            :tag('td')
                                :attr('data-sort-value', 0)
                            :done()
                    end
                    
                    -- Transforming
                    sdnode
                        :tag('td')
                            :attr('data-sort-value', lib.ternary(type(t["lore"]) ~= "nil", 1, 0))
                            :wikitext(lib.ternary(type(t["lore"]) ~= "nil", tostring(availablenode), ""))
                        :done()
                    
                    -- Chromas
                    if (type(t["chromas"]) ~= "nil") then
                        sdnode
                            :tag('td')
                                :addClass('chroma-icon')
                                :attr('data-sort-value', 1)
                                :attr('data-character', championname)
                                :attr('data-skin', skinname)
                                :attr('data-chromas', 'all')
                                :wikitext(tostring(availablenode))
                            :done()
                    else
                        sdnode
                            :tag('td')
                                :attr('data-sort-value', 0)
                            :done()
                    end
                    
                    -- Add skin row to the table
                    sdtable
                        :newline()
                        :node(sdnode)
                end
            end
        end
        -- END
    
    sdtable:allDone()
    return tostring(sdtable)
end

function p._newestOrUpcomingSkins(frame, upcoming)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
    
    local skins = {}
    
    for cname,cdata in pairs(skinData) do
        for sname,sdata in pairs(cdata["skins"]) do
            if (upcoming and (sdata["availability"] or "Kommend") == "Kommend")
                or (not upcoming
                    and sdata["release"]
                    and (sdata["availability"] or "Kommend") ~= "Kommend")
            then
                table.insert(skins, {cname, sname, sdata["release"], sdata["cost"]})
            end
        end
    end
    
    local function comp(a, b)
        if a[3] == b[3] then
            return a[1] < b[1]
        end
        return (not a[3] and "9999-01-01" or a[3]) > (not b[3] and "9999-01-01" or b[3])
    end
    
    table.sort(skins, comp)
    
    local lang = mw.language.new("de")
    local count = upcoming and 14 or 7
    local s = ""
    
    for i,data in ipairs(skins) do
        if i <= count then
            local champ = data[1]
            local skin = data[2]
            local release = data[3]
            local cost = data[4]
           
            if skin == "Standard "..champ then
                count = count + 1
            else
                s = s .. "{{Skinporträt|" .. champ .. "|" .. skin
                if     cost == 10  then s = s .. "|gems="
                elseif cost == 100 then s = s .. "|prestige="
                else                    s = s .. "|rp="
                end
                s = s .. cost .. "|style=padding-bottom:5px;|date=" .. (release and (release ~= "N/A" and lang:formatDate("d. M Y", release) or release) or "") .. "}}"
            end
        end
    end
 
    return frame:preprocess(s)
end

function p.newestSkins(frame)
    return p._newestOrUpcomingSkins(frame, false)
end

function p.upcomingSkins(frame)
    return p._newestOrUpcomingSkins(frame, true)
end

function p.skinCatalog(frame)
    local dlib          = require("Dev:Datecalc")
    local lang          = mw.language.new( "de" )
    local championtable = {}
    local sdtable       = mw.html.create('table')
    
    sdtable
        :addClass('sortable article-table novpadding hcpadding sticky-header')
        :css('width','100%')
        :css('text-align','center')
        :css('font-size','12px')
        :newline()
        :tag('tr')
            :tag('th')
                :css('font-size','12px')
                :css('width','140x')
                :wikitext('Champion')
            :done()
            :newline()
            :tag('th')
                :css('font-size','12px')
                :attr('data-sort-type', "number")
                :wikitext('<div title="Im Shop oder durch Hextech-Crafting verfügbar.">Verfügbar</div>')
            :done()
            :newline()
            :tag('th')
                :css('font-size','12px')
                :attr('data-sort-type', "number")
                :wikitext('<div title="Durch limitierte Verkäufe oder durch Hextech-Crafting verfügbar.">Klassisch</div>')
            :done()
            :newline()
            :tag('th')
                :css('font-size','12px')
                :attr('data-sort-type', "number")
                :wikitext('<div title="Nur periodisch verfügbar oder durch besondere Ereignisse erhältlich.">Selten</div>')
            :done()
            :newline()
            :tag('th')
                :css('font-size','12px')
                :attr('data-sort-type', "number")
                :wikitext('Nicht Verfügbar')
            :done()
            :newline()
            :tag('th')
                :css('font-size','12px')
                :attr('data-sort-type', "number")
                :wikitext('Gesamt')
            :done()
            :newline()
            :tag('th')
                :css('font-size','12px')
                :attr('data-sort-type', "isoDate")
                :wikitext('Letzter Skin')
            :done()
            :newline()
            :tag('th')
                :css('font-size','12px')
                :attr('data-sort-type', "number")
                :wikitext('Tage her')
            :done()
            :newline()
        :done()
        :newline()
    
    for x in pairs(skinData) do
        table.insert(championtable, x)
    end
    table.sort(championtable)
    
    local availablecounttotal = 0
    local legacycounttotal    = 0
    local rarecounttotal      = 0
    local limitedcounttotal   = 0
    for _, championname in pairs(championtable) do
        local t                = skinData[championname]["skins"]
        local availablecount   = 0
	    local availablecircles = ""
        local legacycount      = 0
	    local legacycircles    = ""
        local rarecount        = 0
	    local rarecircles      = ""
        local limitedcount     = 0
	    local limitedcircles   = ""
        local result           = {"","",""}
        local sdnode           = mw.html.create('tr')
        local border           = ""
        local skintable        = {}
        
        for skinname in pairs(t) do
            if (
                championname        == "Akali"      and skinname == "Blutrote Akali" 
                or 
                championname        == "Amumu"      and skinname == "Chaospuppe-Amumu"
                or
                championname        == "Blitzcrank" and skinname == "Chaospuppe-Blitzcrank"
                or
                championname        == "Ryze"       and skinname == "Menschlicher Ryze"
                or
                skinname            == "Standard "..championname
                or
                t[skinname].release == "N/A"
            ) then
                -- skip
            else
                table.insert(skintable, skinname)
            end
        end
        table.sort(skintable, function(a, b) return t[a].release < t[b].release end)
        
        for i, skinname in pairs(skintable) do
            if t[skintable[i]].release == t[skintable[#skintable]].release then
                border = "border-radius:13px; width:26px; height:26px; box-shadow: 0 0 2px 2px #70fff2, 0 0 4px #111;"
            end
            
            if t[skinname].availability == "Verfügbar" then
                availablecount      = availablecount      + 1
                availablecounttotal = availablecounttotal + 1
                availablecircles = availablecircles .. '<li class="skin-icon" data-character="' .. championname ..'" data-skin="' .. skinname .. '" style="'.. border ..'">[[File:' .. FN.championcircle({championname, skinname}) .. '|26px|link=]]'
            end
            if t[skinname].availability == "Klassisch" then
                legacycount         = legacycount         + 1
                legacycounttotal    = legacycounttotal    + 1
                legacycircles = legacycircles .. '<li class="skin-icon" data-character="' .. championname ..'" data-skin="' .. skinname .. '" style="'.. border ..'">[[File:' .. FN.championcircle({championname, skinname}) .. '|26px|link=]]'
            end
            if t[skinname].availability == "Selten" then
                rarecount           = rarecount           + 1
                rarecounttotal      = rarecounttotal      + 1
                rarecircles = rarecircles .. '<li class="skin-icon" data-character="' .. championname ..'" data-skin="' .. skinname .. '" style="'.. border ..'">[[File:' .. FN.championcircle({championname, skinname}) .. '|26px|link=]]'
            end
            if t[skinname].availability == "Limitiert" then
                limitedcount        = limitedcount        + 1
                limitedcounttotal   = limitedcounttotal   + 1
                limitedcircles = limitedcircles .. '<li class="skin-icon" data-character="' .. championname ..'" data-skin="' .. skinname .. '" style="'.. border ..'">[[File:' .. FN.championcircle({championname, skinname}) .. '|26px|link=]]'
            end
            
            if t[skinname].release > result[2] then
                    result[1] = skinname
                    result[2] = t[skinname].release
                    result[3] = t[skinname].formatname
            end
        end
        
        sdnode
            :tag('td')
                :addClass('skin-icon')
                :attr('data-sort-value', championname)
                :attr('data-character', championname)
                :attr('data-skin', "Standard "..championname)
                :css('text-align', 'left')
                :wikitext('[[File:' .. FN.championcircle({championname, "Standard "..championname}) .. '|26px|link=' .. championname .. ']] ' .. championname)
            :done()
        
        -- Available skins
        sdnode
            :tag('td')
                :addClass('icon_list')
                :attr('data-sort-value', availablecount)
                :css('text-align', 'left')
                :css('background-color', '#0a1827')
                :wikitext(availablecircles)
            :done()
            
        -- Legacy skins
        sdnode
            :tag('td')
                :addClass('icon_list')
                :attr('data-sort-value', legacycount)
                :css('text-align', 'left')
                :wikitext(legacycircles)
            :done()
            
        -- Rare skins
        sdnode
            :tag('td')
                :addClass('icon_list')
                :attr('data-sort-value', rarecount)
                :css('text-align', 'left')
                :css('background-color', '#0a1827')
                :wikitext(rarecircles)
            :done()
         
        -- Limited skins
        sdnode
            :tag('td')
                :addClass('icon_list')
                :attr('data-sort-value', limitedcount)
                :css('text-align', 'left')
                :wikitext(limitedcircles)
            :done()   
           
        -- Total
            
        sdnode
            :tag('td')
                :css('text-align','right')
                :wikitext(availablecount + legacycount + rarecount + limitedcount)
            :done()

        -- Last Skin
        local y, m, d = result[2]:match("(%d+)-(%d+)-(%d+)")
        if y == nil or m == nil or d == nil then
            sdnode
                :tag('td')
                    :addClass('skin-icon')
                    :css('white-space', 'nowrap')
                    :attr('data-sort-value', result[2])
                    :attr('data-character', championname)
                    :attr('data-skin', result[1])
                    :wikitext(result[2])
                :done()
                :tag('td')
                    :css('text-align','right')
                    :wikitext(result[2])
                :done()
        else
            sdnode
                :tag('td')
                    :addClass('skin-icon')
                    :css('white-space', 'nowrap')
                    :attr('data-sort-value', result[2])
                    :attr('data-character', championname)
                    :attr('data-skin', result[1])
                    :wikitext(lang:formatDate('d-M-Y', result[2]))
                :done()
                :tag('td')
                    :css('text-align','right')
                    :wikitext(dlib.main{"diff", lang:formatDate('Y-m-d'), result[2]})
                :done()
        end
        
        -- Add skin row to the table
        sdtable
            :newline()
            :node(sdnode)
            
    end
    local sdfooter = mw.html.create('tr')
    sdfooter
        :tag('th')
            :css('font-size','12px')
            :wikitext('Gesamt')
        :done()
        :newline()
        :tag('th')
            :css('font-size','12px')
            :wikitext(availablecounttotal)
        :done()
        :newline()
        :tag('th')
            :css('font-size','12px')
            :wikitext(legacycounttotal)
        :done()
        :newline()
        :tag('th')
            :css('font-size','12px')
            :wikitext(rarecounttotal)
        :done()
        :newline()
        :tag('th')
            :css('font-size','12px')
            :wikitext(limitedcounttotal)
        :done()
        :newline()
        :tag('th')
            :css('font-size','12px')
            :wikitext(availablecounttotal + legacycounttotal + rarecounttotal + limitedcounttotal)
        :done()
        :newline()
        :tag('th')
        :done()
        :newline()
        :tag('th')
        :done()
        
    sdtable
        :newline()
        :node(sdfooter)

    return sdtable
end

function p.skintooltip(frame)
    local args; if frame.args == nil then args = lib.arguments(frame) else args = lib.arguments(frame.args) end
    
    local championname = args["champion"]
    local skinname     = args["skin"] or "Standard "..championname
    local variant      = args["variant"]
    
    local filename     = FN.skin{championname, skinname, variant}
    local t            = skinData[championname]["skins"][skinname]
    local newrecall    = t["newrecall"]
    local formatname   = t["formatname"]
    local cost         = t["cost"]
    local distribution = t["distribution"]
    local voiceactor   = p.getVoiceactor{championname, skinname}
    local splashartist = p.getSplashartist{championname, skinname}
    local set          = p.getSet{championname, skinname}
    local filter       = t["filter"]
    local newquotes    = t["newquotes"]
    local newvoice     = t["newvoice"]
    local neweffects   = t["neweffects"]
    --local newrecall    = t["newrecall"]
    local newanimations= t["newanimations"]
    local transforming = t["transforming"]
    local extras       = t["extras"]
    local chromas      = t["chromas"]
    local looteligible = t["looteligible"]
    local variantof    = p.getVariant{championname, skinname}
    
    local rpskins      = {[260]=true, [585]=true, [790]=true, [880]=true, [390]=true, [460]=true, [500]=true, [520]=true, [750]=true, [975]=true, [1350]=true, [1820]=true, [2775]=true, [3250]=true, [5000]=true}
    local s            = ''
    
    -- Hier stimmt was nicht mit der Anzahl <div> & </div>
    s = s .. '<div style="position:relative;">[[File:' .. filename .. '|700px]]'
        s = s .. '<div class="skin-features" style="padding: 15px 45px 15px 15px; position:absolute; bottom:16px; left:16px; max-width:576px; background-color:RGBA(10, 24, 39, 0.75);">'
            s = s .. '<div style="font-family:BeaufortLoL;">'
                s = s .. '<span style="font-size:16px; color:#f1e6d0; width:100%; text-transform:uppercase;">'
                    s = s .. lib.ternary(formatname ~= nil, formatname, skinname) .. lib.ternary(variant ~= nil, '&nbsp;<small>(' .. tostring(variant) .. ')</small>', '')
                s = s .. '</span>&nbsp;<span style="font-size:14px; color:#c9aa71; width:100%;">'
                
                    if cost == 10 then
                        s = s .. '&#x2011;&nbsp;' .. tostring(IL.basic{link = 'Edelsteine', text = cost, image = 'Edelstein Symbol.png', alttext = cost .. ' Edelsteine}', border = "false", labellink = "false"})
                    elseif cost == 100 then
                        s = s .. '&#x2011;&nbsp;' .. tostring(IL.basic{link = 'Prestige-Punkte', text = cost, image = 'Hextech Crafting Prestige Token.png', alttext = cost .. ' Prestige-Punkte}', border = "false", labellink = "false"})
                    elseif rpskins[cost] == true then
                        s = s .. '&#x2011;&nbsp;' .. tostring(IL.basic{link = 'Riot Points', text = cost, image = 'RpPoints.png', alttext = cost .. ' RP', border = "false", labellink = "false"})
                    elseif cost == 150000 then
                        s = s .. '&#x2011;&nbsp;' .. tostring(IL.basic{link = 'Blaue Essenz', text = cost, image = 'BE_Saison_8.png', alttext = cost .. ' BE', border = "false", labellink = "false"})
                    else
                        -- default: do nothing
                    end
                    
                s = s .. lib.ternary(distribution ~= nil, ' ' .. tostring(distribution), '') .. '</span>'
            s = s .. '</div>'
            s = s .. '<div style="font-size: 11px;">'
                s = s .. lib.ternary(voiceactor ~= nil, '<div style="display:inline-block; padding-right:1em;">[[File:Actor.png|20px|link=]]' .. tostring(voiceactor) .. '</div>', '')
                s = s .. lib.ternary(splashartist ~= nil, '<div style="display:inline-block; padding-right:1em;">[[File:Artist.png|20px|link=]]' .. tostring(splashartist) .. '</div>', '')
                s = s .. lib.ternary(set ~= nil, '<div style="display:inline-block; padding-right:1em;">[[File:Set piece.png|20px|link=]]' .. tostring(set) .. '</div>', '')
                s = s .. lib.ternary(looteligible ~= false, '<div style="display:inline-block; padding-right:1em;">[[File:Loot eligible.png|20px|link=]] Über Beute erhältlich</div>', '')
                s = s .. lib.ternary(looteligible == false, '<div style="display:inline-block; padding-right:1em;">[[File:Loot ineligible.png|20px|link=]] Nicht über Beute erhältlich </div>', '')
            
            if availability or filter or newquotes or newvoice or neweffects or newanimations or transforming or extras or chromas or looteligible then
                s = s .. '<div>'
                
                if availability == 'Limitiert' then
                    s = s .. '<div style="display:inline-grid; padding:0 1em; text-align:center;"><div>[[File:Limited skin.png|50px|link=]]</div><div>Limitierte Edition</div></div>'
                elseif availability == 'Legacy' then
                    s = s .. '<div style="display:inline-grid; padding:0 1em; text-align:center;"><div>[[File:Legacy skin.png|50px|link=]]</div><div>Klassisch</div></div>'
                end
                        
                s = s .. lib.ternary(filter ~= nil, '<div style="display:inline-grid; padding:0 1em; text-align:center;"><div>[[File:Voice filter.png|50px|link=]]</div><div>Sprachfilter</div></div>', '')
                s = s .. lib.ternary(newquotes ~= nil, '<div style="display:inline-grid; padding:0 1em; text-align:center;"><div>[[File:Additional quotes.png|50px|link=]]</div><div>Zusätzliche Sprüche</div></div>', '')
                s = s .. lib.ternary(newvoice ~= nil, '<div style="display:inline-grid; padding:0 1em; text-align:center;"><div>[[File:New voice.png|50px|link=]]</div><div>Neue Stimme</div></div>', '')
                s = s .. lib.ternary(neweffects ~= nil, '<div style="display:inline-grid; padding:0 1em; text-align:center;"><div>[[File:New effects.png|50px|link=]]</div><div>Neue SFX/VFX</div></div>', '')
                s = s .. lib.ternary(newanimations ~= nil, '<div style="display:inline-grid; padding:0 1em; text-align:center;"><div>[[File:New animations.png|50px|link=]]</div><div>Neue Animationen</div></div>', '')
                s = s .. lib.ternary(transforming ~= nil, '<div style="display:inline-grid; padding:0 1em; text-align:center;"><div>[[File:Transforming.png|50px|link=]]</div><div>Transformierend</div></div>', '')
                s = s .. lib.ternary(extras ~= nil, '<div style="display:inline-grid; padding:0 1em; text-align:center;"><div>[[File:Includes extras.png|50px|link=]]</div><div>Enthält Extras</div></div>', '')
                s = s .. lib.ternary(chromas ~= nil, '<div style="display:inline-grid; padding:0 1em; text-align:center;"><div>[[File:Chromas available.png|50px|link=]]</div><div>Chromas</div></div>', '')
                s = s .. '</div>'
            end
            s = s .. lib.ternary(variantof ~= nil, '<div>Dieser Skin ist eine Variante von ' .. tostring(IL.skin{champion = championname, skin = variantof, circle = "true", link = '*none*', text = variantof}) .. '.</div>', '')
        s = s .. '</div>'
    s = s .. '</div>'
    
    return s
end


function p.chromaList(frame)
    local lang = mw.language.new( "de" )
    local sdtable = mw.html.create('table')
    
    sdtable
        :addClass('sortable article-table nopadding sticky-header')
        :css('text-align','center')
        :newline()
        :tag('tr')
            :tag('th')
                :css('width','26px')
            :done()
            :newline()
            :tag('th')
                :wikitext('Skin')
            :done()
            :newline()
            :tag('th')
                :tag('span')
                    :attr('title','Verfügbarkeit')
                    :wikitext('[[File:Availability.png|40px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :tag('span')
                    :attr('title','Kosten')
                    :wikitext('[[File:RpPoints.png|30px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('div')
                    :attr('title','Shop-Chromas')
                    :css('width','30px')
                    :css('height','30px')
                    :css('padding','5px')
                    :wikitext('[[File:Chromaskins.png|30px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('div')
                    :attr('title','Paket-Chromas')
                    :css('width','30px')
                    :css('height','30px')
                    :css('padding','5px')
                    :wikitext('[[File:Legendary_Skin.png|30px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('div')
                    :attr('title','Partner-Chromas')
                    :css('width','30px')
                    :css('height','30px')
                    :css('padding','5px')
                    :wikitext('[[File:China Skin Tier 2.png|30px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('div')
                    :attr('title','Beute-Chromas')
                    :css('width','30px')
                    :css('height','30px')
                    :css('padding','5px')
                    :wikitext('[[File:China Skin Tier 1.png|30px|link=|]]')
                :done()
            :done()
            :newline()
            :tag('th')
                :css('width','40px')
                :tag('div')
                    :attr('title','Verteilte Chromas')
                    :css('width','30px')
                    :css('height','30px')
                    :css('padding','5px')
                    :wikitext('[[File:Limited skin.png|30px|link=|]]')
                :done()
            :done()
        :done()
        :newline()
        
        -- START
        local championtable = {}
        for x in pairs(skinData) do
            table.insert(championtable, x)
        end
        table.sort(championtable)
        
        local availablenode = mw.html.create('span')
        availablenode
            :css('color', 'green')
            :css('font-size', 'x-large')
            :css('vertical-align', 'text-top')
            :wikitext("✔")
            
        local legacynode = mw.html.create('span')
        legacynode
            :css('color', 'yellow')
            :css('font-size', 'x-large')
            :css('font-weight', '600')
            :css('vertical-align', 'text-top')
            :wikitext("‒")
            
        local limitednode = mw.html.create('span')
        limitednode
            :css('color', 'red')
            :css('font-size', 'x-large')
            :css('vertical-align', 'text-top')
            :wikitext("✘")
        local rarenode = mw.html.create('span')
        rarenode
            :css('color', 'orange')
            :css('font-size', 'x-large')
            :css('vertical-align', 'text-top')
            :wikitext("⭐")
        
        for _, championname in pairs(championtable) do
            local skintable  = {}
            for championname in pairs(skinData[championname]["skins"]) do
                table.insert(skintable, championname)
            end
            table.sort(skintable)
    
            for _, skinname in pairs(skintable) do
                if skinData[championname]["skins"][skinname]["chromas"] == nil then
                    -- skip
                else
                    local t = skinData[championname]["skins"][skinname]
                    local sdnode = mw.html.create('tr')
                    local temp = ""
                    
                    -- Skincircle
                    if (skinname == "Original") then
                        temp = "!" .. t["release"]
                    else 
                        temp = t["release"]
                    end
                    
                    sdnode
                        :tag('td')
                            :addClass('character-icon')
                            :attr('data-sort-value', championname .. temp)
                            :attr('data-character', championname)
                            :attr('data-skin', skinname)
                            :wikitext('[[File:' .. FN.championcircle({championname, skinname}) .. '|20px|link=' .. championname .. ']]')
                        :done()
                    
                    -- Skinname
                    sdnode
                        :tag('td')
                            :addClass('skin-icon')
                            :attr('data-character', championname)
                            :attr('data-skin', skinname)
                            :css('text-align', 'left')
                            :wikitext('[[' .. championname .. '|'..skinname ..']]')
                        :done()
                    
                    -- Availability
                    astring = '<span style="color: cornflowerblue;font-size: large;font-weight: 600;">⭘</span>'
                    if (t["availability"] == "Verfügbar") then
                        astring = tostring(availablenode)
                    end
                    if (t["availability"] == "Klassisch") then
                        astring = tostring(legacynode)
                    end
                    if (t["availability"] == "Limitiert") then
                        astring = tostring(limitednode)
                    end
                    if (t["availability"] == "Selten") then
                        astring = tostring(rarenode)
                    end
                    sdnode
                        :tag('td')
                            :tag('span')
                                :attr('title', t["availability"] or 'Kommend')
                                :wikitext(astring)
                        :done()
                    
                    -- Cost
                    local image = ""
                    if (tostring(t["cost"]) == "150000") then
                        image = "[[File:BE_Saison_8.png|20px|link=]]"
                    end 
                    if (tostring(t["cost"]) == "100") then
                        image = "[[File:Hextech Crafting Prestige token.png|20px|link=]]"
                    end
                    if (tostring(t["cost"]) == "10") then
                        image = "[[File:Edelstein Symbol.png|20px|link=]]"
                    end
                    sdnode
                        :tag('td')
                            :attr('data-sort-value', lib.ternary(tostring(t["cost"]) == "10" or tostring(t["cost"]) == "100", "2450", t["cost"]))
                            :tag('span')
                                :css('color', color.skin({t["cost"] .. ""}))
                                :wikitext(image .. t["cost"])
                            :done()
                        :done()
                    
                    -- Chromas
                    local availtable   = {}
                    local bundletable  = {}
                    local partnertable = {}
                    local loottable    = {}
                    local rewardtable  = {}
                    local futuretable  = {}
                    
                    for chromaname in pairs(t["chromas"]) do
                        if     t["chromas"][chromaname]["source"] == "Paket" then
                            table.insert(bundletable, chromaname)
                        elseif t["chromas"][chromaname]["source"] == "Partner" then
                            table.insert(partnertable, chromaname)
                        elseif t["chromas"][chromaname]["source"] == "Beute" then
                            table.insert(loottable, chromaname)
                        elseif t["chromas"][chromaname]["source"] == "Belohnung" then
                            table.insert(rewardtable, chromaname)
                        elseif t["chromas"][chromaname]["source"] == "Kommend" then
                            table.insert(futuretable, chromaname)
                        else
                            table.insert(availtable, chromaname)
                        end
                    end
                    
                    --normal
                    if (#availtable ~= 0) then
                        local s = table.concat(availtable, ",")
                        sdnode
                            :tag('td')
                                :addClass('chroma-icon')
                                :attr('data-sort-value', 1)
                                :attr('data-character', championname)
                                :attr('data-skin', skinname)
                                :attr('data-chromas', s)
                                :wikitext(tostring(availablenode))
                            :done()
                    else
                        sdnode
                            :tag('td')
                                :attr('data-sort-value', 0)
                            :done()
                    end
                    
                    --bundle
                    if (#bundletable ~= 0) then
                        local s = table.concat(bundletable, ",")
                        sdnode
                            :tag('td')
                                :addClass('chroma-icon')
                                :attr('data-sort-value', 1)
                                :attr('data-character', championname)
                                :attr('data-skin', skinname)
                                :attr('data-chromas', s)
                                :wikitext(tostring(availablenode))
                            :done()
                    else
                        sdnode
                            :tag('td')
                                :attr('data-sort-value', 0)
                            :done()
                    end
                    
                    --partner
                    if (#partnertable ~= 0) then
                        local s = table.concat(partnertable, ",")
                        sdnode
                            :tag('td')
                                :addClass('chroma-icon')
                                :attr('data-sort-value', 1)
                                :attr('data-character', championname)
                                :attr('data-skin', skinname)
                                :attr('data-chromas', s)
                                :wikitext(tostring(availablenode))
                            :done()
                    else
                        sdnode
                            :tag('td')
                                :attr('data-sort-value', 0)
                            :done()
                    end
                    
                    --loot
                    if (#loottable ~= 0) then
                        local s = table.concat(loottable, ",")
                        sdnode
                            :tag('td')
                                :addClass('chroma-icon')
                                :attr('data-sort-value', 1)
                                :attr('data-character', championname)
                                :attr('data-skin', skinname)
                                :attr('data-chromas', s)
                                :wikitext(tostring(availablenode))
                            :done()
                    else
                        sdnode
                            :tag('td')
                                :attr('data-sort-value', 0)
                            :done()
                    end
                    
                    --distributed
                    if (#rewardtable ~= 0) then
                        local s = table.concat(rewardtable, ",")
                        sdnode
                            :tag('td')
                                :addClass('chroma-icon')
                                :attr('data-sort-value', 1)
                                :attr('data-character', championname)
                                :attr('data-skin', skinname)
                                :attr('data-chromas', s)
                                :wikitext(tostring(availablenode))
                            :done()
                    else
                        sdnode
                            :tag('td')
                                :attr('data-sort-value', 0)
                            :done()
                    end
                    
                    -- Add skin row to the table
                    sdtable
                        :newline()
                        :node(sdnode)
                end
            end
        -- END
        end
    
    sdtable:allDone()
    return tostring(sdtable)
end

return p

-- </pre>
-- [[Category:Lua]]
Nutzung von Community-Inhalten gemäß CC-BY-SA, sofern nicht anders angegeben.