<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://wiki.cowboy-of-bottrop.de/index.php?action=history&amp;feed=atom&amp;title=Modul%3APageUtil</id>
	<title>Modul:PageUtil - Versionsgeschichte</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.cowboy-of-bottrop.de/index.php?action=history&amp;feed=atom&amp;title=Modul%3APageUtil"/>
	<link rel="alternate" type="text/html" href="https://wiki.cowboy-of-bottrop.de/index.php?title=Modul:PageUtil&amp;action=history"/>
	<updated>2026-04-17T16:08:49Z</updated>
	<subtitle>Versionsgeschichte dieser Seite in Cowboy’s Wiki</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>https://wiki.cowboy-of-bottrop.de/index.php?title=Modul:PageUtil&amp;diff=340&amp;oldid=prev</id>
		<title>Cowboy: Die Seite wurde neu angelegt: „local PageUtil = { suite  = &quot;PageUtil&quot;,                    serial = &quot;2024-08-20&quot;,                    item   = 89064539 } --[=[ PageUtil ]=] local Failsafe = PageUtil    PageUtil.maxPages = 200    local function fault( alert, frame )     -- Format message with class=&quot;error&quot;     --     alert  -- string, with message     --     frame  -- object, if known     -- Returns message with markup     local scream = alert     if frame then         scream = string.for…“</title>
		<link rel="alternate" type="text/html" href="https://wiki.cowboy-of-bottrop.de/index.php?title=Modul:PageUtil&amp;diff=340&amp;oldid=prev"/>
		<updated>2025-02-03T22:31:15Z</updated>

		<summary type="html">&lt;p&gt;Die Seite wurde neu angelegt: „local PageUtil = { suite  = &amp;quot;PageUtil&amp;quot;,                    serial = &amp;quot;2024-08-20&amp;quot;,                    item   = 89064539 } --[=[ PageUtil ]=] local Failsafe = PageUtil    PageUtil.maxPages = 200    local function fault( alert, frame )     -- Format message with class=&amp;quot;error&amp;quot;     --     alert  -- string, with message     --     frame  -- object, if known     -- Returns message with markup     local scream = alert     if frame then         scream = string.for…“&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Neue Seite&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local PageUtil = { suite  = &amp;quot;PageUtil&amp;quot;,&lt;br /&gt;
                   serial = &amp;quot;2024-08-20&amp;quot;,&lt;br /&gt;
                   item   = 89064539 }&lt;br /&gt;
--[=[&lt;br /&gt;
PageUtil&lt;br /&gt;
]=]&lt;br /&gt;
local Failsafe = PageUtil&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PageUtil.maxPages = 200&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function fault( alert, frame )&lt;br /&gt;
    -- Format message with class=&amp;quot;error&amp;quot;&lt;br /&gt;
    --     alert  -- string, with message&lt;br /&gt;
    --     frame  -- object, if known&lt;br /&gt;
    -- Returns message with markup&lt;br /&gt;
    local scream = alert&lt;br /&gt;
    if frame then&lt;br /&gt;
        scream = string.format( &amp;quot;%s * %s&amp;quot;, frame:getTitle(), scream )&lt;br /&gt;
    end&lt;br /&gt;
    return tostring( mw.html.create( &amp;quot;span&amp;quot; )&lt;br /&gt;
                            :addClass( &amp;quot;error&amp;quot; )&lt;br /&gt;
                            :wikitext( scream ) )&lt;br /&gt;
end -- fault()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function find( area, ask )&lt;br /&gt;
    -- Check for local page existence without traces&lt;br /&gt;
    --     area    -- number, with namespace number &amp;gt;= 0&lt;br /&gt;
    --     ask     -- string, with title&lt;br /&gt;
    -- Returns boolean&lt;br /&gt;
    local r = false&lt;br /&gt;
    if mw.title.makeTitle( area, ask ).protectionLevels.edit then&lt;br /&gt;
        r = true&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- find()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function flat( adjust, assembly )&lt;br /&gt;
    -- Replace links to pages by inner links&lt;br /&gt;
    --     adjust    -- string, with text&lt;br /&gt;
    --     assembly  -- table, with page infos&lt;br /&gt;
    -- Returns adjusted string&lt;br /&gt;
    local r = adjust&lt;br /&gt;
    local seek, shift, source, subst&lt;br /&gt;
    for k, v in pairs( assembly ) do&lt;br /&gt;
        source = v[ 1 ]&lt;br /&gt;
        shift  = v[ 2 ]&lt;br /&gt;
        source = &amp;quot;:?&amp;quot; .. source:gsub( &amp;quot; &amp;quot;, &amp;quot;[_ ]+&amp;quot; )&lt;br /&gt;
                               :gsub( &amp;quot;[%.%(%)%*%?%+%-]&amp;quot;, &amp;quot;%1&amp;quot; )&lt;br /&gt;
                      .. &amp;quot;%s*&amp;quot;&lt;br /&gt;
        seek   = &amp;quot;%[%[%s*&amp;quot; .. source .. &amp;quot;(#[^%]]*%]%])&amp;quot;&lt;br /&gt;
        subst  = &amp;quot;[[%1&amp;quot;&lt;br /&gt;
        r = r:gsub( seek, subst )&lt;br /&gt;
        seek  = &amp;quot;%[%[%s*&amp;quot; .. source .. &amp;quot;(%|[^%]]*%]%])&amp;quot;&lt;br /&gt;
        subst = &amp;quot;[[#&amp;quot; .. shift .. &amp;quot;%1&amp;quot;&lt;br /&gt;
        r = r:gsub( seek, subst )&lt;br /&gt;
        seek  = &amp;quot;%[%[%s*(&amp;quot; .. source .. &amp;quot;%]%])&amp;quot;&lt;br /&gt;
        subst = &amp;quot;[[#&amp;quot; .. shift .. &amp;quot;|%1&amp;quot;&lt;br /&gt;
        r = r:gsub( seek, subst )&lt;br /&gt;
    end -- for k, v&lt;br /&gt;
    return r&lt;br /&gt;
end -- flat()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function fraction( access, frame )&lt;br /&gt;
    -- Retrieve text from section&lt;br /&gt;
    --     access  -- string, with request&lt;br /&gt;
    --     frame   -- object&lt;br /&gt;
    -- Returns content, or false&lt;br /&gt;
    -- Uses:&lt;br /&gt;
    --     mw.title.new() .exists&lt;br /&gt;
    local r&lt;br /&gt;
    local seek = &amp;quot;^(#lstx?):%s*%[%[([^%[|%]\n]+)%]%]%s*(%S.*)%s*$&amp;quot;&lt;br /&gt;
    local scope, source, section = access:match( seek )&lt;br /&gt;
    if source then&lt;br /&gt;
        local page = mw.title.new( source )&lt;br /&gt;
        source = page.prefixedText&lt;br /&gt;
        if page.exists then&lt;br /&gt;
            section = mw.text.trim( section )&lt;br /&gt;
            if section ~= &amp;quot;&amp;quot; then&lt;br /&gt;
                r = frame:callParserFunction{ name = scope,&lt;br /&gt;
                                              args = { source,&lt;br /&gt;
                                                       section } }&lt;br /&gt;
            end&lt;br /&gt;
        else&lt;br /&gt;
            r = tostring( mw.html.create( &amp;quot;div&amp;quot; )&lt;br /&gt;
                                 :addClass( &amp;quot;error&amp;quot; )&lt;br /&gt;
                                 :wikitext( source ) )&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- fraction()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function full( access, frame, alias, assembly )&lt;br /&gt;
    -- Retrieve text from page&lt;br /&gt;
    --     access    -- string, with page name&lt;br /&gt;
    --     frame     -- object&lt;br /&gt;
    --     alias     -- number, unique&lt;br /&gt;
    --     assembly  -- table, with page infos&lt;br /&gt;
    -- Returns string with content, or nil&lt;br /&gt;
    -- Uses:&lt;br /&gt;
    --     mw.title.new() .exists&lt;br /&gt;
    local page = mw.title.new( access )&lt;br /&gt;
    local r&lt;br /&gt;
    if page then&lt;br /&gt;
        if page.exists then&lt;br /&gt;
            local source  = page.prefixedText&lt;br /&gt;
            local segment = string.format( &amp;quot;PageUtilMerge-%d&amp;quot;, alias )&lt;br /&gt;
            local seed&lt;br /&gt;
            if page.namespace == 0 then&lt;br /&gt;
                seed = &amp;quot;:&amp;quot; .. source&lt;br /&gt;
            else&lt;br /&gt;
                seed = source&lt;br /&gt;
            end&lt;br /&gt;
            r = string.format( &amp;quot;%s\n%s&amp;quot;,&lt;br /&gt;
                               tostring( mw.html.create( &amp;quot;span&amp;quot; )&lt;br /&gt;
                                                :attr( &amp;quot;id&amp;quot;, segment ) ),&lt;br /&gt;
                               frame:expandTemplate( { title = seed } ) )&lt;br /&gt;
            table.insert( assembly,  { source, segment } )&lt;br /&gt;
        else&lt;br /&gt;
            r = tostring( mw.html.create( &amp;quot;div&amp;quot; )&lt;br /&gt;
                                 :addClass( &amp;quot;error&amp;quot; )&lt;br /&gt;
                                 :wikitext( page.prefixedText ) )&lt;br /&gt;
        end&lt;br /&gt;
    else&lt;br /&gt;
        r = string.format( &amp;quot;%s &amp;#039;%s&amp;#039;&amp;quot;, &amp;quot;Unknown page&amp;quot;, access )&lt;br /&gt;
        r = tostring( mw.html.create( &amp;quot;div&amp;quot; )&lt;br /&gt;
                             :addClass( &amp;quot;error&amp;quot; )&lt;br /&gt;
                             :wikitext( r ) )&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- full()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PageUtil.exists = function ( area, ask, apply, alert )&lt;br /&gt;
    -- Check for existence&lt;br /&gt;
    --     area    -- number or string, with namespace specification&lt;br /&gt;
    --                -- number &amp;gt;= 0 of local namespace&lt;br /&gt;
    --                -- &amp;quot;media&amp;quot;  -- files including commons&lt;br /&gt;
    --                -- &amp;quot;msg&amp;quot;    -- system messages&lt;br /&gt;
    --                -- &amp;quot;data&amp;quot;   -- commons:Data:*.tab&lt;br /&gt;
    --     ask     -- table, with list of titles&lt;br /&gt;
    --     apply   -- table or not, with 0, 1, 2 elements&lt;br /&gt;
    --                -- [true]: category list on existence&lt;br /&gt;
    --                -- [false]: category list on non-existence&lt;br /&gt;
    --                -- category titles, multiple separated by \n&lt;br /&gt;
    --     alert   -- table or not, with 0, 1, 2 elements&lt;br /&gt;
    --                -- [true]: return value on existence&lt;br /&gt;
    --                -- [false]: return value on non-existence&lt;br /&gt;
    --                -- if string then followed by apply categories&lt;br /&gt;
    -- Returns string, with content, or other element of alert&lt;br /&gt;
    local got, leg, r&lt;br /&gt;
    if type( area ) == &amp;quot;number&amp;quot;  and&lt;br /&gt;
       area &amp;gt;= 0  and&lt;br /&gt;
       math.floor( area ) == area then&lt;br /&gt;
        for k, v in pairs( ask ) do&lt;br /&gt;
            if type( v ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
                got = got  or  { }&lt;br /&gt;
                leg = find( area, v )&lt;br /&gt;
                got[ leg ] = got[ leg ]  or  { }&lt;br /&gt;
                table.insert( got[ leg ], v )&lt;br /&gt;
            end&lt;br /&gt;
        end -- for k, v&lt;br /&gt;
    elseif area == &amp;quot;media&amp;quot; then&lt;br /&gt;
        for k, v in pairs( ask ) do&lt;br /&gt;
            if type( v ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
                got = got  or  { }&lt;br /&gt;
                leg = find( 6, v )&lt;br /&gt;
                if not leg then&lt;br /&gt;
                    leg = mw.title.makeTitle( 6, v ).exists&lt;br /&gt;
                end&lt;br /&gt;
                got[ leg ] = got[ leg ]  or  { }&lt;br /&gt;
                table.insert( got[ leg ], v )&lt;br /&gt;
            end&lt;br /&gt;
        end -- for k, v&lt;br /&gt;
    elseif area == &amp;quot;msg&amp;quot; then&lt;br /&gt;
        for k, v in pairs( ask ) do&lt;br /&gt;
            if type( v ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
                got = got  or  { }&lt;br /&gt;
                leg = mw.message.new( v ):exists()&lt;br /&gt;
                got[ leg ] = got[ leg ]  or  { }&lt;br /&gt;
                table.insert( got[ leg ], v )&lt;br /&gt;
            end&lt;br /&gt;
        end -- for k, v&lt;br /&gt;
    elseif area == &amp;quot;data&amp;quot; then&lt;br /&gt;
        local suffix = &amp;quot;tab&amp;quot;&lt;br /&gt;
        local data, j, lucky&lt;br /&gt;
        for k, v in pairs( ask ) do&lt;br /&gt;
            if type( v ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
                got = got  or  { }&lt;br /&gt;
                if not v:find( &amp;quot;.&amp;quot;, 2, true ) then&lt;br /&gt;
                    j = -1 - #suffix&lt;br /&gt;
                    if v:sub( j ) ~= &amp;quot;.&amp;quot; .. suffix then&lt;br /&gt;
                        v = string.format( &amp;quot;%s.%s&amp;quot;, v, suffix )&lt;br /&gt;
                    end&lt;br /&gt;
                end&lt;br /&gt;
                lucky, data = pcall( mw.ext.data.get, v )&lt;br /&gt;
                if lucky then&lt;br /&gt;
                    leg = true&lt;br /&gt;
                else&lt;br /&gt;
                    leg = false&lt;br /&gt;
                end&lt;br /&gt;
                got[ leg ] = got[ leg ]  or  { }&lt;br /&gt;
                table.insert( got[ leg ], v )&lt;br /&gt;
            end&lt;br /&gt;
        end -- for k, v&lt;br /&gt;
    else&lt;br /&gt;
        r = tostring( mw.html.create( &amp;quot;span&amp;quot; )&lt;br /&gt;
                             :addClass( &amp;quot;error&amp;quot; )&lt;br /&gt;
                             :wikitext( &amp;quot;exists@PageUtil space error&amp;quot; ) )&lt;br /&gt;
    end&lt;br /&gt;
    if got then&lt;br /&gt;
        local b = { false, true }&lt;br /&gt;
        local bg, ea, sa, sr&lt;br /&gt;
        for bk, bv in pairs( b ) do&lt;br /&gt;
            bg = got[ bv ]&lt;br /&gt;
            if bg then&lt;br /&gt;
                sr = type( r )&lt;br /&gt;
                ea = alert[ bv ]&lt;br /&gt;
                if ea then&lt;br /&gt;
                    sa = type( ea )&lt;br /&gt;
                    if sr == &amp;quot;string&amp;quot;  and&lt;br /&gt;
                       sa == &amp;quot;string&amp;quot; then&lt;br /&gt;
                        r = r .. ea&lt;br /&gt;
                    elseif sr == &amp;quot;nil&amp;quot; then&lt;br /&gt;
                        r  = ea&lt;br /&gt;
                        sr = sa&lt;br /&gt;
                    end&lt;br /&gt;
                    if sr == &amp;quot;string&amp;quot;  and&lt;br /&gt;
                       r:find( &amp;quot;@@@&amp;quot;, 1, true ) then&lt;br /&gt;
                       local space&lt;br /&gt;
                       if type( area ) == &amp;quot;number&amp;quot; then&lt;br /&gt;
                           space = area&lt;br /&gt;
                       elseif area == &amp;quot;media&amp;quot; then&lt;br /&gt;
                           space = 6&lt;br /&gt;
                       elseif area == &amp;quot;msg&amp;quot; then&lt;br /&gt;
                           space = 8&lt;br /&gt;
                       elseif area == &amp;quot;data&amp;quot; then&lt;br /&gt;
                           space = &amp;quot;commons:Data&amp;quot;&lt;br /&gt;
                       end&lt;br /&gt;
                       if type( space ) == &amp;quot;number&amp;quot; then&lt;br /&gt;
                           sa = mw.site.namespaces[ space ].name&lt;br /&gt;
                           if space == 6  or  space == 14 then&lt;br /&gt;
                               space = &amp;quot;:&amp;quot; .. sa&lt;br /&gt;
                           else&lt;br /&gt;
                               space = sa&lt;br /&gt;
                           end&lt;br /&gt;
                       end&lt;br /&gt;
                       sa = &amp;quot;&amp;quot;&lt;br /&gt;
                       for k, v in pairs( bg ) do&lt;br /&gt;
                           sa = string.format( &amp;quot;%s [[%s:%s]]&amp;quot;,&lt;br /&gt;
                                               sa, space, v )&lt;br /&gt;
                       end -- for k, v&lt;br /&gt;
                       r = r:gsub( &amp;quot;@@@&amp;quot;, sa )&lt;br /&gt;
                    end&lt;br /&gt;
                end&lt;br /&gt;
                ea = apply[ bv ]&lt;br /&gt;
                if ea then&lt;br /&gt;
                    if sr == &amp;quot;nil&amp;quot; then&lt;br /&gt;
                        r  = &amp;quot;&amp;quot;&lt;br /&gt;
                        sr = &amp;quot;string&amp;quot;&lt;br /&gt;
                    end&lt;br /&gt;
                    if sr == &amp;quot;string&amp;quot; then&lt;br /&gt;
                        sa = type( ea )&lt;br /&gt;
                        if sa == &amp;quot;string&amp;quot; then&lt;br /&gt;
                            r = string.format( &amp;quot;%s[[Category:%s]]&amp;quot;,&lt;br /&gt;
                                               r, sa )&lt;br /&gt;
                        elseif sa == &amp;quot;table&amp;quot; then&lt;br /&gt;
                            for k, v in pairs( ea ) do&lt;br /&gt;
                                r = string.format( &amp;quot;%s[[Category:%s]]&amp;quot;,&lt;br /&gt;
                                                   r, v )&lt;br /&gt;
                            end -- for k, v&lt;br /&gt;
                        end&lt;br /&gt;
                    end&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end -- for bk, bv&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- PageUtil.exists()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PageUtil.getProtection = function ( access, action )&lt;br /&gt;
    -- Retrieve protection&lt;br /&gt;
    --     access  -- string or title or nil, with page, default: current&lt;br /&gt;
    --     action  -- string or nil, with action, default: edit&lt;br /&gt;
    -- Returns number: One of: 0, 0.5, 0.75, 1&lt;br /&gt;
    local t = type( access )&lt;br /&gt;
    local r = 0&lt;br /&gt;
    local p&lt;br /&gt;
    if t == &amp;quot;string&amp;quot; then&lt;br /&gt;
        t = mw.title.new( access )&lt;br /&gt;
    elseif t == &amp;quot;table&amp;quot; then&lt;br /&gt;
        t = access&lt;br /&gt;
    else&lt;br /&gt;
        t = mw.title.getCurrentTitle()&lt;br /&gt;
    end&lt;br /&gt;
    p = t.protectionLevels&lt;br /&gt;
    if type( p ) == &amp;quot;table&amp;quot; then&lt;br /&gt;
        local s&lt;br /&gt;
        if type( action ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
            s = mw.text.trim( action )&lt;br /&gt;
            if s == &amp;quot;&amp;quot; then&lt;br /&gt;
                s = false&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
        p = p[ s or &amp;quot;edit&amp;quot; ]&lt;br /&gt;
        if type( p ) == &amp;quot;table&amp;quot; then&lt;br /&gt;
            for k, v in pairs( p ) do&lt;br /&gt;
                if v == &amp;quot;autoconfirmed&amp;quot; then&lt;br /&gt;
                    r = 0.5&lt;br /&gt;
                elseif v == &amp;quot;editeditorprotected&amp;quot; then&lt;br /&gt;
                    r = 0.75&lt;br /&gt;
                elseif v == &amp;quot;sysop&amp;quot; then&lt;br /&gt;
                    r = 1&lt;br /&gt;
                end&lt;br /&gt;
            end -- for k, v&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- PageUtil.getProtection()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PageUtil.merge = function ( args, frame )&lt;br /&gt;
    -- Retrieve text&lt;br /&gt;
    --     args   -- table, with request&lt;br /&gt;
    --     frame  -- object, if available&lt;br /&gt;
    -- Returns string, with content&lt;br /&gt;
    local max = 0&lt;br /&gt;
    local r   = &amp;quot;&amp;quot;&lt;br /&gt;
    for k, v in pairs( args ) do&lt;br /&gt;
        if type( k ) == &amp;quot;number&amp;quot;  and&lt;br /&gt;
           k &amp;gt; max then&lt;br /&gt;
            max = k&lt;br /&gt;
        end&lt;br /&gt;
    end -- for k, v&lt;br /&gt;
    if max &amp;gt; 0 then&lt;br /&gt;
        local n     = 0&lt;br /&gt;
        local pages = {  { mw.title.getCurrentTitle().prefixedText,&lt;br /&gt;
                           &amp;quot;&amp;quot; }  }&lt;br /&gt;
        local mode, s, section, swallow&lt;br /&gt;
        if not frame then&lt;br /&gt;
            frame = mw.getCurrentFrame()&lt;br /&gt;
        end&lt;br /&gt;
        for i = 1, max do&lt;br /&gt;
            s = args[ i ]&lt;br /&gt;
            if s then&lt;br /&gt;
                swallow = s:match( &amp;quot;^%s*(#lstx?:[^\n]*%S)%s*$&amp;quot; )&lt;br /&gt;
                if swallow then&lt;br /&gt;
                    s = fraction( swallow, frame )&lt;br /&gt;
                    n = n + 1&lt;br /&gt;
                else&lt;br /&gt;
                    swallow = s:match( &amp;quot;^%s*%[%[([^%[|%]\n]+)%]%]%s*$&amp;quot; )&lt;br /&gt;
                    if swallow then&lt;br /&gt;
                        s = full( swallow, frame, i, pages )&lt;br /&gt;
                        n = n + 1&lt;br /&gt;
                    end&lt;br /&gt;
                end&lt;br /&gt;
                if s then&lt;br /&gt;
                    r = r .. mw.text.trim( s )&lt;br /&gt;
                end&lt;br /&gt;
                if n &amp;gt; PageUtil.maxPages then&lt;br /&gt;
                    s = string.format( &amp;quot;&amp;#039;&amp;#039;&amp;#039;Too many pages (max. %d)&amp;#039;&amp;#039;&amp;#039;&amp;quot;,&lt;br /&gt;
                                       PageUtil.maxPages )&lt;br /&gt;
                    r = string.format( &amp;quot;%s\n\n%s&amp;quot;,&lt;br /&gt;
                                       r,&lt;br /&gt;
                                       fault( s, frame ) )&lt;br /&gt;
                    break -- for i&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end -- for i&lt;br /&gt;
        r = flat( r, pages )&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- .merge()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Failsafe.failsafe = function ( atleast )&lt;br /&gt;
    -- Retrieve versioning and check for compliance&lt;br /&gt;
    -- Precondition:&lt;br /&gt;
    --     atleast  -- string, with required version&lt;br /&gt;
    --                         or wikidata|item|~|@ or false&lt;br /&gt;
    -- Postcondition:&lt;br /&gt;
    --     Returns  string  -- with queried version/item, also if problem&lt;br /&gt;
    --              false   -- if appropriate&lt;br /&gt;
    -- 2024-03-01&lt;br /&gt;
    local since  = atleast&lt;br /&gt;
    local last   = ( since == &amp;quot;~&amp;quot; )&lt;br /&gt;
    local linked = ( since == &amp;quot;@&amp;quot; )&lt;br /&gt;
    local link   = ( since == &amp;quot;item&amp;quot; )&lt;br /&gt;
    local r&lt;br /&gt;
    if last  or  link  or  linked  or  since == &amp;quot;wikidata&amp;quot; then&lt;br /&gt;
        local item = Failsafe.item&lt;br /&gt;
        since = false&lt;br /&gt;
        if type( item ) == &amp;quot;number&amp;quot;  and  item &amp;gt; 0 then&lt;br /&gt;
            local suited = string.format( &amp;quot;Q%d&amp;quot;, item )&lt;br /&gt;
            if link then&lt;br /&gt;
                r = suited&lt;br /&gt;
            else&lt;br /&gt;
                local entity = mw.wikibase.getEntity( suited )&lt;br /&gt;
                if type( entity ) == &amp;quot;table&amp;quot; then&lt;br /&gt;
                    local seek = Failsafe.serialProperty or &amp;quot;P348&amp;quot;&lt;br /&gt;
                    local vsn  = entity:formatPropertyValues( seek )&lt;br /&gt;
                    if type( vsn ) == &amp;quot;table&amp;quot;  and&lt;br /&gt;
                       type( vsn.value ) == &amp;quot;string&amp;quot;  and&lt;br /&gt;
                       vsn.value ~= &amp;quot;&amp;quot; then&lt;br /&gt;
                        if last  and  vsn.value == Failsafe.serial then&lt;br /&gt;
                            r = false&lt;br /&gt;
                        elseif linked then&lt;br /&gt;
                            if mw.title.getCurrentTitle().prefixedText&lt;br /&gt;
                               ==  mw.wikibase.getSitelink( suited ) then&lt;br /&gt;
                                r = false&lt;br /&gt;
                            else&lt;br /&gt;
                                r = suited&lt;br /&gt;
                            end&lt;br /&gt;
                        else&lt;br /&gt;
                            r = vsn.value&lt;br /&gt;
                        end&lt;br /&gt;
                    end&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        elseif link then&lt;br /&gt;
            r = false&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    if type( r ) == &amp;quot;nil&amp;quot; then&lt;br /&gt;
        if not since  or  since &amp;lt;= Failsafe.serial then&lt;br /&gt;
            r = Failsafe.serial&lt;br /&gt;
        else&lt;br /&gt;
            r = false&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- Failsafe.failsafe()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Export&lt;br /&gt;
local p = { }&lt;br /&gt;
&lt;br /&gt;
p.exists = function ( frame )&lt;br /&gt;
    local pars = frame:getParent().args&lt;br /&gt;
    local ns, r&lt;br /&gt;
    if not pars.ns then&lt;br /&gt;
    elseif pars.ns:find( &amp;quot;^%d+$&amp;quot; ) then&lt;br /&gt;
        ns = tonumber( pars.ns )&lt;br /&gt;
    elseif pars.ns:find( &amp;quot;^%a+$&amp;quot; ) then&lt;br /&gt;
        ns = pars.ns:lower()&lt;br /&gt;
    end&lt;br /&gt;
    if ns then&lt;br /&gt;
        local coll, t&lt;br /&gt;
        for k, v in pairs( pars ) do&lt;br /&gt;
            t = type( k )&lt;br /&gt;
            if t == &amp;quot;string&amp;quot; then&lt;br /&gt;
                if t:match( &amp;quot;^%d+$&amp;quot; ) then&lt;br /&gt;
                    k = tonumber( k )&lt;br /&gt;
                else&lt;br /&gt;
                    k = false&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
            if k then&lt;br /&gt;
                v = mw.text.trim( v )&lt;br /&gt;
                if v ~= &amp;quot;&amp;quot; then&lt;br /&gt;
                    coll = coll or { }&lt;br /&gt;
                    table.insert( coll, v )&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end -- for k, v&lt;br /&gt;
        if coll then&lt;br /&gt;
            local loss = ( pars.loss == &amp;quot;1&amp;quot; )&lt;br /&gt;
            local cat, err&lt;br /&gt;
            if pars.cat then&lt;br /&gt;
                t = mw.text.split( pars.cat, &amp;quot;%s*\n%s*&amp;quot; )&lt;br /&gt;
                if #t &amp;gt; 0 then&lt;br /&gt;
                    cat = { [ loss ] = t }&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
            if pars.err  and  pars.err ~= &amp;quot;&amp;quot; then&lt;br /&gt;
               err = { [ loss ] = pars.err }&lt;br /&gt;
            end&lt;br /&gt;
            r = PageUtil.exists( ns, coll, cat, err )&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return r or &amp;quot;&amp;quot;&lt;br /&gt;
end -- p.exists&lt;br /&gt;
&lt;br /&gt;
p.getCategories = function ( frame )&lt;br /&gt;
    local r = &amp;quot;&amp;quot;&lt;br /&gt;
    local s = frame.args[ 1 ]&lt;br /&gt;
    local c, t&lt;br /&gt;
    if s then&lt;br /&gt;
        s = mw.text.trim( s )&lt;br /&gt;
        if s == &amp;quot;&amp;quot; then&lt;br /&gt;
            s = false&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    if s then&lt;br /&gt;
        t = mw.title.new( s )&lt;br /&gt;
    else&lt;br /&gt;
        t = mw.title.getCurrentTitle()&lt;br /&gt;
    end&lt;br /&gt;
    c = t.categories&lt;br /&gt;
    if c then&lt;br /&gt;
        local n = #c&lt;br /&gt;
        if n &amp;gt; 0 then&lt;br /&gt;
            for i = 1, n do&lt;br /&gt;
                if r ~= &amp;quot;&amp;quot; then&lt;br /&gt;
                    r = r .. &amp;quot;|&amp;quot;&lt;br /&gt;
                end&lt;br /&gt;
                r = r .. c[ i ]&lt;br /&gt;
            end -- for i&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- p.getCategories&lt;br /&gt;
&lt;br /&gt;
p.getProtection = function ( frame )&lt;br /&gt;
    local n = PageUtil.getProtection( frame.args[ 1 ], frame.args[ 2 ] )&lt;br /&gt;
    local t = { [ 0 ]    = &amp;quot;&amp;quot;,&lt;br /&gt;
                [ 0.5 ]  = mw.ustring.char( 189 ),&lt;br /&gt;
                [ 0.75 ] = mw.ustring.char( 190 ),&lt;br /&gt;
                [ 1 ]    = &amp;quot;1&amp;quot; }&lt;br /&gt;
    return t[ n ]&lt;br /&gt;
end -- p.getProtection&lt;br /&gt;
&lt;br /&gt;
p.isRedirect = function ()&lt;br /&gt;
    return mw.title.getCurrentTitle().isRedirect and &amp;quot;1&amp;quot;  or  &amp;quot;&amp;quot;&lt;br /&gt;
end -- p.isRedirect&lt;br /&gt;
&lt;br /&gt;
p.merge = function ( frame )&lt;br /&gt;
    local lucky, r = pcall( PageUtil.merge, frame.args, frame )&lt;br /&gt;
    if not lucky then&lt;br /&gt;
        r = fault( r, frame )&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- p.merge&lt;br /&gt;
&lt;br /&gt;
p.failsafe = function ( frame )&lt;br /&gt;
    -- Versioning interface&lt;br /&gt;
    local s = type( frame )&lt;br /&gt;
    local since&lt;br /&gt;
    if s == &amp;quot;table&amp;quot; then&lt;br /&gt;
        since = frame.args[ 1 ]&lt;br /&gt;
    elseif s == &amp;quot;string&amp;quot; then&lt;br /&gt;
        since = frame&lt;br /&gt;
    end&lt;br /&gt;
    if since then&lt;br /&gt;
        since = mw.text.trim( since )&lt;br /&gt;
        if since == &amp;quot;&amp;quot; then&lt;br /&gt;
            since = false&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return Failsafe.failsafe( since )  or  &amp;quot;&amp;quot;&lt;br /&gt;
end -- p.failsafe()&lt;br /&gt;
&lt;br /&gt;
function p.PageUtil()&lt;br /&gt;
    return PageUtil&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
setmetatable( p,  { __call = function ( func, ... )&lt;br /&gt;
                                 setmetatable( p, nil )&lt;br /&gt;
                                 return Failsafe&lt;br /&gt;
                             end } )&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Cowboy</name></author>
	</entry>
</feed>