<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://stockhub.co/index.php?action=history&amp;feed=atom&amp;title=Module%3ASandbox%2FPHansen%2FURLutil</id>
	<title>Module:Sandbox/PHansen/URLutil - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://stockhub.co/index.php?action=history&amp;feed=atom&amp;title=Module%3ASandbox%2FPHansen%2FURLutil"/>
	<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Sandbox/PHansen/URLutil&amp;action=history"/>
	<updated>2026-04-21T09:02:52Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://stockhub.co/index.php?title=Module:Sandbox/PHansen/URLutil&amp;diff=145962&amp;oldid=prev</id>
		<title>imported&gt;PHansen: ..created</title>
		<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Sandbox/PHansen/URLutil&amp;diff=145962&amp;oldid=prev"/>
		<updated>2015-01-13T16:49:19Z</updated>

		<summary type="html">&lt;p&gt;..created&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;-- From [[:de:Modul:URLutil]]&lt;br /&gt;
-- Via [[:en:User:PHansen/URLutil]] &lt;br /&gt;
&lt;br /&gt;
-- Descriptions&lt;br /&gt;
-- en: [[:de:Wikipedia:Lua/Modul/URLutil/en]]&lt;br /&gt;
-- de: [[:de:Wikipedia:Lua/Modul/URLutil/de]]&lt;br /&gt;
&lt;br /&gt;
-- Test : [[:de:Wikipedia:Lua/Modul/URLutil/Test]]&lt;br /&gt;
-- Wikidata: [[:d:Q10859193]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--[=[ URLutil 2014-09-20&lt;br /&gt;
Utilities for URL etc. on www.&lt;br /&gt;
* getAuthority()&lt;br /&gt;
* getFragment()&lt;br /&gt;
* getHost()&lt;br /&gt;
* getLocation()&lt;br /&gt;
* getPath()&lt;br /&gt;
* getPort()&lt;br /&gt;
* getQuery()&lt;br /&gt;
* getQueryTable()&lt;br /&gt;
* getRelativePath()&lt;br /&gt;
* getScheme()&lt;br /&gt;
* getTLD()&lt;br /&gt;
* getTop2domain()&lt;br /&gt;
* getTop3domain()&lt;br /&gt;
* isAuthority()&lt;br /&gt;
* isDomain()&lt;br /&gt;
* isDomainExample()&lt;br /&gt;
* isDomainInt()&lt;br /&gt;
* isHost()&lt;br /&gt;
* isIP()&lt;br /&gt;
* isIPlocal()&lt;br /&gt;
* isIPv4()&lt;br /&gt;
* isIPv6()&lt;br /&gt;
* isMailAddress()&lt;br /&gt;
* isMailLink()&lt;br /&gt;
* isProtocolDialog()&lt;br /&gt;
* isProtocolWiki()&lt;br /&gt;
* isResourceURL()&lt;br /&gt;
* isSuspiciousURL()&lt;br /&gt;
* isUnescapedURL()&lt;br /&gt;
* isWebURL()&lt;br /&gt;
* wikiEscapeURL()&lt;br /&gt;
Only [[dotted decimal]] notation for IPv4 supported.&lt;br /&gt;
Does not support dotted hexadecimal, dotted octal, or single-number formats.&lt;br /&gt;
IPv6 URL (bracketed) not yet implemented; might need Wikintax escaping anyway.&lt;br /&gt;
]=]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- table for export&lt;br /&gt;
local URLutil = {}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.getURIScheme = function ( uri )&lt;br /&gt;
    if type( uri ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
        local prot, colon, slashes = uri:match( &amp;quot;^%s*([a-zA-Z]*)(:?)(/?/?)&amp;quot; )&lt;br /&gt;
        if #colon == 1 and #prot &amp;gt;= 2 then&lt;br /&gt;
            return prot:lower()&lt;br /&gt;
        elseif #slashes == 2 and #prot == 0 then&lt;br /&gt;
            return &amp;quot;//&amp;quot;&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return false&lt;br /&gt;
end -- getURIScheme()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local getTopDomain = function ( url, mode )&lt;br /&gt;
    local r = URLutil.getHost( url )&lt;br /&gt;
    if r then&lt;br /&gt;
        local pattern = &amp;quot;[%w%%]+%.%a[%w-]*%a)$&amp;quot;&lt;br /&gt;
        if mode == 3 then&lt;br /&gt;
            pattern = &amp;quot;[%w%%]+%.&amp;quot; .. pattern&lt;br /&gt;
        end&lt;br /&gt;
        r = mw.ustring.match( &amp;quot;.&amp;quot; .. r,  &amp;quot;%.(&amp;quot; .. pattern )&lt;br /&gt;
        if not r then&lt;br /&gt;
            r = false&lt;br /&gt;
        end&lt;br /&gt;
    else&lt;br /&gt;
        r = false&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- getTopDomain()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.getAuthority = function ( url )&lt;br /&gt;
    local r&lt;br /&gt;
    if type( url ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
        local colon, host, port&lt;br /&gt;
        local pattern = &amp;quot;^%s*%w*:?//([%w%.%%-]+)(:?)([%d]*)/&amp;quot;&lt;br /&gt;
        local s = mw.text.decode( url )&lt;br /&gt;
        local i = s:find( &amp;quot;#&amp;quot;, 6, true )&lt;br /&gt;
        if i then&lt;br /&gt;
            s = s:sub( 1,  i - 1 )  ..  &amp;quot;/&amp;quot;&lt;br /&gt;
        else&lt;br /&gt;
            s = s .. &amp;quot;/&amp;quot;&lt;br /&gt;
        end&lt;br /&gt;
        host, colon, port = mw.ustring.match( s, pattern )&lt;br /&gt;
        if URLutil.isHost( host ) then&lt;br /&gt;
            host = mw.ustring.lower( host )&lt;br /&gt;
            if colon == &amp;quot;:&amp;quot; then&lt;br /&gt;
                if port:find( &amp;quot;^[1-9]&amp;quot; ) then&lt;br /&gt;
                    r = ( host .. &amp;quot;:&amp;quot; .. port )&lt;br /&gt;
                end&lt;br /&gt;
            elseif #port == 0 then&lt;br /&gt;
                r = host&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    else&lt;br /&gt;
        r = false&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- URLutil.getAuthority()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.getFragment = function ( url, decode )&lt;br /&gt;
    local r&lt;br /&gt;
    if type( url ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
        local s = mw.text.decode( url )&lt;br /&gt;
        local i = s:find( &amp;quot;#&amp;quot;, 1, true )&lt;br /&gt;
        if i then&lt;br /&gt;
            r = mw.text.trim( s:sub( i ) ):sub( 2 )&lt;br /&gt;
            if type( decode ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
                local encoding = mw.text.trim( decode )&lt;br /&gt;
                local launch&lt;br /&gt;
                if encoding == &amp;quot;%&amp;quot; then&lt;br /&gt;
                    launch = true&lt;br /&gt;
                elseif encoding == &amp;quot;WIKI&amp;quot; then&lt;br /&gt;
                    r = r:gsub( &amp;quot;%.(%x%x)&amp;quot;, &amp;quot;%%%1&amp;quot; )&lt;br /&gt;
                         :gsub( &amp;quot;_&amp;quot;, &amp;quot; &amp;quot; )&lt;br /&gt;
                    launch = true&lt;br /&gt;
                end&lt;br /&gt;
                if launch then&lt;br /&gt;
                    r = mw.uri.decode( r, &amp;quot;PATH&amp;quot; )&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        else&lt;br /&gt;
            r = false&lt;br /&gt;
        end&lt;br /&gt;
    else&lt;br /&gt;
        r = nil&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- URLutil.getFragment()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.getHost = function ( url )&lt;br /&gt;
    local r = URLutil.getAuthority( url )&lt;br /&gt;
    if r then&lt;br /&gt;
        r = mw.ustring.match( r, &amp;quot;^([%w%.%%-]+):?[%d]*$&amp;quot; )&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- URLutil.getHost()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.getLocation = function ( url )&lt;br /&gt;
    local r&lt;br /&gt;
    if type( url ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
        r = mw.text.trim( url )&lt;br /&gt;
        if r == &amp;quot;&amp;quot; then&lt;br /&gt;
            r = false&lt;br /&gt;
        else&lt;br /&gt;
            local i&lt;br /&gt;
            r = mw.text.decode( r )&lt;br /&gt;
            i = r:find( &amp;quot;#&amp;quot;, 1, true )&lt;br /&gt;
            if i then&lt;br /&gt;
                if i == 1 then&lt;br /&gt;
                    r = false&lt;br /&gt;
                else&lt;br /&gt;
                    r = r:sub( 1,  i - 1 )&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    else&lt;br /&gt;
        r = nil&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- URLutil.getLocation()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.getPath = function ( url )&lt;br /&gt;
    local r = URLutil.getRelativePath( url )&lt;br /&gt;
    if r then&lt;br /&gt;
        local s = r:match( &amp;quot;^([^%?]*)%?&amp;quot; )&lt;br /&gt;
        if s then&lt;br /&gt;
            r = s&lt;br /&gt;
        end&lt;br /&gt;
        s = r:match( &amp;quot;^([^#]*)#&amp;quot; )&lt;br /&gt;
        if s then&lt;br /&gt;
            r = s&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- URLutil.getPath()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.getPort = function ( url )&lt;br /&gt;
    local r = URLutil.getAuthority( url )&lt;br /&gt;
    if r then&lt;br /&gt;
        r = r:match( &amp;quot;:([1-9][0-9]*)$&amp;quot; )&lt;br /&gt;
        if r then&lt;br /&gt;
            r = tonumber( r )&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 -- URLutil.getPort()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.getQuery = function ( url, key, separator )&lt;br /&gt;
    local r = URLutil.getLocation( url )&lt;br /&gt;
    if r then&lt;br /&gt;
        r = r:match( &amp;quot;^[^%?]*%?(.+)$&amp;quot; )&lt;br /&gt;
        if r then&lt;br /&gt;
            if type( key ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
                local single = mw.text.trim( key )&lt;br /&gt;
                local sep = &amp;quot;&amp;amp;&amp;quot;&lt;br /&gt;
                local s, scan&lt;br /&gt;
                if type( separator ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
                    s = mw.text.trim( separator )&lt;br /&gt;
                    if s:match( &amp;quot;^[&amp;amp;;,/]$&amp;quot; ) then&lt;br /&gt;
                        sep = s&lt;br /&gt;
                    end&lt;br /&gt;
                end&lt;br /&gt;
                s = string.format( &amp;quot;%s%s%s&amp;quot;, sep, r, sep )&lt;br /&gt;
                scan = string.format( &amp;quot;%s%s=([^%s]*)%s&amp;quot;,&lt;br /&gt;
                                      sep, key, sep, sep )&lt;br /&gt;
                r = s:match( scan )&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
        if not r then&lt;br /&gt;
            r = false&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- URLutil.getQuery()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.getQueryTable = function ( url, separator )&lt;br /&gt;
    local r = URLutil.getQuery( url )&lt;br /&gt;
    if r then&lt;br /&gt;
        local sep = &amp;quot;&amp;amp;&amp;quot;&lt;br /&gt;
        local n, pairs, s, set&lt;br /&gt;
        if type( separator ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
            s = mw.text.trim( separator )&lt;br /&gt;
            if s:match( &amp;quot;^[&amp;amp;;,/]$&amp;quot; ) then&lt;br /&gt;
                sep = s&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
        pairs = mw.text.split( r, sep, true )&lt;br /&gt;
        n = #pairs&lt;br /&gt;
        r = { }&lt;br /&gt;
        for i = 1, n do&lt;br /&gt;
            s = pairs[ i ]&lt;br /&gt;
            if s:find( &amp;quot;=&amp;quot;, 2, true ) then&lt;br /&gt;
                s, set = s:match( &amp;quot;^([^=]+)=(.*)$&amp;quot; )&lt;br /&gt;
                if s then&lt;br /&gt;
                    r[ s ] = set&lt;br /&gt;
                end&lt;br /&gt;
            else&lt;br /&gt;
                r[ s ] = false&lt;br /&gt;
            end&lt;br /&gt;
        end -- for i&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- URLutil.getQueryTable()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.getRelativePath = function ( url )&lt;br /&gt;
    local r&lt;br /&gt;
    if type( url ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
        local s = url:match( &amp;quot;^%s*[a-zA-Z]*://(.*)$&amp;quot; )&lt;br /&gt;
        if s then&lt;br /&gt;
            s = s:match( &amp;quot;[^/]+(/.*)$&amp;quot; )&lt;br /&gt;
        else&lt;br /&gt;
            local x&lt;br /&gt;
            x, s = url:match( &amp;quot;^%s*(/?)(/.*)$&amp;quot; )&lt;br /&gt;
            if x == &amp;quot;/&amp;quot; then&lt;br /&gt;
                s = s:match( &amp;quot;/[^/]+(/.*)$&amp;quot; )&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
        if s then&lt;br /&gt;
            r = mw.text.trim( s )&lt;br /&gt;
        elseif URLutil.isResourceURL( url ) then&lt;br /&gt;
            r = &amp;quot;/&amp;quot;&lt;br /&gt;
        else&lt;br /&gt;
            r = false&lt;br /&gt;
        end&lt;br /&gt;
    else&lt;br /&gt;
        r = nil&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- URLutil.getRelativePath()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.getScheme = function ( url )&lt;br /&gt;
    local r&lt;br /&gt;
    if type( url ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
        local pattern = &amp;quot;^%s*([a-zA-Z]*)(:?)(//)&amp;quot;&lt;br /&gt;
        local prot, colon, slashes = url:match( pattern )&lt;br /&gt;
        r = false&lt;br /&gt;
        if slashes == &amp;quot;//&amp;quot; then&lt;br /&gt;
            if colon == &amp;quot;:&amp;quot; then&lt;br /&gt;
                if #prot &amp;gt; 2 then&lt;br /&gt;
                    r = prot:lower() .. &amp;quot;://&amp;quot;&lt;br /&gt;
                end&lt;br /&gt;
            elseif #prot == 0 then&lt;br /&gt;
                r = &amp;quot;//&amp;quot;&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    else&lt;br /&gt;
        r = nil&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- URLutil.getScheme()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.getTLD = function ( url )&lt;br /&gt;
    local r = URLutil.getHost( url )&lt;br /&gt;
    if r then&lt;br /&gt;
        r = mw.ustring.match( r, &amp;quot;[%w]+%.(%a[%w-]*%a)$&amp;quot; )&lt;br /&gt;
        if not r then&lt;br /&gt;
            r = false&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- URLutil.getTLD()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.getTop2domain = function ( url )&lt;br /&gt;
    return getTopDomain( url, 2 )&lt;br /&gt;
end -- URLutil.getTop2domain()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.getTop3domain = function ( url )&lt;br /&gt;
    return getTopDomain( url, 3 )&lt;br /&gt;
end -- URLutil.getTop3domain()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.isAuthority = function ( s )&lt;br /&gt;
    local r&lt;br /&gt;
    if type( s ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
        local pattern = &amp;quot;^%s*([%w%.%%-]+)(:?)(%d*)%s*$&amp;quot;&lt;br /&gt;
        local host, colon, port = mw.ustring.match( s, pattern )&lt;br /&gt;
        if colon == &amp;quot;:&amp;quot; then&lt;br /&gt;
            port = port:match( &amp;quot;^[1-9][0-9]*$&amp;quot; )&lt;br /&gt;
            if type( port ) ~= &amp;quot;string&amp;quot; then&lt;br /&gt;
                r = false&lt;br /&gt;
            end&lt;br /&gt;
        elseif port ~= &amp;quot;&amp;quot; then&lt;br /&gt;
            r = false&lt;br /&gt;
        end&lt;br /&gt;
        r = URLutil.isHost( host )&lt;br /&gt;
    else&lt;br /&gt;
        r = nil&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- URLutil.isAuthority()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.isDomain = function ( s )&lt;br /&gt;
    local r&lt;br /&gt;
    if type( s ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
        local scan = &amp;quot;^%s*([%w%.%%-]+%w)%.(%a[%w-]*%a)%s*$&amp;quot;&lt;br /&gt;
        local scope&lt;br /&gt;
        s, scope = mw.ustring.match( s, scan )&lt;br /&gt;
        if type( s ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
            if mw.ustring.find( s, &amp;quot;^%w&amp;quot; ) then&lt;br /&gt;
                if mw.ustring.find( s, &amp;quot;..&amp;quot;, 1, true ) then&lt;br /&gt;
                    r = false&lt;br /&gt;
                else&lt;br /&gt;
                    r = true&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    else&lt;br /&gt;
        r = nil&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- URLutil.isDomain()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.isDomainExample = function ( url )&lt;br /&gt;
    -- RFC 2606: example.com example.net example.org example.edu&lt;br /&gt;
    local r = getTopDomain( url, 2 )&lt;br /&gt;
    if r then&lt;br /&gt;
        local s = r:lower():match( &amp;quot;^example%.([a-z][a-z][a-z])$&amp;quot; )&lt;br /&gt;
        if s then&lt;br /&gt;
            r = ( s == &amp;quot;com&amp;quot; or&lt;br /&gt;
                  s == &amp;quot;edu&amp;quot; or&lt;br /&gt;
                  s == &amp;quot;net&amp;quot; or&lt;br /&gt;
                  s == &amp;quot;org&amp;quot; )&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 -- URLutil.isDomainExample()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.isDomainInt = function ( url )&lt;br /&gt;
    -- Internationalized Domain Name (Punycode)&lt;br /&gt;
    local r = URLutil.getHost( url )&lt;br /&gt;
    if r then&lt;br /&gt;
        if r:match( &amp;quot;^[!-~]+$&amp;quot; ) then&lt;br /&gt;
            local s = &amp;quot;.&amp;quot; .. r&lt;br /&gt;
            if s:find( &amp;quot;.xn--&amp;quot;, 1, true ) then&lt;br /&gt;
                r = true&lt;br /&gt;
            else&lt;br /&gt;
                r = false&lt;br /&gt;
            end&lt;br /&gt;
        else&lt;br /&gt;
            r = true&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- URLutil.isDomainInt()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.isHost = function ( s )&lt;br /&gt;
    return URLutil.isDomain( s ) or URLutil.isIP( s )&lt;br /&gt;
end -- URLutil.isHost()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.isIP = function ( s )&lt;br /&gt;
    return URLutil.isIPv4( s ) and 4 or URLutil.isIPv6( s ) and 6&lt;br /&gt;
end -- URLutil.isIP()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.isIPlocal = function ( s )&lt;br /&gt;
    -- IPv4 according to RFC 1918, RFC 1122; even any 0.0.0.0 (RFC 5735)&lt;br /&gt;
    local r = false&lt;br /&gt;
    local num = s:match( &amp;quot;^ *([01][0-9]*)%.&amp;quot; )&lt;br /&gt;
    if num then&lt;br /&gt;
        num = tonumber( num )&lt;br /&gt;
        if num == 0 then&lt;br /&gt;
            r = s:match( &amp;quot;^ *0+%.[0-9]+%.[0-9]+%.[0-9]+ *$&amp;quot; )&lt;br /&gt;
        elseif num == 10  or  num == 127 then&lt;br /&gt;
            -- loopback; private/local host: 127.0.0.1&lt;br /&gt;
            r = URLutil.isIPv4( s )&lt;br /&gt;
        elseif num == 169 then&lt;br /&gt;
            -- 169.254.*.*&lt;br /&gt;
        elseif num == 172 then&lt;br /&gt;
            -- 172.(16...31).*.*&lt;br /&gt;
            num = s:match( &amp;quot;^ *0*172%.([0-9]+)%.&amp;quot; )&lt;br /&gt;
            if num then&lt;br /&gt;
                num = tonumber( num )&lt;br /&gt;
                if num &amp;gt;= 16  and  num &amp;lt;= 31 then&lt;br /&gt;
                    r = URLutil.isIPv4( s )&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        elseif beg == 192 then&lt;br /&gt;
            -- 192.168.*.*&lt;br /&gt;
            num = s:match( &amp;quot;^ *0*192%.([0-9]+)%.&amp;quot; )&lt;br /&gt;
            if num then&lt;br /&gt;
                num = tonumber( num )&lt;br /&gt;
                if num == 168 then&lt;br /&gt;
                    r = URLutil.isIPv4( s )&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    if r then&lt;br /&gt;
        r = true&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- URLutil.isIPlocal()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.isIPv4 = function ( s )&lt;br /&gt;
    local function legal( n )&lt;br /&gt;
              return ( tonumber( n ) &amp;lt; 256 )&lt;br /&gt;
          end&lt;br /&gt;
    local r = false&lt;br /&gt;
    if type( s ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
        local p1, p2, p3, p4 = s:match( &amp;quot;^%s*([1-9][0-9]?[0-9]?)%.([12]?[0-9]?[0-9])%.([12]?[0-9]?[0-9])%.([12]?[0-9]?[0-9])%s*$&amp;quot; )&lt;br /&gt;
        if p1 and p2 and p3 and p4 then&lt;br /&gt;
            r = legal( p1 ) and legal( p2 ) and legal( p3 ) and legal( p4 )&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end -- URLutil.isIPv4()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.isIPv6 = function ( s )&lt;br /&gt;
    local dcolon, groups&lt;br /&gt;
    if type( s ) ~= &amp;quot;string&amp;quot;&lt;br /&gt;
        or s:len() == 0&lt;br /&gt;
        or s:find( &amp;quot;[^:%x]&amp;quot; ) -- only colon and hex digits are legal chars&lt;br /&gt;
        or s:find( &amp;quot;^:[^:]&amp;quot; ) -- can begin or end with :: but not with single :&lt;br /&gt;
        or s:find( &amp;quot;[^:]:$&amp;quot; )&lt;br /&gt;
        or s:find( &amp;quot;:::&amp;quot; )&lt;br /&gt;
    then&lt;br /&gt;
        return false&lt;br /&gt;
    end&lt;br /&gt;
    s = mw.text.trim( s )&lt;br /&gt;
    s, dcolon = s:gsub( &amp;quot;::&amp;quot;, &amp;quot;:&amp;quot; )&lt;br /&gt;
    if dcolon &amp;gt; 1 then&lt;br /&gt;
        return false&lt;br /&gt;
    end -- at most one ::&lt;br /&gt;
    s = s:gsub( &amp;quot;^:?&amp;quot;, &amp;quot;:&amp;quot; ) -- prepend : if needed, upper&lt;br /&gt;
    s, groups = s:gsub( &amp;quot;:%x%x?%x?%x?&amp;quot;, &amp;quot;&amp;quot; ) -- remove valid groups, and count them&lt;br /&gt;
    return ( ( dcolon == 1 and groups &amp;lt; 8 ) or&lt;br /&gt;
             ( dcolon == 0 and groups == 8 ) )&lt;br /&gt;
        and ( s:len() == 0 or ( dcolon == 1 and s == &amp;quot;:&amp;quot; ) ) -- might be one dangling : if original ended with ::&lt;br /&gt;
end -- URLutil.isIPv6()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.isMailAddress = function ( s )&lt;br /&gt;
    if type( s ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
        s = mw.ustring.match( s, &amp;quot;^%s*[%w%.%%_-]+@([%w%.%%-]+)%s*$&amp;quot; )&lt;br /&gt;
        return URLutil.isDomain( s )&lt;br /&gt;
    end&lt;br /&gt;
    return false&lt;br /&gt;
end -- URLutil.isMailAddress()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.isMailLink = function ( s )&lt;br /&gt;
    if type( s ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
        local addr&lt;br /&gt;
        s, addr = mw.ustring.match( s, &amp;quot;^%s*([Mm][Aa][Ii][Ll][Tt][Oo]):(%S[%w%.%%_-]*@[%w%.%%-]+)%s*$&amp;quot; )&lt;br /&gt;
        if type( s ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
            if s:lower() == &amp;quot;mailto&amp;quot; then&lt;br /&gt;
                return URLutil.isMailAddress( addr )&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return false&lt;br /&gt;
end -- URLutil.isMailLink()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function isProtocolAccepted( prot, supplied )&lt;br /&gt;
    if type( prot ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
        local scheme, colon, slashes = mw.ustring.match( prot, &amp;quot;^%s*([a-zA-Z]*)(:?)(/?/?)%s*$&amp;quot; )&lt;br /&gt;
        if slashes ~= &amp;quot;/&amp;quot; then&lt;br /&gt;
            if scheme == &amp;quot;&amp;quot; then&lt;br /&gt;
                if colon ~= &amp;quot;:&amp;quot; and slashes == &amp;quot;//&amp;quot; then&lt;br /&gt;
                    return true&lt;br /&gt;
                end&lt;br /&gt;
             elseif colon == &amp;quot;:&amp;quot; or slashes == &amp;quot;&amp;quot; then&lt;br /&gt;
                local s = supplied:match( &amp;quot; &amp;quot; .. scheme:lower() .. &amp;quot; &amp;quot; )&lt;br /&gt;
                if type( s ) == &amp;quot;string&amp;quot; then&lt;br /&gt;
                    return true&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return false&lt;br /&gt;
end -- isProtocolAccepted()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.isProtocolMW = function ( prot )&lt;br /&gt;
    return isProtocolAccepted( prot,&lt;br /&gt;
                               &amp;quot; http https ftp ftps ssh sftp irc ircs xmpp sip sips gopher telnet nntp worldwind mailto tel sms news svn git mms bitcoin magnet urn geo &amp;quot; )&lt;br /&gt;
end -- URLutil.isProtocolMW()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.isProtocolDialog = function ( prot )&lt;br /&gt;
    return isProtocolAccepted( prot, &amp;quot; mailto irc ircs ssh telnet &amp;quot; )&lt;br /&gt;
end -- URLutil.isProtocolDialog()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.isProtocolWiki = function ( prot )&lt;br /&gt;
    return isProtocolAccepted( prot,&lt;br /&gt;
                               &amp;quot; ftp ftps git http https nntp sftp svn worldwind &amp;quot; )&lt;br /&gt;
end -- URLutil.isProtocolWiki()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.isResourceURL = function ( url )&lt;br /&gt;
    local scheme = URLutil.getScheme( url )&lt;br /&gt;
    if scheme then&lt;br /&gt;
        local s = &amp;quot; // http:// https:// ftp:// sftp:// &amp;quot;&lt;br /&gt;
        s = s:find( string.format( &amp;quot; %s &amp;quot;, scheme ) )&lt;br /&gt;
        if s then&lt;br /&gt;
            if URLutil.getAuthority( url ) then&lt;br /&gt;
                if not url:match( &amp;quot;%S%s+%S&amp;quot; ) then&lt;br /&gt;
                    return true&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return false&lt;br /&gt;
end -- URLutil.isResourceURL()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.isSuspiciousURL = function ( url )&lt;br /&gt;
    if URLutil.isResourceURL( url ) then&lt;br /&gt;
        local s = URLutil.getAuthority( url )&lt;br /&gt;
        local pat = &amp;quot;[%[|%]&amp;quot; ..&lt;br /&gt;
                    mw.ustring.char( 8201, 45, 8207, 8234, 45, 8239, 8288 )&lt;br /&gt;
                    .. &amp;quot;]&amp;quot;&lt;br /&gt;
        if s:find( &amp;quot;@&amp;quot; )&lt;br /&gt;
           or url:find( &amp;quot;&amp;#039;&amp;#039;&amp;quot; )&lt;br /&gt;
           or url:find( pat )&lt;br /&gt;
           or url:find( &amp;quot;[%.,]$&amp;quot; ) then&lt;br /&gt;
            return true&lt;br /&gt;
        end&lt;br /&gt;
        -- TODO  zero width character ??&lt;br /&gt;
        return false&lt;br /&gt;
    end&lt;br /&gt;
    return true&lt;br /&gt;
end -- URLutil.isSuspiciousURL()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.isUnescapedURL = function ( url, trailing )&lt;br /&gt;
    if type( trailing ) ~= &amp;quot;string&amp;quot; then&lt;br /&gt;
        if URLutil.isWebURL( url ) then&lt;br /&gt;
            if url:match( &amp;quot;[%[|%]]&amp;quot; ) then&lt;br /&gt;
                return true&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return false&lt;br /&gt;
end -- URLutil.isUnescapedURL()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.isWebURL = function ( url )&lt;br /&gt;
    if URLutil.getScheme( url ) and URLutil.getAuthority( url ) then&lt;br /&gt;
        if not url:match( &amp;quot;%S%s+%S&amp;quot; ) then&lt;br /&gt;
            return true&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    return false&lt;br /&gt;
end -- URLutil.isWebURL()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
URLutil.wikiEscapeURL = function ( url )&lt;br /&gt;
    if url:find( &amp;quot;[%[|%]]&amp;quot; ) then&lt;br /&gt;
        local n&lt;br /&gt;
        url, n = url:gsub( &amp;quot;%[&amp;quot;, &amp;quot;&amp;amp;#91;&amp;quot; )&lt;br /&gt;
                    :gsub( &amp;quot;|&amp;quot;, &amp;quot;&amp;amp;#124;&amp;quot; )&lt;br /&gt;
                    :gsub( &amp;quot;%]&amp;quot;, &amp;quot;&amp;amp;#93;&amp;quot; )&lt;br /&gt;
    end&lt;br /&gt;
    return url&lt;br /&gt;
end -- URLutil.wikiEscapeURL()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Provide template access and expose URLutil table to require&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
function p.getURIScheme( frame )&lt;br /&gt;
    return URLutil.getURIScheme( frame.args[ 1 ] ) or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.getAuthority( frame )&lt;br /&gt;
    return URLutil.getAuthority( frame.args[ 1 ] ) or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.getFragment( frame )&lt;br /&gt;
    local r = URLutil.getFragment( frame.args[ 1 ], frame.args[ 2 ] )&lt;br /&gt;
    if r then&lt;br /&gt;
        r = &amp;quot;#&amp;quot; .. r&lt;br /&gt;
    else&lt;br /&gt;
        r = &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end&lt;br /&gt;
function p.getHost( frame )&lt;br /&gt;
    return URLutil.getHost( frame.args[ 1 ] ) or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.getLocation( frame )&lt;br /&gt;
    return URLutil.getLocation( frame.args[ 1 ] ) or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.getPath( frame )&lt;br /&gt;
    return URLutil.getPath( frame.args[ 1 ] ) or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.getPort( frame )&lt;br /&gt;
    return URLutil.getPort( frame.args[ 1 ] ) or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.getQuery( frame )&lt;br /&gt;
    local r&lt;br /&gt;
    local key = frame.args[ 2 ]&lt;br /&gt;
    if key then&lt;br /&gt;
        key = mw.text.trim( key )&lt;br /&gt;
        if key == &amp;quot;&amp;quot; then&lt;br /&gt;
            key = nil&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
    r = URLutil.getQuery( frame.args[ 1 ], key, frame.args[ 3 ] )&lt;br /&gt;
    if r then&lt;br /&gt;
        if not key then&lt;br /&gt;
            r = &amp;quot;?&amp;quot; .. r&lt;br /&gt;
        end&lt;br /&gt;
    else&lt;br /&gt;
        r = &amp;quot;&amp;quot;&lt;br /&gt;
    end&lt;br /&gt;
    return r&lt;br /&gt;
end&lt;br /&gt;
function p.getRelativePath( frame )&lt;br /&gt;
    return URLutil.getRelativePath( frame.args[ 1 ] ) or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.getScheme( frame )&lt;br /&gt;
    return URLutil.getScheme( frame.args[ 1 ] ) or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.getTLD( frame )&lt;br /&gt;
    return URLutil.getTLD( frame.args[ 1 ] ) or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.getTop2domain( frame )&lt;br /&gt;
    return URLutil.getTop2domain( frame.args[ 1 ] ) or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.getTop3domain( frame )&lt;br /&gt;
    return URLutil.getTop3domain( frame.args[ 1 ] ) or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.isAuthority( frame )&lt;br /&gt;
    return URLutil.isAuthority( frame.args[ 1 ] ) and &amp;quot;1&amp;quot; or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.isDomain( frame )&lt;br /&gt;
    return URLutil.isDomain( frame.args[ 1 ] ) and &amp;quot;1&amp;quot; or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.isDomainExample( frame )&lt;br /&gt;
    return URLutil.isDomainExample( frame.args[ 1 ] ) and &amp;quot;1&amp;quot; or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.isDomainInt( frame )&lt;br /&gt;
    return URLutil.isDomainInt( frame.args[ 1 ] ) and &amp;quot;1&amp;quot; or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.isHost( frame )&lt;br /&gt;
    return URLutil.isHost( frame.args[ 1 ] ) and &amp;quot;1&amp;quot; or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.isIP( frame )&lt;br /&gt;
    return URLutil.isIP( frame.args[ 1 ] ) or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.isIPlocal( frame )&lt;br /&gt;
    return URLutil.isIPlocal( frame.args[ 1 ] ) and &amp;quot;1&amp;quot; or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.isIPv4( frame )&lt;br /&gt;
    return URLutil.isIPv4( frame.args[ 1 ] ) and &amp;quot;1&amp;quot; or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.isIPv6( frame )&lt;br /&gt;
    return URLutil.isIPv6( frame.args[ 1 ] ) and &amp;quot;1&amp;quot; or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.isMailAddress( frame )&lt;br /&gt;
    return URLutil.isMailAddress( frame.args[ 1 ] ) and &amp;quot;1&amp;quot; or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.isMailLink( frame )&lt;br /&gt;
    return URLutil.isMailLink( frame.args[ 1 ] ) and &amp;quot;1&amp;quot; or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.isProtocolMW( frame )&lt;br /&gt;
    return URLutil.isProtocolMW( frame.args[ 1 ] ) and &amp;quot;1&amp;quot; or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.isProtocolDialog( frame )&lt;br /&gt;
    return URLutil.isProtocolDialog( frame.args[ 1 ] ) and &amp;quot;1&amp;quot; or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.isProtocolWiki( frame )&lt;br /&gt;
    return URLutil.isProtocolWiki( frame.args[ 1 ] ) and &amp;quot;1&amp;quot; or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.isResourceURL( frame )&lt;br /&gt;
    return URLutil.isResourceURL( frame.args[ 1 ] ) and &amp;quot;1&amp;quot; or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.isSuspiciousURL( frame )&lt;br /&gt;
    return URLutil.isSuspiciousURL( frame.args[ 1 ] ) and &amp;quot;1&amp;quot; or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.isUnescapedURL( frame )&lt;br /&gt;
    return URLutil.isUnescapedURL( frame.args[ 1 ], frame.args[ 2 ] ) and &amp;quot;1&amp;quot; or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.isWebURL( frame )&lt;br /&gt;
    return URLutil.isWebURL( frame.args[ 1 ] ) and &amp;quot;1&amp;quot; or &amp;quot;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
function p.wikiEscapeURL( frame )&lt;br /&gt;
    return URLutil.wikiEscapeURL( frame.args[ 1 ] )&lt;br /&gt;
end&lt;br /&gt;
function p.URLutil()&lt;br /&gt;
    return URLutil&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>imported&gt;PHansen</name></author>
	</entry>
</feed>