Difference between pages "Module:Format TemplateData" and "Card Trivia:Ancient Warriors - Graceful Zhou Gong"

From Yugipedia
(Difference between pages)
Jump to: navigation, search
m (1 revision imported: mass import/update of Wikipedia stuff)
 
(Restoring varnish cache from 2021-11-21 10:44:00+00:00)
 
Line 1: Line 1:
local TemplateData = { suite  = "TemplateData",
+
{{Navigation}}
                      serial = "2022-03-10",
 
                      item  = 46997995 }
 
--[==[
 
improve template:TemplateData
 
]==]
 
local Failsafe = TemplateData
 
  
 +
* This monster appears in the artwork of "[[Ancient Warriors Saga - Sun-Liu Alliance]]".
  
local Config = {
+
* This monster is based on [[wikipedia:Zhou Yu|Zhou Yu]] ([[wikipedia:Courtesy name|courtesy name]]: '''Gongjin'''), from the historical novel ''[[wikipedia:Romance of the Three Kingdoms|Romance of the Three Kingdoms]]'', a famed [[wikipedia:Eastern Wu|Wu]] general known for both his wit and beauty serving under [[wikipedia:Sun Quan|Sun Quan]]. He was known for his role during [[wikipedia:Battle of Red Cliffs|Battle of Red Cliffs]], the [[wikipedia:Battle of Jiangling (208)|Battle of Jiangling]] as well as for his many victories which served as the basis of the Wu Kingdom.
    -- multiple option names mapped into unique internal fields
+
** Additionally, this monster's swan motif and "Graceful" moniker might be a reference to Zhou Yu's popular moniker "Zhou the Beautiful Youth", as swans are symbols of beauty.
    basicCnf = { catProblem          = "strange",
 
                classMultiColumns  = "selMultClm",
 
                classNoNumTOC      = "suppressTOCnum",
 
                classTable          = "classTable",
 
                cssParWrap          = "cssTabWrap",
 
                cssParams          = "cssTable",
 
                docpageCreate      = "suffix",
 
                docpageDetect      = "subpage",
 
                helpBoolean        = "support4boolean",
 
                helpContent        = "support4content",
 
                helpDate            = "support4date",
 
                helpFile            = "support4wiki-file-name",
 
                helpFormat          = "supportFormat",
 
                helpLine            = "support4line",
 
                helpNumber          = "support4number",
 
                helpPage            = "support4wiki-page-name",
 
                helpString          = "support4string",
 
                helpTemplate        = "support4wiki-template-name",
 
                helpURL            = "support4url",
 
                helpUser            = "support4wiki-user-name",
 
                msgDescMiss        = "solo",
 
                tStylesTOCnum      = "stylesTOCnum",
 
                tStylesMultiColumns = "stylesMultClm" },
 
    classTable    = { "wikitable" },    -- classes for params table
 
    debugmultilang = "C0C0C0",
 
    loudly        = false,    -- show exported element, etc.
 
    solo          = false,    -- complaint on missing description
 
    strange        = false,    -- title of maintenance category
 
    cssTable      = false,    -- styles for params table
 
    cssTabWrap    = false,    -- styles for params table wrapper
 
    debug          = false,
 
    subpage        = false,    -- pattern to identify subpage
 
    suffix        = false,    -- subpage creation scheme
 
    suppressTOCnum = false,    -- class for TOC number suppression
 
    jsonDebug      = "json-code-lint"    -- class for jsonDebug tool
 
}
 
local Data = {
 
    div    = false,    -- <div class="mw-templatedata-doc-wrap">
 
    got    = false,    -- table, initial templatedata object
 
    heirs  = false,    -- table, params that are inherited
 
    jump    = false,    -- source position at end of "params"
 
    less    = false,    -- main description missing
 
    lasting = false,    -- old syntax encountered
 
    lazy    = false,    -- doc mode; do not generate effective <templatedata>
 
    leading = false,    -- show TOC
 
--  low    = false,    -- 1= mode
 
    order  = false,    -- parameter sequence
 
    params  = false,    -- table, exported parameters
 
    scream  = false,    -- error messages
 
    sibling = false,    -- TOC juxtaposed
 
    slang  = nil,      -- project/user language code
 
    slim    = false,    -- JSON reduced to plain
 
    source  = false,    -- JSON input
 
    strip  = false,    -- <templatedata> evaluation
 
    tag    = false,    -- table, exported root element
 
    title  = false,    -- page
 
    tree    = false    -- table, rewritten templatedata object
 
}
 
local Permit = {
 
    builder = { after          = "block",
 
                align          = "block",
 
                block          = "block",
 
                compressed      = "block",
 
                dense          = "block",
 
                grouped        = "inline",
 
                half            = "inline",
 
                indent          = "block",
 
                inline          = "inline",
 
                last            = "block",
 
                lead            = "block",
 
                newlines        = "*",
 
                spaced          = "inline" },
 
    colors  = { bg          = "FFFFFF",
 
                fg          = "000000",
 
                tableheadbg = "B3B7FF",
 
                required    = "EAF3FF",
 
                suggested  = "FFFFFF",
 
                optional    = "EAECF0",
 
                deprecated  = "FFCBCB" },
 
    params  = { aliases        = "table",
 
                autovalue      = "string",
 
                default        = "string table I18N nowiki",
 
                deprecated      = "boolean string I18N",
 
                description    = "string table I18N",
 
                example        = "string table I18N nowiki",
 
                label          = "string table I18N",
 
                inherits        = "string",
 
                required        = "boolean",
 
                style          = "string table",
 
                suggested      = "boolean",
 
                suggestedvalues = "string table number boolean",
 
                type            = "string" },
 
    root    = { description = "string table I18N",
 
                format      = "string",
 
                maps        = "table",
 
                params      = "table",
 
                paramOrder  = "table",
 
                sets        = "table" },
 
    search  = "[{,]%%s*(['\"])%s%%1%%s*:%%s*%%{",
 
    types  = { boolean                  = true,
 
                content                  = true,
 
                date                      = true,
 
                line                      = true,
 
                number                    = true,
 
                string                    = true,
 
                unknown                  = true,
 
                url                      = true,
 
                ["wiki-file-name"]        = true,
 
                ["wiki-page-name"]        = true,
 
                ["wiki-template-name"]    = true,
 
                ["wiki-user-name"]        = true,
 
                ["unbalanced-wikitext"]  = true,
 
                ["string/line"]          = "line",
 
                ["string/wiki-page-name"] = "wiki-page-name",
 
                ["string/wiki-user-name"] = "wiki-user-name" }
 
}
 
 
 
 
 
 
 
local function Fault( alert )
 
    -- Memorize error message
 
    -- Parameter:
 
    --    alert  -- string, error message
 
    if Data.scream then
 
        Data.scream = string.format( "%s *** %s", Data.scream, alert )
 
    else
 
        Data.scream = alert
 
    end
 
end -- Fault()
 
 
 
 
 
 
 
local function Fetch( ask, allow )
 
    -- Fetch module
 
    -- Parameter:
 
    --    ask    -- string, with name
 
    --                      "/global"
 
    --                      "JSONutil"
 
    --                      "Multilingual"
 
    --                      "Text"
 
    --                      "WLink"
 
    --    allow  -- true: no error if unavailable
 
    -- Returns table of module
 
    -- error: Module not available
 
    local sign = ask
 
    local r, stem
 
    if sign:sub( 1, 1 ) == "/" then
 
        sign = TemplateData.frame:getTitle() .. sign
 
    else
 
        stem = sign
 
        sign = "Module:" .. stem
 
    end
 
    if TemplateData.extern then
 
        r = TemplateData.extern[ sign ]
 
    else
 
        TemplateData.extern = { }
 
    end
 
    if not r then
 
        local lucky, g = pcall( require, sign )
 
        if type( g ) == "table" then
 
            if stem  and  type( g[ stem ] ) == "function" then
 
                r = g[ stem ]()
 
            else
 
                r = g
 
            end
 
            TemplateData.extern[ sign ] = r
 
        elseif not allow then
 
            error( string.format( "Fetch(%s) %s", sign, g ), 0 )
 
        end
 
    end
 
    return r
 
end -- Fetch()
 
 
 
 
 
 
 
local function Foreign()
 
    -- Guess human language
 
    -- Returns slang, or not
 
    if type( Data.slang ) == "nil" then
 
        local Multilingual = Fetch( "Multilingual", true )
 
        if Multilingual  and
 
          type( Multilingual.userLangCode ) == "function" then
 
            Data.slang = Multilingual.userLangCode()
 
        else
 
            Data.slang = mw.language.getContentLanguage():getCode()
 
                                                        :lower()
 
        end
 
    end
 
    if Data.slang  and
 
      mw.ustring.codepoint( Data.slang, 1, 1 ) > 122 then
 
        Data.slang = false
 
    end
 
    return Data.slang
 
end -- Foreign()
 
 
 
 
 
 
 
local function facet( ask, at )
 
    -- Find physical position of parameter definition in JSON
 
    -- Parameter:
 
    --    ask  -- string, parameter name
 
    --    at  -- number, physical position within definition
 
    -- Returns number, or nil
 
    local seek = string.format( Permit.search,
 
                                ask:gsub( "%%", "%%%%" )
 
                                  :gsub( "([%-.()+*?^$%[%]])",
 
                                          "%%%1" ) )
 
    local i, k, r, slice, source
 
    if not Data.jump then
 
        Data.jump = Data.source:find( "params", 2 )
 
        if Data.jump then
 
            Data.jump = Data.jump + 7
 
        else
 
            Data.jump = 1
 
        end
 
    end
 
    i, k = Data.source:find( seek,  at + Data.jump )
 
    while i  and  not r do
 
        source = Data.source:sub( k + 1 )
 
        slice  = source:match( "^%s*\"([^\"]+)\"s*:" )
 
        if not slice then
 
            slice = source:match( "^%s*'([^']+)'%s*:" )
 
        end
 
        if ( slice and Permit.params[ slice ] )  or
 
          source:match( "^%s*%}" ) then
 
            r = k
 
        else
 
            i, k = Data.source:find( seek,  k )
 
        end
 
    end    -- while i
 
    return r
 
end -- facet()
 
 
 
 
 
 
 
local function facilities( apply )
 
    -- Retrieve details of suggestedvalues
 
    -- Parameter:
 
    --    apply  -- table, with plain or enhanced values
 
    --              .suggestedvalues  -- table|string|number, or more
 
    -- Returns
 
    --    1  -- table, with suggestedvalues
 
    --    2  -- table, with CSS map, or not
 
    --    3  -- string, with class, or not
 
    --    4  -- string, with templatestyles, or not
 
    local elements = apply.suggestedvalues
 
    local s        = type( elements )
 
    local r1, r2, r3, r4
 
    if s == "table" then
 
        local values = elements.values
 
        if type( values ) == "table" then
 
            r1 = values
 
            if type( elements.scroll ) == "string" then
 
                r2 = r2  or  { }
 
                r2.height  = apply.scroll
 
                r2.overflow = "auto"
 
            end
 
            if type( elements.minwidth ) == "string" then
 
                local s = type( elements.maxcolumns )
 
                r2 = r2  or  { }
 
                r2["column-width"] = elements.minwidth
 
                if s == "string"  or
 
                  s == "number" then
 
                    s = tostring( elements.maxcolumns )
 
                    r2["column-count"] = s
 
                end
 
                if type( Config.selMultClm ) == "string" then
 
                    r3 = Config.selMultClm
 
                end
 
                if type( Config.stylesMultClm ) == "string" then
 
                    local src = Config.stylesMultClm .. "/styles.css"
 
                    r4 = TemplateData.frame
 
                                    :extensionTag( "templatestyles",
 
                                                    nil,
 
                                                    { src = src } )
 
                end
 
            end
 
        elseif elements  and  elements ~= "" then
 
            r1 = elements
 
        end
 
    elseif s == "string" then
 
        s = mw.text.trim( about )
 
        if s ~= "" then
 
            r1 = { }
 
            table.insert( r1,
 
                          { code = s } )
 
        end
 
    elseif s == "number" then
 
        r1 = { }
 
        table.insert( r1,
 
                      { code = tostring( elements ) } )
 
    end
 
    return r1, r2, r3, r4
 
end -- facilities()
 
 
 
 
 
 
 
local function factory( adapt )
 
    -- Retrieve localized text from system message
 
    -- Parameter:
 
    --    adapt  -- string, message ID after "templatedata-"
 
    -- Returns string, with localized text
 
    local o = mw.message.new( "templatedata-" .. adapt )
 
    if Foreign() then
 
        o:inLanguage( Data.slang )
 
    end
 
    return o:plain()
 
end -- factory()
 
 
 
 
 
 
 
local function faculty( adjust )
 
    -- Test template arg for boolean
 
    --    adjust  -- string or nil
 
    -- Returns boolean
 
    local s = type( adjust )
 
    local r
 
    if s == "string" then
 
        r = mw.text.trim( adjust )
 
        r = ( r ~= ""  and  r ~= "0" )
 
    elseif s == "boolean" then
 
        r = adjust
 
    else
 
        r = false
 
    end
 
    return r
 
end -- faculty()
 
 
 
 
 
 
 
local function failures()
 
    -- Retrieve error collection and category
 
    -- Returns string
 
    local r
 
    if Data.scream then
 
        local e = mw.html.create( "span" )
 
                        :addClass( "error" )
 
                        :wikitext( Data.scream )
 
        r = tostring( e )
 
        mw.addWarning( "'''TemplateData'''<br />" .. Data.scream )
 
        if Config.strange then
 
            r = string.format( "%s[[category:%s]]",
 
                              r,
 
                              Config.strange )
 
        end
 
    else
 
        r = ""
 
    end
 
    return r
 
end -- failures()
 
 
 
 
 
 
 
local function fair( adjust )
 
    -- Reduce text to one line of plain text, or noexport wikitext blocks
 
    --    adjust  -- string
 
    -- Returns string, with adjusted text
 
    local f    = function ( a )
 
                    return a:gsub( "%s*\n%s*", " " )
 
                            :gsub( "%s%s+", " " )
 
                end
 
    local tags = { { start = "<noexport>",
 
                    stop  = "</noexport>" },
 
                  { start = "<exportonly>",
 
                    stop  = "</exportonly>",
 
                    l    = false }
 
                }
 
    local r = adjust
 
    local i, j, k, s, tag
 
    for m = 1, 2 do
 
        tag = tags[ m ]
 
        if r:find( tag.start, 1, true ) then
 
            s    = r
 
            r    = ""
 
            i    = 1
 
            tag.l = true
 
            j, k  = s:find( tag.start, i, true )
 
            while j do
 
                if j > 1 then
 
                    r = r .. f( s:sub( i,  j - 1 ) )
 
                end
 
                i    = k + 1
 
                j, k = s:find( tag.stop, i, true )
 
                if j then
 
                    if m == 1 then
 
                        r = r .. s:sub( i,  j - 1 )
 
                    end
 
                    i    = k + 1
 
                    j, k = s:find( tag.start, i, true )
 
                else
 
                    Fault( "missing " .. tag.stop )
 
                end
 
            end    -- while j
 
            r = r .. s:sub( i )
 
        elseif m == 1 then
 
            r = f( r )
 
        end
 
    end -- for m
 
    if tags[ 2 ].l then
 
        r = r:gsub( "<exportonly>.*</exportonly>", "" )
 
    end
 
    return r
 
end -- fair()
 
 
 
 
 
 
 
local function fancy( advance, alert )
 
    -- Present JSON source
 
    -- Parameter:
 
    --    advance  -- true, for nice
 
    --    alert    -- true, for visible
 
    -- Returns string
 
    local r
 
    if Data.source then
 
        local support = Config.jsonDebug
 
        local css
 
        if advance then
 
            css = { height = "6em",
 
                    resize = "vertical" }
 
            r  = { [ 1 ] = "syntaxhighlight",
 
                    [ 2 ] = Data.source,
 
                    lang  = "json",
 
                    style = table.concat( css, ";" ) }
 
            if alert then
 
                r.class( support )
 
            end
 
            r = TemplateData.frame:callParserFunction( "#tag", r )
 
        else
 
            css = { [ "font-size" ]  = "77%",
 
                    [ "line-height" ] = "1.35" }
 
            if alert then
 
                css.resize = "vertical"
 
            else
 
                css.display = "none"
 
            end
 
            r = mw.html.create( "pre" )
 
                      :addClass( support )
 
                      :css( css )
 
                      :wikitext( mw.text.encode( Data.source ) )
 
            r = tostring( r )
 
        end
 
        r = "\n".. r
 
    else
 
        r = ""
 
    end
 
    return r
 
end -- fancy()
 
 
 
 
 
 
 
local function faraway( alternatives )
 
    -- Retrieve best language version from multilingual text
 
    -- Parameter:
 
    --    alternatives  -- table, to be evaluated
 
    -- Returns
 
    --    1  -- string, with best match
 
    --    2  -- table of other versions, if any
 
    local n = 0
 
    local variants = { }
 
    local r1, r2
 
    for k, v in pairs( alternatives ) do
 
        if type( v ) == "string" then
 
            v = mw.text.trim( v )
 
            if v ~= ""  and  type( k ) == "string" then
 
                k = k:lower()
 
                variants[ k ] = v
 
                n            = n + 1
 
            end
 
        end
 
    end -- for k, v
 
    if n > 0 then
 
        local Multilingual = Fetch( "Multilingual", true )
 
        if Multilingual  and
 
          type( Multilingual.i18n ) == "function" then
 
            local show, slang = Multilingual.i18n( variants )
 
            if show then
 
                r1 = show
 
                variants[ slang ] = nil
 
                r2 = variants
 
            end
 
        end
 
        if not r1 then
 
            Foreign()
 
            for k, v in pairs( variants ) do
 
                if n == 1 then
 
                    r1 = v
 
                elseif Data.slang == k then
 
                    variants[ k ] = nil
 
                    r1 = v
 
                    r2 = variants
 
                end
 
            end -- for k, v
 
        end
 
        if r2 and Multilingual then
 
            for k, v in pairs( r2 ) do
 
                if v  and  not Multilingual.isLang( k, true ) then
 
                    Fault( string.format( "%s <code>lang=%s</code>",
 
                                          "Invalid",
 
                                          k ) )
 
                end
 
            end -- for k, v
 
        end
 
    end
 
    return r1, r2
 
end -- faraway()
 
 
 
 
 
 
 
local function fashioned( about, asked, assign )
 
    -- Create description head
 
    -- Parameter:
 
    --    about  -- table, supposed to contain description
 
    --    asked  -- true, if mandatory description
 
    --    assign  -- <block>, if to be equipped
 
    -- Returns <block>, with head, or nil
 
    local para = assign or mw.html.create( "div" )
 
    local plus, r
 
    if about and about.description then
 
        if type( about.description ) == "string" then
 
            para:wikitext( about.description )
 
        else
 
            para:wikitext( about.description[ 1 ] )
 
            plus = mw.html.create( "ul" )
 
            plus:css( "text-align", "left" )
 
            for k, v in pairs( about.description[ 2 ] ) do
 
                plus:node( mw.html.create( "li" )
 
                                  :node( mw.html.create( "code" )
 
                                                :wikitext( k ) )
 
                                  :node( mw.html.create( "br" ) )
 
                                  :wikitext( fair( v ) ) )
 
            end -- for k, v
 
            if Config.loudly then
 
                plus = mw.html.create( "div" )
 
                              :css( "background-color",
 
                                    "#" .. Config.debugmultilang )
 
                              :node( plus )
 
            else
 
                plus:addClass( "templatedata-maintain" )
 
                    :css( "display", "none" )
 
            end
 
        end
 
    elseif Config.solo and asked then
 
        para:addClass( "error" )
 
            :wikitext( Config.solo )
 
        Data.less = true
 
    else
 
        para = false
 
    end
 
    if para then
 
        if plus then
 
            r = mw.html.create( "div" )
 
                      :node( para )
 
                      :node( plus )
 
        else
 
            r = para
 
        end
 
    end
 
    return r
 
end -- fashioned()
 
 
 
 
 
 
 
local function fatten( access )
 
    -- Create table row for sub-headline
 
    -- Parameter:
 
    --    access  -- string, with name
 
    -- Returns <tr>
 
    local param    = Data.tree.params[ access ]
 
    local sub, sort = access:match( "(=+)%s*(%S.*)$" )
 
    local headline  = mw.html.create( string.format( "h%d", #sub ) )
 
    local r        = mw.html.create( "tr" )
 
    local td        = mw.html.create( "td" )
 
                            :attr( "colspan", "5" )
 
                            :attr( "data-sort-value",  "!" .. sort )
 
    local s
 
    if param.style then
 
        s = type( param.style )
 
        if s == "table" then
 
            td:css( param.style )
 
        elseif s == "string" then
 
            td:cssText( param.style )
 
        end
 
    end
 
    s = fashioned( param, false, headline )
 
    if s then
 
        headline = s
 
    else
 
        headline:wikitext( sort )
 
    end
 
    td:node( headline )
 
    r:node( td )
 
    return r
 
end -- fatten()
 
 
 
 
 
 
 
local function fathers()
 
    -- Merge params with inherited values
 
    local n = 0
 
    local p = Data.params
 
    local t = Data.tree.params
 
    local p2, t2
 
    for k, v in pairs( Data.heirs ) do
 
        n = n + 1
 
    end -- for k, v
 
    for i = 1, n do
 
        if Data.heirs then
 
            for k, v in pairs( Data.heirs ) do
 
                if v  and  not Data.heirs[ v ] then
 
                    n              = n - 1
 
                    t[ k ].inherits = nil
 
                    Data.heirs[ k ] = nil
 
                    p2              = { }
 
                    t2              = { }
 
                    if p[ v ] then
 
                        for k2, v2 in pairs( p[ v ] ) do
 
                            p2[ k2 ] = v2
 
                        end -- for k2, v2
 
                        if p[ k ] then
 
                            for k2, v2 in pairs( p[ k ] ) do
 
                                if type( v2 ) ~= "nil" then
 
                                    p2[ k2 ] = v2
 
                                end
 
                            end -- for k2, v2
 
                        end
 
                        p[ k ] = p2
 
                        for k2, v2 in pairs( t[ v ] ) do
 
                            t2[ k2 ] = v2
 
                        end -- for k2, v2
 
                        for k2, v2 in pairs( t[ k ] ) do
 
                            if type( v2 ) ~= "nil" then
 
                                t2[ k2 ] = v2
 
                            end
 
                        end -- for k2, v2
 
                        t[ k ] = t2
 
                    else
 
                        Fault( "No params[] inherits " .. v )
 
                    end
 
                end
 
            end -- for k, v
 
        end
 
    end -- i = 1, n
 
    if n > 0 then
 
        local s
 
        for k, v in pairs( Data.heirs ) do
 
            if v then
 
                if s then
 
                    s = string.format( "%s &#124; %s", s, k )
 
                else
 
                    s = "Circular inherits: " .. k
 
                end
 
            end
 
        end -- for k, v
 
        Fault( s )
 
    end
 
end -- fathers()
 
 
 
 
 
 
 
local function favorize()
 
    -- Local customization issues
 
    local boole  = { ["font-size"] = "125%" }
 
    local l, cx = pcall( mw.loadData,
 
                        TemplateData.frame:getTitle() .. "/config" )
 
    local scripting, style
 
    TemplateData.ltr = not mw.language.getContentLanguage():isRTL()
 
    if TemplateData.ltr then
 
        scripting = "left"
 
    else
 
        scripting = "right"
 
    end
 
    boole[ "margin-" .. scripting ] = "3em"
 
    Permit.boole = { [false] = { css  = boole,
 
                                lead = true,
 
                                show = "&#x2610;" },
 
                    [true]  = { css  = boole,
 
                                lead = true,
 
                                show = "&#x2611;" } }
 
    Permit.css  = { }
 
    for k, v in pairs( Permit.colors ) do
 
        if k == "tableheadbg" then
 
            k = "tablehead"
 
        end
 
        if k == "fg" then
 
            style = "color"
 
        else
 
            style = "background-color"
 
        end
 
        Permit.css[ k ] = { }
 
        Permit.css[ k ][ style ] = "#" .. v
 
    end -- for k, v
 
    if type( cx ) == "table" then
 
        local c, s
 
        if type( cx.permit ) == "table" then
 
            if type( cx.permit.boole ) == "table" then
 
                if type( cx.permit.boole[ true ] ) == "table" then
 
                    Permit.boole[ false ]  = cx.permit.boole[ false ]
 
                end
 
                if type( cx.permit.boole[ true ] ) == "table" then
 
                    Permit.boole[ true ]  = cx.permit.boole[ true ]
 
                end
 
            end
 
            if type( cx.permit.css ) == "table" then
 
                for k, v in pairs( cx.permit.css ) do
 
                    if type( v ) == "table" then
 
                        Permit.css[ k ] = v
 
                    end
 
                end -- for k, v
 
            end
 
        end
 
        for k, v in pairs( Config.basicCnf ) do
 
            s = type( cx[ k ] )
 
            if s == "string"  or  s == "table" then
 
                Config[ v ] = cx[ k ]
 
            end
 
        end -- for k, v
 
    end
 
    if type( Config.subpage ) ~= "string"  or
 
      type( Config.suffix ) ~= "string" then
 
        local got = mw.message.new( "templatedata-doc-subpage" )
 
        local suffix
 
        if got:isDisabled() then
 
            suffix = "doc"
 
        else
 
            suffix = got:plain()
 
        end
 
        if type( Config.subpage ) ~= "string" then
 
            Config.subpage = string.format( "/%s$", suffix )
 
        end
 
        if type( Config.suffix ) ~= "string" then
 
            Config.suffix = string.format( "%%s/%s", suffix )
 
        end
 
    end
 
end -- favorize()
 
 
 
 
 
 
 
local function feasible( all, at, about )
 
    -- Deal with suggestedvalues within parameter
 
    -- Parameter:
 
    --    all    -- parameter details
 
    --              .default
 
    --              .type
 
    --    at    -- string, with parameter name
 
    --    about  -- suggestedvalues  -- table,
 
    --                                  value and possibly description
 
    --                                  table may have elements:
 
    --                                    .code    -- mandatory
 
    --                                    .label  -- table|string
 
    --                                    .support -- table|string
 
    --                                    .icon    -- string
 
    --                                    .class  -- table|string
 
    --                                    .css    -- table
 
    --                                    .style  -- string
 
    --                                    .less    -- true: suppress code
 
    -- Returns
 
    --    1: mw.html object <ul>
 
    --    2: sequence table with values, or nil
 
    local h = { }
 
    local e, r1, r2, s, v
 
    if #about > 0 then
 
        for i = 1, #about do
 
            e = about[ i ]
 
            s = type( e )
 
            if s == "table" then
 
                if type( e.code ) == "string" then
 
                    s = mw.text.trim( e.code )
 
                    if s == "" then
 
                        e = nil
 
                    else
 
                        e.code = s
 
                    end
 
                else
 
                    e = nil
 
                    s = string.format( "params.%s.%s[%d] %s",
 
                                      at,
 
                                      "suggestedvalues",
 
                                      i,
 
                                      "MISSING 'code:'" )
 
                end
 
            elseif s == "string" then
 
                s = mw.text.trim( e )
 
                if s == "" then
 
                    e = nil
 
                    s = string.format( "params.%s.%s[%d] EMPTY",
 
                                      at, "suggestedvalues", i )
 
                    Fault( s )
 
                else
 
                    e = { code = s }
 
                end
 
            elseif s == "number" then
 
                e = { code = tostring( e ) }
 
            else
 
                s = string.format( "params.%s.%s[%d] INVALID",
 
                                  at, "suggestedvalues", i )
 
                Fault( s )
 
                e = false
 
            end
 
            if e then
 
                v = v  or  { }
 
                table.insert( v, e )
 
                if h[ e.code ] then
 
                    s = string.format( "params.%s.%s REPEATED %s",
 
                                      at,
 
                                      "suggestedvalues",
 
                                      e.code )
 
                    Fault( s )
 
                else
 
                    h[ e.code ] = true
 
                end
 
            end
 
        end -- for i
 
    else
 
        Fault( string.format( "params.%s.suggestedvalues %s",
 
                              at, "NOT AN ARRAY" ) )
 
    end
 
    if v then
 
        local code, d, k, less, story, swift, t, u
 
        r1 = mw.html.create( "ul" )
 
        r2 = { }
 
        for i = 1, #v do
 
            u = mw.html.create( "li" )
 
            e = v[ i ]
 
            table.insert( r2, e.code )
 
            story = false
 
            less  = ( e.less == true )
 
            if not less then
 
                swift = e.code
 
                if e.support then
 
                    local scream, support
 
                    s = type( e.support )
 
                    if s == "string" then
 
                        support = e.support
 
                    elseif s == "table" then
 
                        support = faraway( e.support )
 
                    else
 
                        scream = "INVALID"
 
                    end
 
                    if support then
 
                        s = mw.text.trim( support )
 
                        if s == "" then
 
                            scream = "EMPTY"
 
                        elseif s:find( "[%[%]|%<%>]" ) then
 
                            scream = "BAD PAGE"
 
                        else
 
                            support = s
 
                        end
 
                    end
 
                    if scream then
 
                        s = string.format( "params.%s.%s[%d].support %s",
 
                                          at,
 
                                          "suggestedvalues",
 
                                          i,
 
                                          scream )
 
                        Fault( s )
 
                    else
 
                        swift = string.format( "[[:%s|%s]]",
 
                                              support, swift )
 
                    end
 
                end
 
                if all.type:sub( 1, 5 ) == "wiki-"  and
 
                  swift == e.code then
 
                    local rooms = { file = 6,
 
                                    temp = 10,
 
                                    user = 2 }
 
                    local ns = rooms[ all.type:sub( 6, 9 ) ]  or  0
 
                    t = mw.title.makeTitle( ns, swift )
 
                    if t and t.exists then
 
                        swift = string.format( "[[:%s|%s]]",
 
                                              t.prefixedText, swift )
 
                    end
 
                end
 
                if e.code == all.default then
 
                    k = 800
 
                else
 
                    k = 300
 
                end
 
                code = mw.html.create( "code" )
 
                              :css( "font-weight", tostring( k ) )
 
                              :css( "white-space", "nowrap" )
 
                              :wikitext( swift )
 
                u:node( code )
 
            end
 
            if e.class then
 
                s = type( e.class )
 
                if s == "string" then
 
                    u:addClass( e.class )
 
                elseif s == "table" then
 
                    for k, s in pairs( e.class ) do
 
                        u:addClass( s )
 
                    end -- for k, s
 
                else
 
                    s = string.format( "params.%s.%s[%d].class INVALID",
 
                                      at, "suggestedvalues", i )
 
                    Fault( s )
 
                end
 
            end
 
            if e.css then
 
                if type( e.css ) == "table" then
 
                    u:css( e.css )
 
                else
 
                    s = string.format( "params.%s.%s[%d].css INVALID",
 
                                      at, "suggestedvalues", i )
 
                    Fault( s )
 
                end
 
            end
 
            if e.style then
 
                if type( e.style ) == "string" then
 
                    u:cssText( e.style )
 
                else
 
                    s = string.format( "params.%s.%s[%d].style INVALID",
 
                                      at, "suggestedvalues", i )
 
                    Fault( s )
 
                end
 
            end
 
            if all.type == "wiki-file-name"  and  not e.icon then
 
                e.icon = e.code
 
            end
 
            if e.label then
 
                s = type( e.label )
 
                if s == "string" then
 
                    s = mw.text.trim( e.label )
 
                    if s == "" then
 
                        s = string.format( "params.%s.%s[%d].label %s",
 
                                          at,
 
                                          "suggestedvalues",
 
                                          i,
 
                                          "EMPTY" )
 
                        Fault( s )
 
                    else
 
                        story = s
 
                    end
 
                elseif s == "table" then
 
                    story = faraway( e.label )
 
                else
 
                    s = string.format( "params.%s.%s[%d].label INVALID",
 
                                      at, "suggestedvalues", i )
 
                    Fault( s )
 
                end
 
            end
 
            s = false
 
            if type( e.icon ) == "string" then
 
                t = mw.title.makeTitle( 6, e.icon )
 
                if t and t.file.exists then
 
                    local g = mw.html.create( "span" )
 
                    s = string.format( "[[%s|16px]]", t.prefixedText )
 
                    g:attr( "role", "presentation" )
 
                    :wikitext( s )
 
                    s = tostring( g )
 
                end
 
            end
 
            if not s  and  not less  and  e.label then
 
                s = mw.ustring.char( 0x2013 )
 
            end
 
            if s then
 
                d = mw.html.create( "span" )
 
                          :wikitext( s )
 
                if TemplateData.ltr then
 
                    if not less then
 
                        d:css( "margin-left", "0.5em" )
 
                    end
 
                    if story then
 
                        d:css( "margin-right", "0.5em" )
 
                    end
 
                else
 
                    if not less then
 
                        d:css( "margin-right", "0.5em" )
 
                    end
 
                    if story then
 
                        d:css( "margin-left", "0.5em" )
 
                    end
 
                end
 
                u:node( d )
 
            end
 
            if story then
 
                u:wikitext( story )
 
            end
 
            r1:newline()
 
              :node( u )
 
        end -- for i
 
    end
 
    if not r1  and  v ~= false then
 
        Fault( string.format( "params.%s.suggestedvalues INVALID", at ) )
 
        r1 = mw.html.create( "code" )
 
                    :addClass( "error" )
 
                    :wikitext( "INVALID" )
 
    end
 
    return r1, r2
 
end -- feasible()
 
 
 
 
 
 
 
local function feat()
 
    -- Check and store parameter sequence
 
    if Data.source then
 
        local i = 0
 
        local s
 
        for k, v in pairs( Data.tree.params ) do
 
            if i == 0 then
 
                Data.order = { }
 
                i = 1
 
                s = k
 
            else
 
                i = 2
 
                break -- for k, v
 
            end
 
        end -- for k, v
 
        if i > 1 then
 
            local pointers = { }
 
            local points  = { }
 
            local given    = { }
 
            for k, v in pairs( Data.tree.params ) do
 
                i = facet( k, 1 )
 
                if type( v ) == "table" then
 
                    if type( v.label ) == "string" then
 
                        s = mw.text.trim( v.label )
 
                        if s == "" then
 
                            s = k
 
                        end
 
                    else
 
                        s = k
 
                    end
 
                    if given[ s ] then
 
                        if given[ s ] == 1 then
 
                            local scream = "Parameter label '%s' detected multiple times"
 
                            Fault( string.format( scream, s ) )
 
                            given[ s ] = 2
 
                        end
 
                    else
 
                        given[ s ] = 1
 
                    end
 
                end
 
                if i then
 
                    table.insert( points, i )
 
                    pointers[ i ] = k
 
                    i = facet( k, i )
 
                    if i then
 
                        s = "Parameter '%s' detected twice"
 
                        Fault( string.format( s, k ) )
 
                    end
 
                else
 
                    s = "Parameter '%s' not detected"
 
                    Fault( string.format( s, k ) )
 
                end
 
            end -- for k, v
 
            table.sort( points )
 
            for i = 1, #points do
 
                table.insert( Data.order,  pointers[ points[ i ] ] )
 
            end -- i = 1, #points
 
        elseif s then
 
            table.insert( Data.order, s )
 
        end
 
    end
 
end -- feat()
 
 
 
 
 
 
 
local function feature( access )
 
    -- Create table row for parameter, check and display violations
 
    -- Parameter:
 
    --    access  -- string, with name
 
    -- Returns <tr>
 
    local mode, s, status
 
    local fine    = function ( a )
 
                        s = mw.text.trim( a )
 
                        return a == s  and
 
                              a ~= ""  and
 
                              not a:find( "%|=\n" )  and
 
                              not a:find( "%s%s" )
 
                    end
 
    local begin  = mw.html.create( "td" )
 
    local code    = mw.html.create( "code" )
 
    local desc    = mw.html.create( "td" )
 
    local eager  = mw.html.create( "td" )
 
    local legal  = true
 
    local param  = Data.tree.params[ access ]
 
    local ranking = { "required", "suggested", "optional", "deprecated" }
 
    local r      = mw.html.create( "tr" )
 
    local styles  = "mw-templatedata-doc-param-"
 
    local sort, typed
 
 
 
    for k, v in pairs( param ) do
 
        if v == "" then
 
            param[ k ] = false
 
        end
 
    end -- for k, v
 
 
 
    -- label
 
    sort = param.label or access
 
    if sort:match( "^%d+$" ) then
 
        begin:attr( "data-sort-value",
 
                    string.format( "%05d", tonumber( sort ) ) )
 
    end
 
    begin:css( "font-weight", "bold" )
 
        :wikitext( sort )
 
 
 
    -- name and aliases
 
    code:css( "font-size", "92%" )
 
        :css( "white-space", "nowrap" )
 
        :wikitext( access )
 
    if not fine( access ) then
 
        code:addClass( "error" )
 
        Fault( string.format( "Bad ID params.<code>%s</code>", access ) )
 
        legal = false
 
        begin:attr( "data-sort-value",  " " .. sort )
 
    end
 
    code = mw.html.create( "td" )
 
                  :addClass( styles .. "name" )
 
                  :node( code )
 
    if access:match( "^%d+$" ) then
 
        code:attr( "data-sort-value",
 
                  string.format( "%05d", tonumber( access ) ) )
 
    end
 
    if type( param.aliases ) == "table" then
 
        local lapsus, syn
 
        for k, v in pairs( param.aliases ) do
 
            code:tag( "br" )
 
            if type( v ) == "string" then
 
                if not fine( v ) then
 
                    lapsus = true
 
                    code:node( mw.html.create( "span" )
 
                                      :addClass( "error" )
 
                                      :css( "font-style", "italic" )
 
                                      :wikitext( "string" ) )
 
                        :wikitext( s )
 
                else
 
                    syn = mw.html.create( "span" )
 
                                :addClass( styles .. "alias" )
 
                                :css( "white-space", "nowrap" )
 
                                :wikitext( s )
 
                    code:node( syn )
 
                end
 
            else
 
                lapsus = true
 
                code:node( mw.html.create( "code" )
 
                                  :addClass( "error" )
 
                                  :wikitext( type( v ) ) )
 
            end
 
        end -- for k, v
 
        if lapsus then
 
            s = string.format( "params.<code>%s</code>.aliases", access )
 
            Fault(  factory( "invalid-value" ):gsub( "$1", s )  )
 
            legal = false
 
        end
 
    end
 
 
 
    -- description etc.
 
    s = fashioned( param )
 
    if s then
 
        desc:node( s )
 
    end
 
    if param.style then
 
        s = type( param.style )
 
        if s == "table" then
 
            desc:css( param.style )
 
        elseif s == "string" then
 
            desc:cssText( param.style )
 
        end
 
    end
 
    if param.suggestedvalues or
 
      param.default or
 
      param.example or
 
      param.autovalue then
 
        local details = { "suggestedvalues",
 
                          "default",
 
                          "example",
 
                          "autovalue" }
 
        local dl      = mw.html.create( "dl" )
 
        local dd, section, show
 
        for i = 1, #details do
 
            s    = details[ i ]
 
            show = param[ s ]
 
            if show then
 
                dd      = mw.html.create( "dd" )
 
                section = factory( "doc-param-" .. s )
 
                if param.type == "boolean"  and
 
                  ( show == "0" or show == "1" ) then
 
                    local boole = Permit.boole[ ( show == "1" ) ]
 
                    if boole.lead == true then
 
                        dd:node( mw.html.create( "code" )
 
                                        :wikitext( show ) )
 
                          :wikitext( " " )
 
                    end
 
                    if type( boole.show ) == "string" then
 
                        local v = mw.html.create( "span" )
 
                                        :attr( "aria-hidden", "true" )
 
                                        :wikitext( boole.show )
 
                        if boole.css then
 
                            v:css( boole.css )
 
                        end
 
                        dd:node( v )
 
                    end
 
                    if type( boole.suffix ) == "string" then
 
                        dd:wikitext( boole.suffix )
 
                    end
 
                    if boole.lead == false then
 
                        dd:wikitext( " " )
 
                          :node( mw.html.create( "code" )
 
                                        :wikitext( show ) )
 
                    end
 
                elseif s == "suggestedvalues" then
 
                    local v, css, class, ts = facilities( param )
 
                    if v then
 
                        local ul
 
                        ul, v = feasible( param, access, v )
 
                        if v then
 
                            dd:newline()
 
                              :node( ul )
 
                            if css then
 
                                dd:css( css )
 
                                if class then
 
                                    dd:addClass( class )
 
                                end
 
                                if ts then
 
                                    dd:newline()
 
                                    dd:node( ts )
 
                                end
 
                            end
 
                            Data.params[ access ].suggestedvalues = v
 
                        end
 
                    end
 
                else
 
                    dd:wikitext( show )
 
                end
 
                dl:node( mw.html.create( "dt" )
 
                                :wikitext( section ) )
 
                  :node( dd )
 
            end
 
        end -- i = 1, #details
 
        desc:node( dl )
 
    end
 
 
 
    -- type
 
    if type( param.type ) == "string" then
 
        param.type = mw.text.trim( param.type )
 
        if param.type == "" then
 
            param.type = false
 
        end
 
    end
 
    if param.type then
 
        s    = Permit.types[ param.type ]
 
        typed = mw.html.create( "td" )
 
                  :addClass( styles .. "type" )
 
        if s then
 
            if s == "string" then
 
                Data.params[ access ].type = s
 
                typed:wikitext( factory( "doc-param-type-" .. s ) )
 
                    :tag( "br" )
 
                typed:node( mw.html.create( "span" )
 
                                  :addClass( "error" )
 
                                  :wikitext( param.type ) )
 
                Data.lasting = true
 
            else
 
                local support = Config[ "support4" .. param.type ]
 
                s = factory( "doc-param-type-" .. param.type )
 
                if support then
 
                    s = string.format( "[[%s|%s]]", support, s )
 
                end
 
                typed:wikitext( s )
 
            end
 
        else
 
            Data.params[ access ].type = "unknown"
 
            typed:addClass( "error" )
 
                :wikitext( "INVALID" )
 
            s = string.format( "params.<code>%s</code>.type", access )
 
            Fault(  factory( "invalid-value" ):gsub( "$1", s )  )
 
            legal = false
 
        end
 
    else
 
        typed = mw.html.create( "td" )
 
                  :wikitext( factory( "doc-param-type-unknown" ) )
 
        Data.params[ access ].type = "unknown"
 
        if param.default then
 
            Data.params[ access ].default = nil
 
            Fault( "Default value requires <code>type</code>" )
 
            legal = false
 
        end
 
    end
 
    typed:addClass( "navigation-not-searchable" )
 
    -- status
 
    if param.required then
 
        mode = 1
 
        if param.autovalue then
 
            Fault( string.format( "autovalued <code>%s</code> required",
 
                                  access ) )
 
            legal = false
 
        end
 
        if param.default then
 
            Fault( string.format( "Defaulted <code>%s</code> required",
 
                                  access ) )
 
            legal = false
 
        end
 
        if param.deprecated then
 
            Fault( string.format( "Required deprecated <code>%s</code>",
 
                                  access ) )
 
            legal = false
 
        end
 
    elseif param.deprecated then
 
        mode = 4
 
    elseif param.suggested then
 
        mode = 2
 
    else
 
        mode = 3
 
    end
 
    status = ranking[ mode ]
 
    ranking = factory( "doc-param-status-" .. status )
 
    if mode == 1  or  mode == 4 then
 
        ranking = mw.html.create( "span" )
 
                        :css( "font-weight", "bold" )
 
                        :wikitext( ranking )
 
        if type( param.deprecated ) == "string" then
 
            ranking:tag( "br" )
 
            ranking:wikitext( param.deprecated )
 
        end
 
        if param.suggested  and  mode == 4 then
 
            s = string.format( "Suggesting deprecated <code>%s</code>",
 
                              access )
 
            Fault( s )
 
            legal = false
 
        end
 
    end
 
    eager:attr( "data-sort-value", tostring( mode ) )
 
                :node( ranking )
 
                :addClass( string.format( "%sstatus-%s %s",
 
                                          styles, status,
 
                                          "navigation-not-searchable" ) )
 
 
 
    -- <tr>
 
    r:attr( "id",  "templatedata:" .. mw.uri.anchorEncode( access ) )
 
    :css( Permit.css[ status ] )
 
    :addClass( styles .. status )
 
    :node( begin )
 
    :node( code )
 
    :node( desc )
 
    :node( typed )
 
    :node( eager )
 
    :newline()
 
    if not legal then
 
        r:css( "border", "#FF0000 3px solid" )
 
    end
 
    return r
 
end -- feature()
 
 
 
 
 
 
 
local function features()
 
    -- Create <table> for parameters
 
    -- Returns <table>, or nil
 
    local r
 
    if Data.tree and Data.tree.params then
 
        local tbl = mw.html.create( "table" )
 
        local tr  = mw.html.create( "tr" )
 
        feat()
 
        if Data.order  and  #Data.order > 1 then
 
            tbl:addClass( "sortable" )
 
        end
 
        if type( Config.classTable ) == "table" then
 
            for k, v in pairs( Config.classTable ) do
 
                tbl:addClass( v )
 
            end -- for k, v
 
        end
 
        if type( Config.cssTable ) == "table" then
 
            tbl:css( Config.cssTable )
 
        end
 
        tr:addClass( "navigation-not-searchable" )
 
          :node( mw.html.create( "th" )
 
                        :attr( "colspan", "2" )
 
                        :css( Permit.css.tablehead )
 
                        :wikitext( factory( "doc-param-name" ) ) )
 
          :node( mw.html.create( "th" )
 
                        :css( Permit.css.tablehead )
 
                        :wikitext( factory( "doc-param-desc" ) ) )
 
          :node( mw.html.create( "th" )
 
                        :css( Permit.css.tablehead )
 
                        :wikitext( factory( "doc-param-type" ) ) )
 
          :node( mw.html.create( "th" )
 
                        :css( Permit.css.tablehead )
 
                        :wikitext( factory( "doc-param-status" ) ) )
 
        tbl:newline()
 
--        :node( mw.html.create( "thead" )
 
                        :node( tr )
 
--              )
 
          :newline()
 
        if Data.order then
 
            local leave, s
 
            for i = 1, #Data.order do
 
                s = Data.order[ i ]
 
                if s:sub( 1, 1 ) == "=" then
 
                    leave = true
 
                    tbl:node( fatten( s ) )
 
                    Data.order[ i ] = false
 
                elseif s:match( "[=|]" ) then
 
                    Fault( string.format( "Bad param <code>%s</code>",
 
                                          s ) )
 
                else
 
                    tbl:node( feature( s ) )
 
                end
 
            end -- for i = 1, #Data.order
 
            if leave then
 
                for i = #Data.order, 1, -1 do
 
                    if not Data.order[ i ] then
 
                        table.remove( Data.order, i )
 
                    end
 
                end -- for i = #Data.order, 1, -1
 
            end
 
            Data.tag.paramOrder = Data.order
 
        end
 
        if Config.cssTabWrap or Data.scroll then
 
            r = mw.html.create( "div" )
 
            if type( Config.cssTabWrap ) == "table" then
 
                r:css( Config.cssTabWrap )
 
            elseif type( Config.cssTabWrap ) == "string" then
 
                -- deprecated
 
                r:cssText( Config.cssTabWrap )
 
            end
 
            if Data.scroll then
 
                r:css( "height",  Data.scroll )
 
                :css( "overflow", "auto" )
 
            end
 
            r:node( tbl )
 
        else
 
            r = tbl
 
        end
 
    end
 
    return r
 
end -- features()
 
 
 
 
 
 
 
local function fellow( any, assigned, at )
 
    -- Check sets[] parameter and issue error message, if necessary
 
    -- Parameter:
 
    --    any      -- should be number
 
    --    assigned  -- parameter name
 
    --    at        -- number, of set
 
    local s
 
    if type( any ) ~= "number" then
 
        s = "<code>sets[%d].params[%s]</code>??"
 
        Fault( string.format( s,
 
                              at,
 
                              mw.text.nowiki( tostring( any ) ) ) )
 
    elseif type( assigned ) == "string" then
 
        if not Data.got.params[ assigned ] then
 
            s = "<code>sets[%d].params %s</code> is undefined"
 
            Fault( string.format( s, at, assigned ) )
 
        end
 
    else
 
        s = "<code>sets[%d].params[%d] = %s</code>??"
 
        Fault( string.format( s,  k,  type( assigned ) ) )
 
    end
 
end -- fellow()
 
 
 
 
 
 
 
local function fellows()
 
    -- Check sets[] and issue error message, if necessary
 
    local s
 
    if type( Data.got.sets ) == "table" then
 
        if type( Data.got.params ) == "table" then
 
            for k, v in pairs( Data.got.sets ) do
 
                if type( k ) == "number" then
 
                    if type( v ) == "table" then
 
                        for ek, ev in pairs( v ) do
 
                            if ek == "label" then
 
                                s = type( ev )
 
                                if s ~= "string"  and
 
                                  s ~= "table" then
 
                                    s = "<code>sets[%d].label</code>??"
 
                                    Fault( string.format( s, k ) )
 
                                end
 
                            elseif ek == "params"  and
 
                                type( ev ) == "table" then
 
                                for pk, pv in pairs( ev ) do
 
                                    fellow( pk, pv, k )
 
                                end -- for pk, pv
 
                            else
 
                                ek = mw.text.nowiki( tostring( ek ) )
 
                                s  = "<code>sets[%d][%s]</code>??"
 
                                Fault( string.format( s, k, ek ) )
 
                            end
 
                        end -- for ek, ev
 
                    else
 
                        k = mw.text.nowiki( tostring( k ) )
 
                        v = mw.text.nowiki( tostring( v ) )
 
                        s = string.format( "<code>sets[%s][%s]</code>??",
 
                                          k, v )
 
                        Fault( s )
 
                    end
 
                else
 
                    k = mw.text.nowiki( tostring( k ) )
 
                    s = string.format( "<code>sets[%s]</code> ?????", k )
 
                    Fault( s )
 
                end
 
            end -- for k, v
 
        else
 
            s = "<code>params</code> required for <code>sets</code>"
 
            Fault( s )
 
        end
 
    else
 
        s = "<code>sets</code> needs to be of <code>object</code> type"
 
        Fault( s )
 
    end
 
end -- fellows()
 
 
 
 
 
 
 
local function finalize( advance )
 
    -- Wrap presentation into frame
 
    -- Parameter:
 
    --    advance  -- true, for nice
 
    -- Returns string
 
    local r, lapsus
 
    if Data.div then
 
        r = tostring( Data.div )
 
    elseif Data.strip then
 
        r = Data.strip
 
    else
 
        lapsus = true
 
        r      = ""
 
    end
 
    r = r .. failures()
 
    if Data.source then
 
        local live = ( advance or lapsus )
 
        if not live then
 
            live = TemplateData.frame:preprocess( "{{REVISIONID}}" )
 
            live = ( live == "" )
 
        end
 
        if live then
 
            r = r .. fancy( advance, lapsus )
 
        end
 
    end
 
    return r
 
end -- finalize()
 
 
 
 
 
 
 
local function find()
 
    -- Find JSON data within page source (title)
 
    -- Returns string, or nil
 
    local s = Data.title:getContent()
 
    local i, j = s:find( "<templatedata>", 1, true )
 
    local r
 
    if i then
 
        local k = s:find( "</templatedata>", j, true )
 
        if k then
 
          r = mw.text.trim( s:sub( j + 1,  k - 1 ) )
 
        end
 
    end
 
    return r
 
end -- find()
 
 
 
 
 
 
 
local function flat( adjust )
 
    -- Remove formatting from text string for VE
 
    -- Parameter:
 
    --    arglist  -- string, to be stripped, or nil
 
    -- Returns string, or nil
 
    local r
 
    if adjust then
 
        r = adjust:gsub( "\n", " " )
 
        if r:find( "<noexport>", 1, true ) then
 
            r = r:gsub( "<noexport>.*</noexport>", "" )
 
        end
 
        if r:find( "<exportonly>", 1, true ) then
 
            r = r:gsub( "</?exportonly>", "" )
 
        end
 
        if r:find( "''", 1, true ) then
 
            r = r:gsub( "'''", "" ):gsub( "''", "" )
 
        end
 
        if r:find( "<", 1, true ) then
 
            local Text = Fetch( "Text" )
 
            r = Text.getPlain( r:gsub( "<br */?>", "\r\n" ) )
 
        end
 
        if r:find( "[", 1, true ) then
 
            local WLink = Fetch( "WLink" )
 
            if WLink.isBracketedURL( r ) then
 
                r = r:gsub( "%[([hf]tt?ps?://%S+) [^%]]+%]", "%1" )
 
            end
 
            r = WLink.getPlain( r )
 
        end
 
        if r:find( "&", 1, true ) then
 
            r = mw.text.decode( r )
 
            if r:find( "&shy;", 1, true ) then
 
                r = r:gsub( "&shy;", "" )
 
            end
 
        end
 
    end
 
    return r
 
end -- flat()
 
 
 
 
 
 
 
local function flush()
 
    -- JSON encode narrowed input; obey unnamed (numerical) parameters
 
    -- Returns <templatedata> JSON string
 
    local r
 
    if Data.tag then
 
        r = mw.text.jsonEncode( Data.tag ):gsub( "%}$", "," )
 
    else
 
        r = "{"
 
    end
 
    r = r .. "\n\"params\":{"
 
    if Data.order then
 
        local sep = ""
 
        local s
 
        for i = 1, #Data.order do
 
            s  = Data.order[ i ]
 
            r  = string.format( "%s%s\n%s:%s",
 
                                r,
 
                                sep,
 
                                mw.text.jsonEncode( s ),
 
                                mw.text.jsonEncode( Data.params[ s ] ) )
 
            sep = ",\n"
 
        end -- for i = 1, #Data.order
 
    end
 
    r = r .. "\n}\n}"
 
    return r
 
end -- flush()
 
 
 
 
 
 
 
local function focus( access )
 
    -- Check components; focus multilingual description, build trees
 
    -- Parameter:
 
    --    access  -- string, name of parameter, nil for root
 
    local f = function ( a, at )
 
                    local r
 
                    if at then
 
                        r = string.format( "<code>params.%s</code>", at )
 
                    else
 
                        r = "''root''"
 
                    end
 
                    if a then
 
                        r = string.format( "%s<code>.%s</code>", r, a )
 
                    end
 
                    return r
 
                end
 
    local parent
 
    if access then
 
        parent = Data.got.params[ access ]
 
    else
 
        parent = Data.got
 
    end
 
    if type( parent ) == "table" then
 
        local elem, got, permit, s, scope, slot, tag, target
 
        if access then
 
            permit = Permit.params
 
            if type( access ) == "number" then
 
                slot = tostring( access )
 
            else
 
                slot = access
 
            end
 
        else
 
            permit = Permit.root
 
        end
 
        for k, v in pairs( parent ) do
 
            scope = permit[ k ]
 
            if scope then
 
                s = type( v )
 
                if s == "string"  and  k ~= "format" then
 
                    v = mw.text.trim( v )
 
                end
 
                if scope:find( s, 1, true ) then
 
                    if scope:find( "I18N", 1, true ) then
 
                        if s == "string" then
 
                            elem = fair( v )
 
                        elseif s == "table" then
 
                            local translated
 
                            v, translated = faraway( v )
 
                            if v then
 
                                if translated  and
 
                                  k == "description" then
 
                                    elem = { [ 1 ] = fair( v ),
 
                                            [ 2 ] = translated }
 
                                else
 
                                    elem = fair( v )
 
                                end
 
                            else
 
                                elem = false
 
                            end
 
                        end
 
                        if type( v ) == "string" then
 
                            if k == "deprecated" then
 
                                if v == "1" then
 
                                    v = true
 
                                elseif v == "0" then
 
                                    v = false
 
                                end
 
                                elem = v
 
                            elseif scope:find( "nowiki", 1, true ) then
 
                                elem = mw.text.nowiki( v )
 
                                elem = elem:gsub( "&#13;\n", "<br>" )
 
                                v    = v:gsub( string.char( 13 ),  "" )
 
                            else
 
                                v = flat( v )
 
                            end
 
                        elseif s == "boolean" then
 
                            if scope:find( "boolean", 1, true ) then
 
                                elem = v
 
                            else
 
                                s = "Type <code>boolean</code> bad for "
 
                                    .. f( k, slot )
 
                                Fault( s )
 
                            end
 
                        end
 
                    else
 
                        if k == "params"  and  not access then
 
                            v    = nil
 
                            elem = nil
 
                        elseif k == "format"  and  not access then
 
                            elem = mw.text.decode( v )
 
                            v    = nil
 
                        elseif k == "inherits" then
 
                            elem = v
 
                            if not Data.heirs then
 
                                Data.heirs = { }
 
                            end
 
                            Data.heirs[ slot ] = v
 
                            v                  = nil
 
                        elseif k == "style" then
 
                            elem = v
 
                            v    = nil
 
                        elseif s == "string" then
 
                            v    = mw.text.nowiki( v )
 
                            elem = v
 
                        else
 
                            elem = v
 
                        end
 
                    end
 
                    if type( elem ) ~= "nil" then
 
                        if not target then
 
                            if access then
 
                                if not Data.tree.params then
 
                                    Data.tree.params = { }
 
                                end
 
                                Data.tree.params[ slot ] = { }
 
                                target = Data.tree.params[ slot ]
 
                            else
 
                                Data.tree = { }
 
                                target    = Data.tree
 
                            end
 
                        end
 
                        target[ k ] = elem
 
                        elem        = false
 
                    end
 
                    if type( v ) ~= "nil" then
 
                        if not tag then
 
                            if access then
 
                                if type( v ) == "string"  and
 
                                  v.sub( 1, 1 ) == "=" then
 
                                    v = nil
 
                                else
 
                                    if not Data.params then
 
                                        Data.params = { }
 
                                    end
 
                                    Data.params[ slot ] = { }
 
                                    tag = Data.params[ slot ]
 
                                end
 
                            else
 
                                Data.tag = { }
 
                                tag      = Data.tag
 
                            end
 
                        end
 
                        if type( v ) ~= "nil"  and
 
                          k ~= "suggestedvalues" then
 
                            tag[ k ] = v
 
                        end
 
                    end
 
                else
 
                    s = string.format( "Type <code>%s</code> bad for %s",
 
                                      scope,  f( k, slot ) )
 
                    Fault( s )
 
                end
 
            else
 
                Fault( "Unknown component " .. f( k, slot ) )
 
            end
 
        end -- for k, v
 
        if not access  and Data.got.sets then
 
            fellows()
 
        end
 
    else
 
        Fault( f() .. " needs to be of <code>object</code> type" )
 
    end
 
end -- focus()
 
 
 
 
 
 
 
local function format()
 
    -- Build formatted element
 
    -- Returns <inline>
 
    local source = Data.tree.format:lower()
 
    local r, s
 
    if source == "inline"  or  source == "block" then
 
        r = mw.html.create( "i" )
 
                  :wikitext( source )
 
    else
 
        local code
 
        if source:find( "|", 1, true ) then
 
            local scan = "^[\n ]*%{%{[\n _]*|[\n _]*=[\n _]*%}%}[\n ]*$"
 
            if source:match( scan ) then
 
                code = source:gsub( "\n", "N" )
 
            else
 
                s = mw.text.nowiki( source ):gsub( "\n", "&#92;n" )
 
                s = tostring( mw.html.create( "code" )
 
                                    :wikitext( s ) )
 
                Fault( "Invalid format " .. s )
 
                source = false
 
            end
 
        else
 
            local words = mw.text.split( source, "%s+" )
 
            local show, start, support, unknown
 
            for i = 1, #words do
 
                s = words[ i ]
 
                if i == 1 then
 
                    start = s
 
                end
 
                support = Permit.builder[ s ]
 
                if support == start  or
 
                  support == "*" then
 
                    Permit.builder[ s ] = true
 
                elseif s:match( "^[1-9]%d?" ) and
 
                      Permit.builder.align then
 
                    Permit.builder.align = tonumber( s )
 
                else
 
                    if unknown then
 
                        unknown = string.format( "%s %s", unknown, s )
 
                    else
 
                        unknown = s
 
                    end
 
                end
 
            end -- i = 1, #words
 
            if unknown then
 
                s = tostring( mw.html.create( "code" )
 
                                    :css( "white-space", "nowrap" )
 
                                    :wikitext( s ) )
 
                Fault( "Unknown/misplaced format keyword " .. s )
 
                source = false
 
                start  = false
 
            end
 
            if start == "inline" then
 
                if Permit.builder.half == true then
 
                    show = "inline half"
 
                    code = "{{_ |_=_}}"
 
                elseif Permit.builder.grouped == true then
 
                    show = "inline grouped"
 
                    code = "{{_ | _=_}}"
 
                elseif Permit.builder.spaced == true then
 
                    show = "inline spaced"
 
                    code = "{{_ | _ = _ }}"
 
                end
 
                if Permit.builder.newlines == true then
 
                    show = show or "inline"
 
                    code = code or "{{_|_=_}}"
 
                    show = show .. " newlines"
 
                    code = string.format( "N%sN", code )
 
                end
 
            elseif start == "block" then
 
                local space  = ""    -- amid "|" and name
 
                local spaced = " "    -- preceding "="
 
                local spacer = " "    -- following "="
 
                local suffix = "N"    -- closing "}}" on new line
 
                show = "block"
 
                if Permit.builder.indent == true then
 
                    start = " "
 
                    show = "block indent"
 
                else
 
                    start = ""
 
                end
 
                if Permit.builder.compressed == true then
 
                    spaced = ""
 
                    spacer = ""
 
                    show  = show .. " compressed"
 
                    if Permit.builder.last == true then
 
                        show = show .. " last"
 
                    else
 
                        suffix = ""
 
                    end
 
                else
 
                    if Permit.builder.lead == true then
 
                        show  = show .. " lead"
 
                        space = " "
 
                    end
 
                    if type( Permit.builder.align ) ~= "string" then
 
                        local n
 
                        s = " align"
 
                        if Permit.builder.align == true then
 
                            n = 0
 
                            if type( Data.got ) == "table"  and
 
                              type( Data.got.params ) == "table" then
 
                                for k, v in pairs( Data.got.params ) do
 
                                    if type( v ) == "table"  and
 
                                      not v.deprecated  and
 
                                      type( k ) == "string" then
 
                                        k = mw.ustring.len( k )
 
                                        if k > n then
 
                                            n = k
 
                                        end
 
                                    end
 
                                end -- for k, v
 
                            end
 
                        else
 
                            n = Permit.builder.align
 
                            if type( n ) == "number"  and  n > 1 then
 
                                s = string.format( "%s %d", s, n )
 
                            else
 
                                n = 0    -- How comes?
 
                            end
 
                        end
 
                        if n > 1 then
 
                            spaced = string.rep( "_",  n - 1 )  ..  " "
 
                        end
 
                        show = show .. s
 
                    elseif Permit.builder.after == true then
 
                        spaced = ""
 
                        show  = show .. " after"
 
                    elseif Permit.builder.dense == true then
 
                        spaced = ""
 
                        spacer = ""
 
                        show  = show .. " dense"
 
                    end
 
                    if Permit.builder.last == true then
 
                        suffix = spacer
 
                        show  = show .. " last"
 
                    end
 
                end
 
                code = string.format( "N{{_N%s|%s_%s=%s_%s}}N",
 
                                      start,
 
                                      space,
 
                                      spaced,
 
                                      spacer,
 
                                      suffix )
 
                if show == "block" then
 
                    show = "block newlines"
 
                end
 
            end
 
            if show then
 
                r = mw.html.create( "span" )
 
                          :wikitext( show )
 
            end
 
        end
 
        if code then
 
            source = code:gsub( "N", "\n" )
 
            code  = mw.text.nowiki( code ):gsub( "N", "&#92;n" )
 
            code  = mw.html.create( "code" )
 
                            :css( "margin-left",  "1em" )
 
                            :css( "margin-right", "1em" )
 
                            :wikitext( code )
 
            if r then
 
                r = mw.html.create( "span" )
 
                          :node( r )
 
                          :node( code )
 
            else
 
                r = code
 
            end
 
        end
 
    end
 
    if source and Data.tag then
 
        Data.tag.format = source
 
    end
 
    return r
 
end -- format()
 
 
 
 
 
 
 
local function formatter()
 
    -- Build presented documentation
 
    -- Returns <div>
 
    local r = mw.html.create( "div" )
 
    local x = fashioned( Data.tree, true, r )
 
    local s
 
    if x then
 
        r = x
 
    end
 
    if Data.leading then
 
        local toc = mw.html.create( "div" )
 
        local shift
 
        if Config.suppressTOCnum then
 
            toc:addClass( Config.suppressTOCnum )
 
            if type( Config.stylesTOCnum ) == "string" then
 
                local src = Config.stylesTOCnum .. "/styles.css"
 
                s = TemplateData.frame:extensionTag( "templatestyles",
 
                                                    nil,
 
                                                    { src = src } )
 
                r:newline()
 
                :node( s )
 
            end
 
        end
 
        toc:addClass( "navigation-not-searchable" )
 
          :css( "margin-top", "0.5em" )
 
          :wikitext( "__TOC__" )
 
        if Data.sibling then
 
            local block = mw.html.create( "div" )
 
            if TemplateData.ltr then
 
                shift = "right"
 
            else
 
                shift = "left"
 
            end
 
            block:css( "float", shift )
 
                :wikitext( Data.sibling )
 
            r:newline()
 
            :node( block )
 
            :newline()
 
        end
 
        r:newline()
 
        :node( toc )
 
        :newline()
 
        if shift then
 
            r:node( mw.html.create( "div" )
 
                          :css( "clear", shift ) )
 
            :newline()
 
        end
 
    end
 
    s = features()
 
    if s then
 
        if Data.leading then
 
            r:node( mw.html.create( "h" .. Config.nested )
 
                          :wikitext( factory( "doc-params" ) ) )
 
            :newline()
 
        end
 
        r:node( s )
 
    end
 
    if Data.shared then
 
        local global = mw.html.create( "div" )
 
                              :attr( "id", "templatedata-global" )
 
        local shift
 
        if TemplateData.ltr then
 
            shift = "right"
 
        else
 
            shift = "left"
 
        end
 
        global:css( "float", shift )
 
              :wikitext( string.format( "[[%s|%s]]",
 
                                        Data.shared, "Global" ) )
 
        r:newline()
 
        :node( global )
 
    end
 
    if Data.tree and Data.tree.format then
 
        local e = format()
 
        if e then
 
            local show = "Format"
 
            if Config.supportFormat then
 
                show = string.format( "[[%s|%s]]",
 
                                      Config.supportFormat, show )
 
            end
 
            r:node( mw.html.create( "p" )
 
                          :addClass( "navigation-not-searchable" )
 
                          :wikitext( show .. ": " )
 
                          :node( e ) )
 
        end
 
    end
 
    return r
 
end -- formatter()
 
 
 
 
 
 
 
local function free()
 
    -- Remove JSON comment lines
 
    if Data.source:find( "//", 1, true ) then
 
        Data.source:gsub( "([{,\"'])(%s*\n%s*//.*\n%s*)([{},\"'])",
 
                          "%1%3" )
 
    end
 
end -- free()
 
 
 
 
 
 
 
local function full()
 
    -- Build survey table from JSON data, append invisible <templatedata>
 
    Data.div = mw.html.create( "div" )
 
                      :addClass( "mw-templatedata-doc-wrap" )
 
    if Permit.css.bg then
 
        Data.div:css( Permit.css.bg )
 
    end
 
    if Permit.css.fg then
 
        Data.div:css( Permit.css.fg )
 
    end
 
    focus()
 
    if Data.tag then
 
        if type( Data.got.params ) == "table" then
 
            for k, v in pairs( Data.got.params ) do
 
                focus( k )
 
            end -- for k, v
 
            if Data.heirs then
 
                fathers()
 
            end
 
        end
 
    end
 
    Data.div:node( formatter() )
 
    if not Data.lazy then
 
        Data.slim = flush()
 
        if TemplateData.frame then
 
            local div  = mw.html.create( "div" )
 
            local tdata = { [ 1 ] = "templatedata",
 
                            [ 2 ] = Data.slim }
 
            Data.strip = TemplateData.frame:callParserFunction( "#tag",
 
                                                                tdata )
 
            div:wikitext( Data.strip )
 
            if Config.loudly then
 
                Data.div:node( mw.html.create( "hr" )
 
                                      :css( { height = "7ex" } ) )
 
            else
 
                div:css( "display", "none" )
 
            end
 
            Data.div:node( div )
 
        end
 
    end
 
    if Data.lasting then
 
        Fault( "deprecated type syntax" )
 
    end
 
    if Data.less then
 
        Fault( Config.solo )
 
    end
 
end -- full()
 
 
 
 
 
 
 
local function furnish( adapt, arglist )
 
    -- Analyze transclusion
 
    -- Parameter:
 
    --    adapt    -- table, #invoke parameters
 
    --    arglist  -- table, template parameters
 
    -- Returns string
 
    local source
 
    favorize()
 
    -- deprecated:
 
    for k, v in pairs( Config.basicCnf ) do
 
        if adapt[ k ]  and  adapt[ k ] ~= "" then
 
            Config[ v ] = adapt[ k ]
 
        end
 
    end -- for k, v
 
    if arglist.heading  and  arglist.heading:match( "^[3-6]$" ) then
 
        Config.nested = arglist.heading
 
    else
 
        Config.nested = "2"
 
    end
 
    Config.loudly = faculty( arglist.debug or adapt.debug )
 
    Data.lazy    = faculty( arglist.lazy )  and  not Config.loudly
 
    Data.leading  = faculty( arglist.TOC )
 
    if Data.leading and arglist.TOCsibling then
 
        Data.sibling = mw.text.trim( arglist.TOCsibling )
 
    end
 
    if arglist.lang then
 
        Data.slang = arglist.lang:lower()
 
    elseif adapt.lang then
 
        Data.slang = adapt.lang:lower()
 
    end
 
    if arglist.JSON then
 
        source = arglist.JSON
 
    elseif arglist.Global then
 
        source = TemplateData.getGlobalJSON( arglist.Global,
 
                                            arglist.Local )
 
    elseif arglist[ 1 ] then
 
        local s     = mw.text.trim( arglist[ 1 ] )
 
        local start = s:sub( 1, 1 )
 
        if start == "<" then
 
            Data.strip = s
 
        elseif start == "{" then
 
            source = s
 
        elseif mw.ustring.sub( s, 1, 8 ) ==
 
              mw.ustring.char( 127, 39, 34, 96, 85, 78, 73, 81 ) then
 
            Data.strip = s
 
        end
 
    end
 
    if type( arglist.vertical ) == "string"  and
 
      arglist.vertical:match( "^%d*%.?%d+[emprx]+$" ) then
 
        Data.scroll = arglist.vertical
 
    end
 
    if not source then
 
        Data.title = mw.title.getCurrentTitle()
 
        source = find()
 
        if not source  and
 
          not Data.title.text:match( Config.subpage ) then
 
            local s = string.format( Config.suffix,
 
                                    Data.title.prefixedText )
 
            Data.title = mw.title.new( s )
 
            if Data.title.exists then
 
                source = find()
 
            end
 
        end
 
    end
 
    if not Data.lazy then
 
        if not Data.title then
 
            Data.title = mw.title.getCurrentTitle()
 
        end
 
        Data.lazy = Data.title.text:match( Config.subpage )
 
    end
 
    if type( source ) == "string" then
 
        TemplateData.getPlainJSON( source )
 
    end
 
    return finalize( faculty( arglist.source ) )
 
end -- furnish()
 
 
 
 
 
 
 
Failsafe.failsafe = function ( atleast )
 
    -- Retrieve versioning and check for compliance
 
    -- Precondition:
 
    --    atleast  -- string, with required version
 
    --                        or wikidata|item|~|@ or false
 
    -- Postcondition:
 
    --    Returns  string  -- with queried version/item, also if problem
 
    --              false  -- if appropriate
 
    -- 2020-08-17
 
    local since  = atleast
 
    local last  = ( since == "~" )
 
    local linked = ( since == "@" )
 
    local link  = ( since == "item" )
 
    local r
 
    if last  or  link  or  linked  or  since == "wikidata" then
 
        local item = Failsafe.item
 
        since = false
 
        if type( item ) == "number"  and  item > 0 then
 
            local suited = string.format( "Q%d", item )
 
            if link then
 
                r = suited
 
            else
 
                local entity = mw.wikibase.getEntity( suited )
 
                if type( entity ) == "table" then
 
                    local seek = Failsafe.serialProperty or "P348"
 
                    local vsn  = entity:formatPropertyValues( seek )
 
                    if type( vsn ) == "table"  and
 
                      type( vsn.value ) == "string"  and
 
                      vsn.value ~= "" then
 
                        if last  and  vsn.value == Failsafe.serial then
 
                            r = false
 
                        elseif linked then
 
                            if mw.title.getCurrentTitle().prefixedText
 
                              ==  mw.wikibase.getSitelink( suited ) then
 
                                r = false
 
                            else
 
                                r = suited
 
                            end
 
                        else
 
                            r = vsn.value
 
                        end
 
                    end
 
                end
 
            end
 
        end
 
    end
 
    if type( r ) == "nil" then
 
        if not since  or  since <= Failsafe.serial then
 
            r = Failsafe.serial
 
        else
 
            r = false
 
        end
 
    end
 
    return r
 
end -- Failsafe.failsafe()
 
 
 
 
 
 
 
TemplateData.getGlobalJSON = function ( access, adapt )
 
    -- Retrieve TemplateData from a global repository (JSON)
 
    -- Parameter:
 
    --    access  -- string, with page specifier (on WikiMedia Commons)
 
    --    adapt  -- JSON string or table with local overrides
 
    -- Returns true, if succeeded
 
    local plugin = Fetch( "/global" )
 
    local r
 
    if type( plugin ) == "table"  and
 
      type( plugin.fetch ) == "function" then
 
        local s, got = plugin.fetch( access, adapt )
 
        if got then
 
            Data.got    = got
 
            Data.order  = got.paramOrder
 
            Data.shared = s
 
            r          = true
 
            full()
 
        else
 
            Fault( s )
 
        end
 
    end
 
    return r
 
end -- TemplateData.getGlobalJSON()
 
 
 
 
 
 
 
TemplateData.getPlainJSON = function ( adapt )
 
    -- Reduce enhanced JSON data to plain text localized JSON
 
    -- Parameter:
 
    --    adapt  -- string, with enhanced JSON
 
    -- Returns string, or not
 
    if type( adapt ) == "string" then
 
        local JSONutil = Fetch( "JSONutil", true )
 
        Data.source = adapt
 
        free()
 
        if JSONutil then
 
            local Multilingual = Fetch( "Multilingual", true )
 
            local f
 
            if Multilingual then
 
                f = Multilingual.i18n
 
            end
 
            Data.got = JSONutil.fetch( Data.source, true, f )
 
        else
 
            local lucky
 
            lucky, Data.got = pcall( mw.text.jsonDecode, Data.source )
 
        end
 
        if type( Data.got ) == "table" then
 
            full()
 
        elseif not Data.strip then
 
            local scream = type( Data.got )
 
            if scream == "string" then
 
                scream = Data.got
 
            else
 
                scream = "Data.got: " .. scream
 
            end
 
            Fault( "fatal JSON error: " .. scream )
 
        end
 
    end
 
    return Data.slim
 
end -- TemplateData.getPlainJSON()
 
 
 
 
 
 
 
TemplateData.test = function ( adapt, arglist )
 
    TemplateData.frame = mw.getCurrentFrame()
 
    return furnish( adapt, arglist )
 
end -- TemplateData.test()
 
 
 
 
 
 
 
-- Export
 
local p = { }
 
 
 
p.f = function ( frame )
 
    -- Template call
 
    local lucky, r
 
    TemplateData.frame = frame
 
    lucky, r = pcall( furnish, frame.args, frame:getParent().args )
 
    if not lucky then
 
        Fault( "INTERNAL: " .. r )
 
        r = failures()
 
    end
 
    return r
 
end -- p.f
 
 
 
p.failsafe = function ( frame )
 
    -- Versioning interface
 
    local s = type( frame )
 
    local since
 
    if s == "table" then
 
        since = frame.args[ 1 ]
 
    elseif s == "string" then
 
        since = frame
 
    end
 
    if since then
 
        since = mw.text.trim( since )
 
        if since == "" then
 
            since = false
 
        end
 
    end
 
    return Failsafe.failsafe( since )  or  ""
 
end -- p.failsafe
 
 
 
p.TemplateData = function ()
 
    -- Module interface
 
    return TemplateData
 
end
 
 
 
return p
 

Latest revision as of 18:35, 8 April 2023

  • This monster is based on Zhou Yu (courtesy name: Gongjin), from the historical novel Romance of the Three Kingdoms, a famed Wu general known for both his wit and beauty serving under Sun Quan. He was known for his role during Battle of Red Cliffs, the Battle of Jiangling as well as for his many victories which served as the basis of the Wu Kingdom.
    • Additionally, this monster's swan motif and "Graceful" moniker might be a reference to Zhou Yu's popular moniker "Zhou the Beautiful Youth", as swans are symbols of beauty.