local WLink = { suite  = "WLink",                 serial = "2016-10-05" }; --[=[ ansiPercent() formatURL() getArticleBase() getBaseTitle() getEscapedTitle() getExtension() getFile() getFragment() getLanguage() getNamespace() getPlain() getProject() getTarget() getTargetPage() getTitle() getWeblink() isBracketedLink() isBracketedURL() isCategorization() isExternalLink() isInterlanguage() isInterwiki() isMedia() isTitledLink() isValidLink() isWikilink() wikilink() failsafe() ]=]  -- local globals local URLutil = false;  local utilURL = function ()     -- Attach URLutil library module     -- Postcondition:     --     Returns  table, with URLutil library     --     Throws error, if not available     if not URLutil then         local lucky, util = pcall( require, "Module:URLutil" );         if lucky then             if type( util ) == "table" then                 URLutil = util.URLutil();             end             util = "library URLutil invalid";         end         if type( URLutil ) ~= "table" then             error( util, 0 );         end     end     return URLutil; end -- utilURL()  local contentExtlink = function ( attempt )     -- Retrieve span of external link between brackets     -- Precondition:     --     attempt  -- string, with presumable link     --                         the first char is expected to be "["     -- Postcondition:     --     Returns  string, number, number     --                  string including whitespace     --                  number with index of relevant "["     --                  number with index after relevant "]"     --              false if nothing found     local r1 = false;     local r2 = false;     local r3 = attempt:find( "]", 2, true );     if r3 then         local s = attempt:sub( 2,  r3 - 1 );         local i = s:find( "[", 1, true );         if i then             r1 = s:sub( i + 1 );             r2 = i;         else             r1 = s;             r2 = 1;         end     else         r3 = false;     end     return r1, r2, r3; end -- contentExtlink()  local contentWikilink = function ( attempt )     -- Retrieve span of wikilink between brackets     -- Precondition:     --     attempt  -- string, with presumable link     --                        the first two chars are expected to be "[["     -- Postcondition:     --     Returns  string, number, number     --                  string including whitespace     --                  number with index of relevant "[["     --                  number with index after relevant "]]"     --              false if nothing found     local r1 = false;     local r2 = false;     local r3 = attempt:find( "]]", 3, true );     if r3 then         local s = attempt:sub( 3,  r3 - 1 );         local i = s:find( "[[", 1, true );         if i then             r1 = s:sub( i + 2 );             r2 = i;         else             r1 = s;             r2 = 1;         end     end     return r1, r2, r3; end -- contentWikilink()  local extractExtlink = function ( attempt )     -- Retrieve external link     -- Precondition:     --     attempt  -- string, with presumable link     --                        the first char is expected to be "["     -- Postcondition:     --     Returns  string, string     --                  first with target and title     --                  second result false if not titled     --              false if nothing found     local r1 = false;     local r2 = false;     local s = contentExtlink( attempt );     if s then         local i = s:find( "%s", 1 );         if i then             r1 = s:sub( 1,  i - 1 );             r2 = mw.text.trim( s:sub( i + 1 ) );             if r2 == "" then                 r2 = false;             end         else             r1 = s;         end         if r1 then             r1 = mw.text.trim( r1 );             if r1 == ""  or                not utilURL().isResourceURL( r1 ) then                 r1 = false;             end         end         if not r1 then             r2 = false;         end     end     return r1, r2; end -- extractExtlink()  local extractWikilink = function ( attempt )     -- Retrieve wikilink     -- Precondition:     --     attempt  -- string, with presumable link     --                        the first two chars are expected to be "[["     -- Postcondition:     --     Returns  string, string     --                  first with target     --                  second result title, or false if not piped     --              false if nothing found     local r1 = false;     local r2 = false;     local s = contentWikilink( attempt );     if s then         local i = s:find( "|", 1, true );         if i then             r1 = s:sub( 1,  i - 1 );             r2 = s:sub( i + 1 );         else             r1 = s;         end         r1 = mw.text.trim( r1 );         if r1 == "" then             r1 = false;         else             r1 = r1:gsub( "_",        " " )                    :gsub( " ",   " " )                    :gsub( " ", " " )                    :gsub( " ",   " " )                    :gsub( " ",  " " )                    :gsub( "  +",      " " );             r1 = mw.text.decode( r1 );         end     end     return r1, r2; end -- extractWikilink()  local prefix = function ( ask, ahead )     -- Interprete prefix of language or project type     -- Precondition:     --     ask    -- string, with presumable prefix     --     ahead  -- true, if first segment     -- Postcondition:     --     Returns  string,string or nil     --                     first  string one of "lead", "lang", "project"     --                     second string is formatted value     --                       type is one of "lead", "lang", "project"     --              nil if nothing found     local r1, r2;     local prefixes = { b           = true,                        c           = "commons",                        d           = true,                        commons     = true,                        m           = "meta",                        mediawiki   = "mw",                        mw          = true,                        meta        = true,                        n           = true,                        q           = true,                        s           = true,                        simple      = false,                        v           = true,                        voy         = true,                        w           = true,                        wikibooks   = "b",                        wikidata    = "d",                        wikinews    = "n",                        wikipedia   = "w",                        wikiquote   = "q",                        wikisource  = "s",                        wikiversity = "v",                        wikivoyage  = "voy",                        wikt        = true,                        wiktionary  = "wikt"                      };     local s = mw.text.trim( ask );     if s == "" then         if ahead then             r1 = "lead";             r2 = true;         end     else         local p;         s = s:lower();         p = prefixes[ s ];         if p == true then             r1 = "project";             r2 = s;         elseif p then             r1 = "project";             r2 = p;         elseif p == false then             r1 = "lang";             r2 = s;         elseif s:match( "^%l%l%l?$" )                and  mw.language.isSupportedLanguage( s ) then             r1 = "lang";             r2 = s;         end     end     return r1, r2; end -- prefix()  local target = function ( attempt, lonely )     -- Retrieve first target (wikilink or URL), or entire string     -- Precondition:     --     attempt  -- string, with presumable link somewhere     --     lonely   -- remove fragment, if true     -- Postcondition:     --     Returns  string, number     --                  string, with detected link target, or entire     --                  number, with number of brackets, if found, or 2     local r1, r2 = WLink.getTarget( attempt );     if not r1 then         r1 = mw.text.trim( attempt );         r2 = 2;     end     if lonely then         local i = r1:find( "#", 1, true );         if i == 1 then             r1 = "";         elseif i then             r1 = r1:sub( 1, i - 1 );         end     end     return r1, r2; end -- target()  function WLink.ansiPercent( attempt, alter )     -- Convert string by ANSI encoding rather than UTF-8 encoding     -- Precondition:     --     attempt  -- string, with presumable ANSI characters     --     alter    -- string or nil, to use for spaces instead of %20     -- Postcondition:     --     Returns  string, encoded     local k, s;     local r = attempt;     if alter then         r = r:gsub( " ", alter );     end     for i = mw.ustring.len( r ), 1, -1 do         k = mw.ustring.codepoint( r, i, i );         if k <= 32  or  k > 126 then             if k > 255 then                 s = mw.ustring.sub( r, i, i );                 if k > 2047 then                     s = string.format( "%%%2X%%%2X%%%2X",                                        s:byte( 1, 1 ),                                        s:byte( 2, 2 ),                                        s:byte( 3, 3 ) );                 else                     s = string.format( "%%%2X%%%2X",                                        s:byte( 1, 1 ),                                        s:byte( 2, 2 ) );                 end             else                 s = string.format( "%%%2X", k );             end             r = string.format( "%s%s%s",                                mw.ustring.sub( r,  1,  i - 1 ),                                s,                                mw.ustring.sub( r,  i + 1 ) );         end     end -- for --i     r = mw.ustring.gsub(r, '^%*', '%%2A')     return r; end -- WLink.ansiPercent()  function WLink.formatURL( adjust )     -- Create bracketed link, if not yet     -- Precondition:     --     adjust  -- string, with URL or domain/path or bracketed link     -- Postcondition:     --     Returns  string, with bracketed link     --              false on invalid format     local r;     if type( adjust ) == "string" then         if WLink.isBracketedLink( adjust ) then             r = adjust;         else             local url = mw.text.trim( adjust );             local host;             utilURL();             host = URLutil.getHost( adjust );             if not host then                 url  = "http://" .. adjust;                 host = URLutil.getHost( url );             end             if host then                 local path = URLutil.getRelativePath( url );                 local show;                 if path == "/" then                     if not url:match( "/$" ) then                         url = url .. "/";                     end                     show = host;                 else                     local i = path:find( "#" );                     if i then                         path = path:sub( 1,  i - 1 );                     end                     show = host .. path;                 end                 r = string.format( "[%s %s]", url, show );             else                 r = adjust;             end         end     else         r = false;     end     return r; end -- WLink.formatURL()  function WLink.getArticleBase( attempt )     -- Retrieve generic article title, no fragment nor brackets     -- Precondition:     --     attempt  -- string, with wikilink or page title     --                         current page title, if missing     -- Postcondition:     --     Returns  string, with identified lemma, or all     --              false on invalid format     local r;     if attempt then         local m;         r, m = target( attempt, true );         if m ~= 2 then             r = false;         end     else         r = mw.title.getCurrentTitle().text;     end     if r then         local sub = r:match( "^(.*%S) *%(.+%)$" );         if sub then             r = sub;         end     end     return r; end -- WLink.getArticleBase()  function WLink.getBaseTitle( attempt )     -- Retrieve last segment in subpage, no fragment     -- Precondition:     --     attempt  -- string, with wikilink or page title     -- Postcondition:     --     Returns  string, with identified segment, or all     local r;     local s, m = target( attempt, true );     if m == 2 then         local sub = s:match( "/([^/]+)$" );         if sub then             r = sub;         else             r = s;         end     else         r = false;     end     return r; end -- WLink.getBaseTitle()  function WLink.getEscapedTitle( attempt )     -- Retrieve escaped link title     -- Precondition:     --     attempt  -- string, with presumable link title     -- Postcondition:     --     Returns  string, with suitable link title     local s = mw.text.trim( attempt );     return s:gsub( "\n", " " )             :gsub( "%[", "[" )             :gsub( "%]", "]" )             :gsub( "|",  "|" ); end -- WLink.getEscapedTitle()  function WLink.getExtension( attempt )     -- Retrieve media extension     -- Precondition:     --     attempt  -- string, with wikilink (media link) or page title     --                         if URL, PDF may be detected     -- Postcondition:     --     Returns  string, with detected downcased media type     --              false if no extension found     local r = false;     local s, m = target( attempt );     if m == 2 then         s = s:match( "%.(%a+)$" );         if s then             r = s:lower();         end     elseif s:upper():match( "[%./](PDF)%W?" ) then         r = "pdf";     end     return r; end -- WLink.getExtension()  function WLink.getFile( attempt )     -- Retrieve media page identifier     -- Precondition:     --     attempt  -- string, with wikilink (media link) or page title     -- Postcondition:     --     Returns  string, with detected file title     --                      no namespace nor project     --              false if no file found     local r = false;     local s, m = target( attempt );     if m == 2 then         local slow    = ":" .. s:lower();         local find = function ( a )                          local seek = string.format( ":%s:().+%%.%%a+$",                                                      a:lower() );                          local join = slow:find( seek );                          local ret;                          if join then                              ret = s:sub( join + #a + 1 );                          end                          return ret;                      end;         r = find( "file" );         if not r then             local trsl = mw.site.namespaces[6];             r = find( trsl.name );             if not r then                 trsl = trsl.aliases;                 for k, v in pairs( trsl ) do                     r = find( v );                     if r then                         break; -- for k, v                     end                 end -- for k, v             end         end     end     return r; end -- WLink.getFile()  function WLink.getFragment( attempt )     -- Retrieve fragment     -- Precondition:     --     attempt  -- string, with presumable fragment     -- Postcondition:     --     Returns  string, with detected fragment     --              false if no address found     local r = false;     local s, m = target( attempt );     if s then         local i = s:find( "#", 1, true );         if i then             if i > 1 then                 s = s:sub( i - 1 );                 i = 2;             end             if s:find( "&#", 1, true ) then                 s = mw.text.decode( s );                 i = s:find( "#", 1, true );                 if not i then                    s = "";                    i = 0;                 end             end             s = s:sub( i + 1 );             r = mw.text.trim( s );             if r == "" then                 r = false;             elseif m == 2 then                 r = r:gsub( "%.(%x%x)", "%%%1" )                      :gsub( "_", " " );                 r = mw.uri.decode( r, "PATH" );             end         end     end     return r; end -- WLink.getFragment()  function WLink.getLanguage( attempt )     -- Retrieve language project identifier     -- Precondition:     --     attempt  -- string, with wikilink or page title     -- Postcondition:     --     Returns  string, with detected downcased language identifier     --              false if no project language found     local r = false;     local s, m = WLink.getTarget( attempt );     if m == 2 then         local w = WLink.wikilink( s );         if w  and  w.lang then             r = w.lang;         end     end     return r; end -- WLink.getLanguage()  function WLink.getNamespace( attempt )     -- Retrieve namespace number     -- Precondition:     --     attempt  -- string, with wikilink or page title     -- Postcondition:     --     Returns  number, of detected namespace     --              false if no namespace found     local r = false;     local s, m = WLink.getTarget( attempt );     if m == 2 then         local w = WLink.wikilink( s );         if w  and  not w.lang  and  not w.project  and  w.ns then             r = w.ns;         end     end     return r; end -- WLink.getNamespace()  function WLink.getPlain( attempt )     -- Retrieve text with all links replaced by link titles     -- Precondition:     --     attempt  -- string, with wikitext     -- Postcondition:     --     Returns  string, with modified wikitext without links     local r = attempt;     local i = 1;     local j, k, n, lean, s, shift, space, suffix;     while ( true ) do         j = r:find( "[", i, true );         if j then             suffix = r:sub( j );             i      = j + 1;             lean   = ( r:byte( i, i ) == 91 );             if lean then                 s, k, n = contentWikilink( suffix );             else                 s, k, n = contentExtlink( suffix );             end             if s then                 if k > 1 then                     n      = n - k;                     i      = j + k;                     j      = i - 1;                     suffix = r:sub( j );                 end                 if lean then                     s, shift = extractWikilink( suffix );                     if s then                         space = s:match( "^([^:]+):" );                         if space then                             space = mw.site.namespaces[ space ];                             if space then                                 space = space.id;                             end                         end                         if space == 6  or  space == 14 then                             shift = "";                         elseif not shift then                             shift = s;                         end                     else                         s     = "";                         shift = "";                     end                 else                     s, shift = extractExtlink( suffix );                     if not s then                         s = "";                     end                     if not shift then                         shift = "";                     end                     i = i - 1;                 end                 if j > 1 then                     s = r:sub( 1, j - 1 );                 else                     s = "";                 end                 r = string.format( "%s%s%s",                                    s,  shift,  r:sub( n + i ) );                 i = i + #shift;             else                 break; -- while true             end         else             break; -- while true         end     end -- while true     return r; end -- WLink.getPlain()  function WLink.getProject( attempt )     -- Retrieve wikifarm project identifier     -- Precondition:     --     attempt  -- string, with wikilink or page title     -- Postcondition:     --     Returns  string, with detected downcased project identifier     --              false if no project identifier found     local r = false;     local s, m = WLink.getTarget( attempt );     if m == 2 then         local w = WLink.wikilink( s );         if w  and  w.project then             r = w.project;         end     end     return r; end -- WLink.getProject()  function WLink.getTarget( attempt )     -- Retrieve first target (wikilink or URL)     -- Precondition:     --     attempt  -- string, with presumable link somewhere     -- Postcondition:     --     Returns  string, number     --                  string, with first detected link target     --                  number, with number of brackets, if found     --              false if nothing found     local r1 = false;     local r2 = false;     local i  = attempt:find( "[", 1, true );     if i then         local m;         r1 = attempt:sub( i );         if r1:byte( 2, 2 ) == 91 then             m  = 2;             r1 = extractWikilink( r1 );         else             m  = 1;             r1 = extractExtlink( r1 );         end         if r1 then             r2 = m;         end     else         r1 = attempt:match( "%A?([hf]t?tps?://%S+)%s?" );         if r1 then             if utilURL().isResourceURL( r1 ) then                 r2 = 0;             else                 r1 = false;             end         else             r1 = false;         end     end     return r1, r2; end -- WLink.getTarget()  function WLink.getTargetPage( attempt )     -- Retrieve first target page (page name or URL of page)     -- Precondition:     --     attempt  -- string, with presumable link somewhere     -- Postcondition:     --     Returns  string, with first detected linked page     --              false if nothing found     local r1, r2 = WLink.getTarget( attempt );     if r1 then         local i = r1:find( "#", 1, true );         if i then             if i == 1 then                 r1 = false;             else                 r1 = mw.text.trim( r1:sub( 1,  i - 1 ) );             end         end     end     return r1, r2; end -- WLink.getTargetPage()  function WLink.getTitle( attempt )     -- Retrieve first link title (wikilink or URL), or wikilink target     -- Precondition:     --     attempt  -- string, with presumable link somewhere     -- Postcondition:     --     Returns  string, with first detected link target     --              false if nothing found     local r = false;     local i = attempt:find( "[", 1, true );     if i then         local s1, s2;         r = attempt:sub( i );         if r:byte( 2, 2 ) == 91 then             s1, s2 = extractWikilink( r );             if s2 then                 r = s2;             else                 r = s1;             end         else             s1, r = extractExtlink( r );         end     end     return r; end -- WLink.getTitle()  function WLink.getWeblink( attempt, anURLutil )     -- Retrieve bracketed link from resource URL     -- Precondition:     --     attempt    -- string, with URL, or something different     --     anURLutil  -- library module object, or nil     -- Postcondition:     --     Returns  string, with first detected link target     --              false if nothing found     local second = ".ac.co.go.gv.or.";     local r;     if type( anURLutil ) == "table" then         URLutil = anURLutil;     else         utilURL();     end     if URLutil.isResourceURL( attempt ) then         local site = URLutil.getAuthority( attempt );         local show;         if #attempt == #site then            site = site .. "/";         end         show = URLutil.getTop3domain( "//" .. site );         if show then             local scan   = "[%./](%a+)(%.%l%l%.)(%a+)$";             local search = "." .. show;             local s1, s2, s3 = search:match( scan );             if s2 then                 if not second:find( s2, 1, true ) then                     show = string.format( "%s.%s", s2, s3 );                 end             else                 show = false;             end         end         if not show then             show = URLutil.getTop2domain( "//" .. site );             if not show then                 show = URLutil.getHost( "//" .. site );             end         end         r = string.format( "[%s %s]", attempt, show );     else         r = attempt;     end     return r; end -- WLink.getWeblink()  function WLink.isBracketedLink( attempt )     -- Does attempt match a bracketed link?     -- Precondition:     --     attempt  -- string, with presumable link somewhere     -- Postcondition:     --     Returns  boolean     local r = false;     local i = attempt:find( "[", 1, true );     if i then         local s = attempt:sub( i );         if s:byte( 2, 2 ) == 91 then             s = extractWikilink( s );         else             s = extractExtlink( s );         end         if s then             r = true;         end     end     return r; end -- WLink.isBracketedLink()  function WLink.isBracketedURL( attempt )     -- Does attempt match a bracketed URL?     -- Precondition:     --     attempt  -- string, with presumable link somewhere     -- Postcondition:     --     Returns  boolean     local s, r = WLink.getTarget( attempt );     return ( r == 1 ); end -- WLink.isBracketedURL()  function WLink.isCategorization( attempt )     -- Does attempt match a categorization?     -- Precondition:     --     attempt  -- string, with presumable link somewhere     -- Postcondition:     --     Returns  boolean     local r = false;     local s, m = WLink.getTarget( attempt );     if m == 2 then         local w = WLink.wikilink( s );         if w  and  w.ns == 14               and  not ( w.lead or w.lang or w.project )               and  w.title ~= "" then             r = true;         end     end     return r; end -- WLink.isCategorization()  function WLink.isExternalLink( attempt )     -- Does attempt match an external link?     -- Precondition:     --     attempt  -- string, with presumable link somewhere     -- Postcondition:     --     Returns  boolean     local s, r = WLink.getTarget( attempt );     if r then         r = ( r < 2 );     end     return r; end -- WLink.isExternalLink()  function WLink.isInterlanguage( attempt )     -- Does attempt match an interlanguage link?     -- Precondition:     --     attempt  -- string, with presumable link somewhere     -- Postcondition:     --     Returns  boolean     local r = false;     local s, m = WLink.getTarget( attempt );     if m == 2 then         local w = WLink.wikilink( s );         if w and w.lang and not w.project and not w.lead              and  w.title ~= "" then             r = true;         end     end     return r; end -- WLink.isInterlanguage()  function WLink.isInterwiki( attempt )     -- Does attempt match an interwiki link within wikifarm?     -- Precondition:     --     attempt  -- string, with presumable link somewhere     -- Postcondition:     --     Returns  boolean     local r = false;     local s, m = WLink.getTarget( attempt );     if m == 2 then         local w = WLink.wikilink( s );         if w  and  ( w.lang or w.project )  and  w.title ~= "" then             r = true;         end     end     return r; end -- WLink.isInterwiki()  function WLink.isMedia( attempt )     -- Does attempt match a media translusion?     -- Precondition:     --     attempt  -- string, with presumable link somewhere     -- Postcondition:     --     Returns  boolean     local r = false;     local s, m = WLink.getTarget( attempt );     if m == 2 then         local w = WLink.wikilink( s );         if w  and  w.ns == 6            and  not ( w.lead or w.lang or w.project )            and  w.title ~= ""            and  WLink.getExtension( w.title ) then             r = true;         end     end     return r; end -- WLink.isMedia()  function WLink.isTitledLink( attempt )     -- Does attempt match a titled link?     -- Precondition:     --     attempt  -- string, with presumable link somewhere     -- Postcondition:     --     Returns  boolean     local r = false;     local i = attempt:find( "[", 1, true );     if i then         local c, n;         local s = attempt:sub( i );         if s:byte( 2, 2 ) == 91 then             n = s:find( "%]%]", 5 );             c = "|";         else             n = s:find( "%]", 8 );             c = "%s%S";         end         if n then             local m = s:find( c, 2 );             if m  and  m + 1 < n  and  WLink.getTarget( attempt ) then                 r = true;             end         end     end     return r; end -- WLink.isTitledLink()  function WLink.isValidLink( attempt )     -- Does attempt match a link?     -- Precondition:     --     attempt  -- string, with presumable link somewhere     -- Postcondition:     --     Returns  boolean     local s, r = WLink.getTarget( attempt );     if r then         r = true;     end     return r; end -- WLink.isValidLink()  function WLink.isWikilink( attempt )     -- Does attempt match a wikilink?     -- Precondition:     --     attempt  -- string, with presumable link somewhere     -- Postcondition:     --     Returns  boolean     local s, m = WLink.getTarget( attempt );     return ( m == 2 ); end -- WLink.isWikilink()  function WLink.wikilink( attempt )     -- Retrieve wikilink components     -- Precondition:     --     attempt  -- string, with presumable link     --                         expected to be enclosed in "" ""     --                         else wikilink     -- Postcondition:     --     Returns  table or false     --              table of assignments with { type, value}     --                       type is one of "lead",     --                          "project", "lang",     --                          "ns", "space", "title"     --              false if nothing found     local s = contentWikilink( attempt );     local got, n, r;     if not s then         s = attempt;     end     i = s:find( "|", 1, true );     if i then         s = s:sub( 1, i - 1 );     end     got = mw.text.split( s, ":" );     n   = table.maxn( got );     if n == 1 then         r = { title = mw.text.trim( s ) };     else         local j, k, o, v;         r = { title = "" };         if n > 4 then             k = 4;         else             k = n - 1;         end         j = k;         for i = 1, j do             s = mw.text.trim( got[ i ] );             if s ~= "" then                 o = mw.site.namespaces[ mw.text.trim( got[ i ] ) ];                 if o then                     r.ns    = o.id;                     r.space = o.name;                     k = i + 1;                     j = i - 1;                     break; -- for i                 end             end         end -- for i         for i = 1, j do             o, v = prefix( got[ i ],  ( i == 1 ) );             if o then                 if r[ o ] then                     k = i;                     break; -- for i                 else                     r[ o ] = v;                 end             else                 k = i;                 break; -- for i             end         end -- for i         for i = k, n do             r.title = r.title .. got[ i ];             if i < n then                 r.title = r.title .. ":";             end         end -- for i     end     if r.lead and        ( r.project  or  not r.title  or          ( not r.lang  and  r.ns ~= 6  and  r.ns ~= 14 ) ) then         r.lead = false;     end     return r; end -- WLink.wikilink()  function WLink.failsafe( assert )     -- Retrieve versioning and check for compliance     -- Precondition:     --     assert  -- string, with required version, or false     -- Postcondition:     --     Returns  string with appropriate version, or false     local r;     if assert  and  assert > WLink.serial then         r = false;     else         r = WLink.serial;     end     return r end -- WLink.failsafe()  local function Template( frame, action, leave, lone )     -- Run actual code from template transclusion     -- Precondition:     --     frame   -- object     --     action  -- string, with function name     --     leave   -- true: keep whitespace around     --     lone    -- true: permit call without parameters     -- Postcondition:     --     Return string; might be error message     local lucky = true;     local s = false;     local r = false;     local space;     for k, v in pairs( frame.args ) do         if k == 1 then             if leave then                 s = v;             else                 s = mw.text.trim( v );             end         elseif action == "ansiPercent"  and  k == "space" then             if v ~= "" then                 space = v;             end         elseif k ~= "template" then             lucky = false;             if r then                 r = r .. "|";             else                 r = "Unknown parameter: ";             end             r = string.format( "%s%s=", r, k );         end     end -- for k, v     if lucky then         if s or lone then             lucky, r = pcall( WLink[ action ],  s,  space );         else             r = "Parameter missing";             lucky = false;         end     end     if lucky then         if type( r ) == "boolean" then             if r then                 r = "1";             else                 r = "";             end         end     else         r = string.format( "%s", r );     end     return r; end -- Template()  -- Export local p = { };  p.ansiPercent = function ( frame )     return Template( frame, "ansiPercent" ); end p.formatURL = function ( frame )     return Template( frame, "formatURL" ); end p.getArticleBase = function ( frame )     return Template( frame, "getArticleBase", false, true ); end p.getBaseTitle = function ( frame )     return Template( frame, "getBaseTitle" ); end p.getEscapedTitle = function ( frame )     return Template( frame, "getEscapedTitle" ); end p.getExtension = function ( frame )     return Template( frame, "getExtension" ); end p.getFile = function ( frame )     return Template( frame, "getFile" ); end p.getFragment = function ( frame )     return Template( frame, "getFragment" ); end p.getInterwiki = function ( frame )     return Template( frame, "getInterwiki" ); end p.getLanguage = function ( frame )     return Template( frame, "getLanguage" ); end p.getNamespace = function ( frame )     return tostring( Template( frame, "getNamespace" ) ); end p.getPlain = function ( frame )     return Template( frame, "getPlain" ); end p.getProject = function ( frame )     return Template( frame, "getProject" ); end p.getTarget = function ( frame )     return Template( frame, "getTarget" ); end p.getTargetPage = function ( frame )     return Template( frame, "getTargetPage" ); end p.getTitle = function ( frame )     return Template( frame, "getTitle" ); end p.getWeblink = function ( frame )     return Template( frame, "getWeblink" ); end p.isBracketedLink = function ( frame )     return Template( frame, "isBracketedLink" ); end p.isBracketedURL = function ( frame )     return Template( frame, "isBracketedURL" ); end p.isCategorization = function ( frame )     return Template( frame, "isCategorization" ); end p.isExternalLink = function ( frame )     return Template( frame, "isExternalLink" ); end p.isInterlanguage = function ( frame )     return Template( frame, "isInterlanguage" ); end p.isInterwiki = function ( frame )     return Template( frame, "isInterwiki" ); end p.isMedia = function ( frame )     return Template( frame, "isMedia" ); end p.isTitledLink = function ( frame )     return Template( frame, "isTitledLink" ); end p.isValidLink = function ( frame )     return Template( frame, "isValidLink" ); end p.isWeblink = function ( frame )     return Template( frame, "isWeblink" ); end p.isWikilink = function ( frame )     return Template( frame, "isWikilink" ); end p.failsafe = function ( frame )     local since = frame.args[ 1 ];     if since then         since = mw.text.trim( since );         if since == "" then             since = false;         end     end     return WLink.failsafe( since ) or ""; end p.WLink = function ()     return WLink; end  return p;