Index: trunk/docs/examples/_config.inc.php
===================================================================
--- trunk/docs/examples/_config.inc.php	(revision 544)
+++ trunk/docs/examples/_config.inc.php	(revision 545)
@@ -84,5 +84,5 @@
     'error_reporting' => E_ALL & ~E_DEPRECATED & ~E_STRICT,
 
-    'log_directory' => COMMON_BASE . '/log',
+    'log_directory' => '/tmp',
     'log_filename' => 'site_log',
     'log_file_priority' => LOG_DEBUG,
Index: trunk/lib/Utilities.inc.php
===================================================================
--- trunk/lib/Utilities.inc.php	(revision 544)
+++ trunk/lib/Utilities.inc.php	(revision 545)
@@ -225,4 +225,7 @@
 function hyperlinkTxt($text, $strict=false, $length=null, $delim='âŠ')
 {
+    // A list of schemes we allow at the beginning of a URL.
+    $schemes = 'mailto:|tel:|skype:|callto:|facetime:|bitcoin:|geo:|magnet:\?|sip:|sms:|xmpp:|view-source:(?:https?://)?|[\w-]{2,}://';
+
     // Capture the full URL into the first match and only the first X characters into the second match.
     // This will match URLs not preceeded by " ' or = (URLs inside an attribute) or ` (Markdown quoted) or double-scheme (http://http://www.asdf.com)
@@ -233,18 +236,17 @@
         (                               # Begin match 1
             (                           # Begin match 2
-                (?:[\w-]{2,}://%s)      # URL starts with SCHEME:// or www. (if strict = false)
+                (?:%s)                  # URL starts with known scheme or www. if strict = false
                 [^\s/$.?#]+             # Any domain-valid characters
-                \.                      # At least one point
                 [^\s"`<>]{1,%s}         # Match 2 is limited to a maximum of LENGTH valid URL characters
             )
             [^\s"`<>]*                  # Match 1 continues with any further valid URL characters
-            [^\P{Any}\sâŠ<>Â«Â»"ââ%s]      # Final character not a space or common end-of-sentence punctuation (.,:;?!, etc). Using double negation set, see http://stackoverflow.com/a/4786560/277303
+            ([^\P{Any}\sâŠ<>Â«Â»"ââ%s])    # Final character not a space or common end-of-sentence punctuation (.,:;?!, etc). Using double negation set, see http://stackoverflow.com/a/4786560/277303
         )
         @Suxi
     ';
     $regex = sprintf($regex,
-        ($strict ? '' : '|www\.'), // Strict=false allows URLs beginning with www.
-        $length,
-        ($strict ? '' : '?!.,:;)\'-') // Strict=false excludes these characters as a possible last character of URL.
+        ($strict ? $schemes : $schemes . '|www\.'), // Strict=false adds "www." to the list of allowed start-of-URL.
+        ($length ? $length : ''),
+        ($strict ? '' : '?!.,:;)\'-') // Strict=false excludes some "URL-valid" characters from the last character of URL. (Hyphen must remain last character in this class.)
     );
 
@@ -253,13 +255,15 @@
     return preg_replace_callback($regex, function ($m) use ($length, $delim) {
         $url = $m[1];
-        $truncated_url = $m[2];
+        $truncated_url = $m[2] . $m[3];
         $absolute_url = preg_replace('!^www\.!', 'http://www.', $url);
         if (is_null($length) || $url == $truncated_url) {
             // If not truncating, or URL was not truncated.
-            $display_url = preg_replace('!^[\w-]{2,}://!', '', $url);
+            // Remove http schemas, and any single trailing / to make the display URL.
+            $display_url = preg_replace(['!^https?://!', '!^([^/]+)/$!'], ['', '$1'], $url);
             return sprintf('<a href="%s">%s</a>', oTxt($absolute_url), $display_url);
         } else {
             // Truncated URL.
-            $display_url = preg_replace('!^[\w-]{2,}://!', '', trim($truncated_url));
+            // Remove http schemas, and any single trailing / to make the display URL.
+            $display_url = preg_replace(['!^https?://!', '!^([^/]+)/$!'], ['', '$1'], trim($truncated_url));
             return sprintf('<a href="%s">%s%s</a>', oTxt($absolute_url), $display_url, $delim);
         }
Index: trunk/tests/UtilitiesTest.php
===================================================================
--- trunk/tests/UtilitiesTest.php	(revision 544)
+++ trunk/tests/UtilitiesTest.php	(revision 545)
@@ -50,7 +50,10 @@
     {
         $urls = [
-            ' http://www.asdf.com/ ' => ' <a href="http://www.asdf.com/">www.asdf.com/</a> ',
-            ' www.asdf.com/ ' => ' <a href="http://www.asdf.com/">www.asdf.com/</a> ',
-            ' www.asdf.com/? ' => ' <a href="http://www.asdf.com/">www.asdf.com/</a>? ',
+            ' http://www.asdf.com/ ' => ' <a href="http://www.asdf.com/">www.asdf.com</a> ',
+            ' ws://www.asdf.com/ ' => ' <a href="ws://www.asdf.com/">ws://www.asdf.com/</a> ',
+            ' sftp://user@host.tld:22/path/x ' => ' <a href="sftp://user@host.tld:22/path/x">sftp://user@host.tld:22/path/x</a> ',
+            ' www.asdf.com/ ' => ' <a href="http://www.asdf.com/">www.asdf.com</a> ',
+            ' http://asdf/ ' => ' <a href="http://asdf/">asdf</a> ',
+            ' www.asdf.com/? ' => ' <a href="http://www.asdf.com/">www.asdf.com</a>? ',
             ' www.asdf.com/?x=y+z ' => ' <a href="http://www.asdf.com/?x=y+z">www.asdf.com/?x=y+z</a> ',
             ' www.asdf.com/?x=y+ ' => ' <a href="http://www.asdf.com/?x=y+">www.asdf.com/?x=y+</a> ',
@@ -79,24 +82,24 @@
             ' http://âªdf.ws/123 ' => ' <a href="http://âªdf.ws/123">âªdf.ws/123</a> ',
             ' http://userid:password@example.com:8080 ' => ' <a href="http://userid:password@example.com:8080">userid:password@example.com:8080</a> ',
-            ' http://userid:password@example.com:8080/ ' => ' <a href="http://userid:password@example.com:8080/">userid:password@example.com:8080/</a> ',
+            ' http://userid:password@example.com:8080/ ' => ' <a href="http://userid:password@example.com:8080/">userid:password@example.com:8080</a> ',
             ' http://userid@example.com ' => ' <a href="http://userid@example.com">userid@example.com</a> ',
-            ' http://userid@example.com/ ' => ' <a href="http://userid@example.com/">userid@example.com/</a> ',
+            ' http://userid@example.com/ ' => ' <a href="http://userid@example.com/">userid@example.com</a> ',
             ' http://userid@example.com:8080 ' => ' <a href="http://userid@example.com:8080">userid@example.com:8080</a> ',
-            ' http://userid@example.com:8080/ ' => ' <a href="http://userid@example.com:8080/">userid@example.com:8080/</a> ',
+            ' http://userid@example.com:8080/ ' => ' <a href="http://userid@example.com:8080/">userid@example.com:8080</a> ',
             ' http://userid:password@example.com ' => ' <a href="http://userid:password@example.com">userid:password@example.com</a> ',
-            ' http://userid:password@example.com/ ' => ' <a href="http://userid:password@example.com/">userid:password@example.com/</a> ',
-            ' http://142.42.1.1/ ' => ' <a href="http://142.42.1.1/">142.42.1.1/</a> ',
-            ' http://142.42.1.1:8080/ ' => ' <a href="http://142.42.1.1:8080/">142.42.1.1:8080/</a> ',
+            ' http://userid:password@example.com/ ' => ' <a href="http://userid:password@example.com/">userid:password@example.com</a> ',
+            ' http://142.42.1.1/ ' => ' <a href="http://142.42.1.1/">142.42.1.1</a> ',
+            ' http://142.42.1.1:8080/ ' => ' <a href="http://142.42.1.1:8080/">142.42.1.1:8080</a> ',
             ' http://â¡.ws/äš¹ ' => ' <a href="http://â¡.ws/äš¹">â¡.ws/äš¹</a> ',
             ' http://â.ws ' => ' <a href="http://â.ws">â.ws</a> ',
-            ' http://â.ws/ ' => ' <a href="http://â.ws/">â.ws/</a> ',
+            ' http://â.ws/ ' => ' <a href="http://â.ws/">â.ws</a> ',
             ' http://foo.com/blah_(wikipedia)#cite-1 ' => ' <a href="http://foo.com/blah_(wikipedia)#cite-1">foo.com/blah_(wikipedia)#cite-1</a> ',
             ' http://foo.com/blah_(wikipedia)_blah#cite-1 ' => ' <a href="http://foo.com/blah_(wikipedia)_blah#cite-1">foo.com/blah_(wikipedia)_blah#cite-1</a> ',
             ' http://foo.com/unicode_(âª)_in_parens ' => ' <a href="http://foo.com/unicode_(âª)_in_parens">foo.com/unicode_(âª)_in_parens</a> ',
             ' http://foo.com/(something)?after=parens ' => ' <a href="http://foo.com/(something)?after=parens">foo.com/(something)?after=parens</a> ',
-            ' http://âº.damowmow.com/ ' => ' <a href="http://âº.damowmow.com/">âº.damowmow.com/</a> ',
+            ' http://âº.damowmow.com/ ' => ' <a href="http://âº.damowmow.com/">âº.damowmow.com</a> ',
             ' http://code.google.com/events/#&product=browser ' => ' <a href="http://code.google.com/events/#&amp;product=browser">code.google.com/events/#&product=browser</a> ',
             ' http://j.mp ' => ' <a href="http://j.mp">j.mp</a> ',
-            ' ftp://foo.bar/baz ' => ' <a href="ftp://foo.bar/baz">foo.bar/baz</a> ',
+            ' ftp://foo.bar/baz ' => ' <a href="ftp://foo.bar/baz">ftp://foo.bar/baz</a> ',
             ' http://foo.bar/?q=Test%20URL-encoded%20stuff ' => ' <a href="http://foo.bar/?q=Test%20URL-encoded%20stuff">foo.bar/?q=Test%20URL-encoded%20stuff</a> ',
             ' http://Ù
@@ -116,6 +119,128 @@
             ' https://github.com/search?q=gif&utf8=â ' => ' <a href="https://github.com/search?q=gif&amp;utf8=â">github.com/search?q=gif&utf8=â</a> ',
 
+            // These should fail.
+            ' http://x and.co OK?' => ' http://x and.co OK?',
+            ' www. ' => ' www. ',
+            ' www.x ' => ' www.x ',
+            ' http: ' => ' http: ',
+            ' http:// ' => ' http:// ',
+            ' http:x ' => ' http:x ',
+            ' http://x ' => ' http://x ',
+            ' http://x/ ' => ' http://x/ ',
+            ' http:// ?.x.com/ ' => ' http:// ?.x.com/ ',
+            ' http://?.com/ ' => ' http://?.com/ ',
+            ' http://.?.com/ ' => ' http://.?.com/ ',
+
             // These are allowed to fuckup due to limitations in our ability to be omnipotent.
-            ' <a href=http://www.example.com/ > http://www.example.com/</a> ' => ' <a href=http://www.example.com/ > <a href="http://www.example.com/">www.example.com/</a></a> ',
+            ' http:// www.x.com/ ' => ' http:// <a href="http://www.x.com/">www.x.com</a> ',
+            ' <a href=http://www.example.com/ > http://www.example.com/</a> ' => ' <a href=http://www.example.com/ > <a href="http://www.example.com/">www.example.com</a></a> ',
+
+            '<a href="http://www.example.com">Lorem ipsum</a> <a href="sftp://user@host.tld/path">dolor sit amet</a> sftp://user@host.tld/path, [http://www.example.com/ consetetur] sadipscing elitr, (sed diam) www.example.com! Nonumy http://x.com! Invidunt mailto:asdf@asdf.com ut <a href="mailto:asdf@asdf.com">asdf@asdf.com</a> \'\'\'et dolore\'\'\' magna. <!-- comment -->  Aliquyam:erat, sed://diam //voluptua//. At vero.eos.et {{{ for (var i = Things.length - 1; i >= 0; i--) { Things[i]; } }}} `http://x.com` justo duo doloreshttp://www.not.com!' => '<a href="http://www.example.com">Lorem ipsum</a> <a href="sftp://user@host.tld/path">dolor sit amet</a> <a href="sftp://user@host.tld/path">sftp://user@host.tld/path</a>, [<a href="http://www.example.com/">www.example.com</a> consetetur] sadipscing elitr, (sed diam) <a href="http://www.example.com">www.example.com</a>! Nonumy <a href="http://x.com">x.com</a>! Invidunt <a href="mailto:asdf@asdf.com">mailto:asdf@asdf.com</a> ut <a href="mailto:asdf@asdf.com">asdf@asdf.com</a> \'\'\'et dolore\'\'\' magna. <!-- comment -->  Aliquyam:erat, <a href="sed://diam">sed://diam</a> //voluptua//. At vero.eos.et {{{ for (var i = Things.length - 1; i >= 0; i--) { Things[i]; } }}} `http://x.com` justo duo <a href="doloreshttp://www.not.com">doloreshttp://www.not.com</a>!',
+        ];
+
+        $urls_strict = [
+            ' http://www.asdf.com/ ' => ' <a href="http://www.asdf.com/">www.asdf.com</a> ',
+            ' ws://www.asdf.com/ ' => ' <a href="ws://www.asdf.com/">ws://www.asdf.com/</a> ',
+            ' sftp://user@host.tld:22/path/x ' => ' <a href="sftp://user@host.tld:22/path/x">sftp://user@host.tld:22/path/x</a> ',
+            ' sip:beer ' => ' <a href="sip:beer">sip:beer</a> ',
+            ' http://asdf/ ' => ' <a href="http://asdf/">asdf</a> ',
+            ' http://www.asdf.com/? ' => ' <a href="http://www.asdf.com/?">www.asdf.com/?</a> ',
+            ' http://www.asdf.com/?x=y+z ' => ' <a href="http://www.asdf.com/?x=y+z">www.asdf.com/?x=y+z</a> ',
+            ' http://www.asdf.com/?x=y+ ' => ' <a href="http://www.asdf.com/?x=y+">www.asdf.com/?x=y+</a> ',
+            ' http://www.asdf.com/?x= ' => ' <a href="http://www.asdf.com/?x=">www.asdf.com/?x=</a> ',
+            ' http://www.asdf.com/?x ' => ' <a href="http://www.asdf.com/?x">www.asdf.com/?x</a> ',
+            ' https://www.asdf.com/?â€ïž=ð¥ ' => ' <a href="https://www.asdf.com/?â€ïž=ð¥">www.asdf.com/?â€ïž=ð¥</a> ',
+            ' www.asdf.com? ' => ' www.asdf.com? ',
+            ' www.asdf.com/ ' => ' www.asdf.com/ ',
+            ' www.asdf.com/? ' => ' www.asdf.com/? ',
+            ' www.asdf.com/?x=y+z ' => ' www.asdf.com/?x=y+z ',
+            ' www.asdf.com/?x=y+ ' => ' www.asdf.com/?x=y+ ',
+            ' www.asdf.com/?x= ' => ' www.asdf.com/?x= ',
+            ' www.asdf.com/?x ' => ' www.asdf.com/?x ',
+            ' www.asdf.com/?â€ïž=ð¥ ' => ' www.asdf.com/?â€ïž=ð¥ ',
+            ' www.asdf.com! ' => ' www.asdf.com! ',
+            ' www.asdf.com. ' => ' www.asdf.com. ',
+            ' `www.asdf.com` ' => ' `www.asdf.com` ',
+            ' "www.asdf.com" ' => ' "www.asdf.com" ',
+            ' <www.asdf.com> ' => ' <www.asdf.com> ',
+            ' `http://www.asdf.com` ' => ' `http://www.asdf.com` ',
+            ' "http://www.asdf.com" ' => ' "http://www.asdf.com" ',
+            ' <http://www.asdf.com> ' => ' <<a href="http://www.asdf.com">www.asdf.com</a>> ',
+            ' (http://www.asdf.com) ' => ' (<a href="http://www.asdf.com)">www.asdf.com)</a> ',
+            ' (URL: http://www.asdf.com#1) ' => ' (URL: <a href="http://www.asdf.com#1)">www.asdf.com#1)</a> ',
+            ' <a href="http://www.example.com/">Click Here</a> ' => ' <a href="http://www.example.com/">Click Here</a> ',
+            ' <a href="http://www.example.com/">http://www.example.com/</a> ' => ' <a href="http://www.example.com/">http://www.example.com/</a> ',
+            ' <a href=http://www.example.com/>http://www.example.com/</a> ' => ' <a href=http://www.example.com/>http://www.example.com/</a> ',
+            ' <a href=\'http://www.example.com/\' >http://www.example.com/</a> ' => ' <a href=\'http://www.example.com/\' >http://www.example.com/</a> ',
+            ' http://foo.com/blah_blah ' => ' <a href="http://foo.com/blah_blah">foo.com/blah_blah</a> ',
+            ' http://foo.com/blah_blah/ ' => ' <a href="http://foo.com/blah_blah/">foo.com/blah_blah/</a> ',
+            ' http://foo.com/blah_blah_(wikipedia) ' => ' <a href="http://foo.com/blah_blah_(wikipedia)">foo.com/blah_blah_(wikipedia)</a> ',
+            ' http://foo.com/blah_blah_(wikipedia)_(again) ' => ' <a href="http://foo.com/blah_blah_(wikipedia)_(again)">foo.com/blah_blah_(wikipedia)_(again)</a> ',
+            ' http://www.example.com/wpstyle/?p=364 ' => ' <a href="http://www.example.com/wpstyle/?p=364">www.example.com/wpstyle/?p=364</a> ',
+            ' https://www.example.com/foo/?bar=baz&inga=42&quux ' => ' <a href="https://www.example.com/foo/?bar=baz&amp;inga=42&amp;quux">www.example.com/foo/?bar=baz&inga=42&quux</a> ',
+            ' http://âªdf.ws/123 ' => ' <a href="http://âªdf.ws/123">âªdf.ws/123</a> ',
+            ' http://userid:password@example.com:8080 ' => ' <a href="http://userid:password@example.com:8080">userid:password@example.com:8080</a> ',
+            ' http://userid:password@example.com:8080/ ' => ' <a href="http://userid:password@example.com:8080/">userid:password@example.com:8080</a> ',
+            ' http://userid@example.com ' => ' <a href="http://userid@example.com">userid@example.com</a> ',
+            ' http://userid@example.com/ ' => ' <a href="http://userid@example.com/">userid@example.com</a> ',
+            ' http://userid@example.com:8080 ' => ' <a href="http://userid@example.com:8080">userid@example.com:8080</a> ',
+            ' http://userid@example.com:8080/ ' => ' <a href="http://userid@example.com:8080/">userid@example.com:8080</a> ',
+            ' http://userid:password@example.com ' => ' <a href="http://userid:password@example.com">userid:password@example.com</a> ',
+            ' http://userid:password@example.com/ ' => ' <a href="http://userid:password@example.com/">userid:password@example.com</a> ',
+            ' http://142.42.1.1/ ' => ' <a href="http://142.42.1.1/">142.42.1.1</a> ',
+            ' http://142.42.1.1:8080/ ' => ' <a href="http://142.42.1.1:8080/">142.42.1.1:8080</a> ',
+            ' http://â¡.ws/äš¹ ' => ' <a href="http://â¡.ws/äš¹">â¡.ws/äš¹</a> ',
+            ' http://â.ws ' => ' <a href="http://â.ws">â.ws</a> ',
+            ' http://â.ws/ ' => ' <a href="http://â.ws/">â.ws</a> ',
+            ' http://foo.com/blah_(wikipedia)#cite-1 ' => ' <a href="http://foo.com/blah_(wikipedia)#cite-1">foo.com/blah_(wikipedia)#cite-1</a> ',
+            ' http://foo.com/blah_(wikipedia)_blah#cite-1 ' => ' <a href="http://foo.com/blah_(wikipedia)_blah#cite-1">foo.com/blah_(wikipedia)_blah#cite-1</a> ',
+            ' http://foo.com/unicode_(âª)_in_parens ' => ' <a href="http://foo.com/unicode_(âª)_in_parens">foo.com/unicode_(âª)_in_parens</a> ',
+            ' http://foo.com/(something)?after=parens ' => ' <a href="http://foo.com/(something)?after=parens">foo.com/(something)?after=parens</a> ',
+            ' http://âº.damowmow.com/ ' => ' <a href="http://âº.damowmow.com/">âº.damowmow.com</a> ',
+            ' http://code.google.com/events/#&product=browser ' => ' <a href="http://code.google.com/events/#&amp;product=browser">code.google.com/events/#&product=browser</a> ',
+            ' http://j.mp ' => ' <a href="http://j.mp">j.mp</a> ',
+            ' ftp://foo.bar/baz ' => ' <a href="ftp://foo.bar/baz">ftp://foo.bar/baz</a> ',
+            ' http://foo.bar/?q=Test%20URL-encoded%20stuff ' => ' <a href="http://foo.bar/?q=Test%20URL-encoded%20stuff">foo.bar/?q=Test%20URL-encoded%20stuff</a> ',
+            ' http://Ù
+Ø«Ø§Ù.Ø¥Ø®ØªØšØ§Ø± ' => ' <a href="http://Ù
+Ø«Ø§Ù.Ø¥Ø®ØªØšØ§Ø±">Ù
+Ø«Ø§Ù.Ø¥Ø®ØªØšØ§Ø±</a> ',
+            ' http://äŸå­.æµè¯ ' => ' <a href="http://äŸå­.æµè¯">äŸå­.æµè¯</a> ',
+            ' http://à€à€Šà€Ÿà€¹à€°à€£.à€ªà€°à¥à€à¥à€·à€Ÿ ' => ' <a href="http://à€à€Šà€Ÿà€¹à€°à€£.à€ªà€°à¥à€à¥à€·à€Ÿ">à€à€Šà€Ÿà€¹à€°à€£.à€ªà€°à¥à€à¥à€·à€Ÿ</a> ',
+            ' http://-.~_!$&\'()*+,;=:%40:80%2f::::::@example.com ' => ' <a href="http://-.~_!$&amp;&#039;()*+,;=:%40:80%2f::::::@example.com">-.~_!$&\'()*+,;=:%40:80%2f::::::@example.com</a> ',
+            ' http://1337.net ' => ' <a href="http://1337.net">1337.net</a> ',
+            ' http://a.b-c.de ' => ' <a href="http://a.b-c.de">a.b-c.de</a> ',
+            ' http://223.255.255.254 ' => ' <a href="http://223.255.255.254">223.255.255.254</a> ',
+            ' http://foo.bar?q=Spaces should be encoded ' => ' <a href="http://foo.bar?q=Spaces">foo.bar?q=Spaces</a> should be encoded ',
+            ' https://github.com/search?utf8=â&q=gif ' => ' <a href="https://github.com/search?utf8=â&amp;q=gif">github.com/search?utf8=â&q=gif</a> ',
+            ' https://github.com/search?q=gif&utf8=* ' => ' <a href="https://github.com/search?q=gif&amp;utf8=*">github.com/search?q=gif&utf8=*</a> ',
+            ' https://github.com/search?q=gif&utf8=â ' => ' <a href="https://github.com/search?q=gif&amp;utf8=â">github.com/search?q=gif&utf8=â</a> ',
+
+            // Unusual schemes.
+            ' view-source:https://trac.strangecode.com/x/ticket/2#comment:4 ' => ' <a href="view-source:https://trac.strangecode.com/x/ticket/2#comment:4">view-source:https://trac.strangecode.com/x/ticket/2#comment:4</a> ',
+            ' mailto:asdf@asdf.com ' => ' <a href="mailto:asdf@asdf.com">mailto:asdf@asdf.com</a> ',
+            ' facetime://+19995551234 ' => ' <a href="facetime://+19995551234">facetime://+19995551234</a> ',
+            ' tel:+15552001010 ' => ' <a href="tel:+15552001010">tel:+15552001010</a> ',
+            ' magnet:?xt=urn:ed2k:354B15E68FB8F36D7CD88FF94116CDC1&xt=urn:tree:tiger:7N5OAMRNGMSSEUE3ORHOKWN4WWIQ5X4EBOOTLJY&xt=urn:btih:QHQXPYWMACKDWKP47RRVIV7VOURXFE5Q&xl=10826029&dn=mediawiki-1.15.1.tar.gz&tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A80%2Fannounce&as=http%3A%2F%2Fdownload.wikimedia.org%2Fmediawiki%2F1.15%2Fmediawiki-1.15.1.tar.gz&xs=http%3A%2F%2Fcache.example.org%2FXRX2PEFXOOEJFRVUCX6HMZMKS5TWG4K5&xs=dchub://example.org ' => ' <a href="magnet:?xt=urn:ed2k:354B15E68FB8F36D7CD88FF94116CDC1&amp;xt=urn:tree:tiger:7N5OAMRNGMSSEUE3ORHOKWN4WWIQ5X4EBOOTLJY&amp;xt=urn:btih:QHQXPYWMACKDWKP47RRVIV7VOURXFE5Q&amp;xl=10826029&amp;dn=mediawiki-1.15.1.tar.gz&amp;tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A80%2Fannounce&amp;as=http%3A%2F%2Fdownload.wikimedia.org%2Fmediawiki%2F1.15%2Fmediawiki-1.15.1.tar.gz&amp;xs=http%3A%2F%2Fcache.example.org%2FXRX2PEFXOOEJFRVUCX6HMZMKS5TWG4K5&amp;xs=dchub://example.org">magnet:?xt=urn:ed2k:354B15E68FB8F36D7CD88FF94116CDC1&xt=urn:tree:tiger:7N5OAMRNGMSSEUE3ORHOKWN4WWIQ5X4EBOOTLJY&xt=urn:btih:QHQXPYWMACKDWKP47RRVIV7VOURXFE5Q&xl=10826029&dn=mediawiki-1.15.1.tar.gz&tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A80%2Fannounce&as=http%3A%2F%2Fdownload.wikimedia.org%2Fmediawiki%2F1.15%2Fmediawiki-1.15.1.tar.gz&xs=http%3A%2F%2Fcache.example.org%2FXRX2PEFXOOEJFRVUCX6HMZMKS5TWG4K5&xs=dchub://example.org</a> ',
+            ' chrome-extension://71f05c488a96b441ef679b09267ea46c/index.html ' => ' <a href="chrome-extension://71f05c488a96b441ef679b09267ea46c/index.html">chrome-extension://71f05c488a96b441ef679b09267ea46c/index.html</a> ',
+
+            // These should fail.
+            ' http://x and.co OK?' => ' http://x and.co OK?',
+            ' www. ' => ' www. ',
+            ' www.x ' => ' www.x ',
+            ' http: ' => ' http: ',
+            ' http:// ' => ' http:// ',
+            ' http:x ' => ' http:x ',
+            ' http://x ' => ' http://x ',
+            ' http://x/ ' => ' http://x/ ',
+            ' http:// www.x.com/ ' => ' http:// www.x.com/ ',
+            ' http://?.com/ ' => ' http://?.com/ ',
+            ' http://.?.com/ ' => ' http://.?.com/ ',
+
+            // These are allowed to fuckup due to limitations in our ability to be omnipotent.
+            ' <a href=http://www.example.com/ > http://www.example.com/</a> ' => ' <a href=http://www.example.com/ > <a href="http://www.example.com/">www.example.com</a></a> ',
+            ' dummyhttp://www.asdf.com/ ' => ' <a href="dummyhttp://www.asdf.com/">dummyhttp://www.asdf.com/</a> ',
+
+            '<a href="http://www.example.com">Lorem ipsum</a> <a href="sftp://user@host.tld/path">dolor sit amet</a> sftp://user@host.tld/path, [http://www.example.com/ consetetur] sadipscing elitr, (sed diam) www.example.com! Nonumy http://x.com! Invidunt mailto:asdf@asdf.com ut <a href="mailto:asdf@asdf.com">asdf@asdf.com</a> \'\'\'et dolore\'\'\' magna. <!-- comment -->  Aliquyam:erat, sed://diam //voluptua//. At vero.eos.et {{{ for (var i = Things.length - 1; i >= 0; i--) { Things[i]; } }}} `http://x.com` justo duo doloreshttp://www.not.com!' => '<a href="http://www.example.com">Lorem ipsum</a> <a href="sftp://user@host.tld/path">dolor sit amet</a> <a href="sftp://user@host.tld/path,">sftp://user@host.tld/path,</a> [<a href="http://www.example.com/">www.example.com</a> consetetur] sadipscing elitr, (sed diam) www.example.com! Nonumy <a href="http://x.com!">x.com!</a> Invidunt <a href="mailto:asdf@asdf.com">mailto:asdf@asdf.com</a> ut <a href="mailto:asdf@asdf.com">asdf@asdf.com</a> \'\'\'et dolore\'\'\' magna. <!-- comment -->  Aliquyam:erat, <a href="sed://diam">sed://diam</a> //voluptua//. At vero.eos.et {{{ for (var i = Things.length - 1; i >= 0; i--) { Things[i]; } }}} `http://x.com` justo duo <a href="doloreshttp://www.not.com!">doloreshttp://www.not.com!</a>',
         ];
         foreach ($urls as $input => $expected) {
@@ -123,4 +248,9 @@
             $this->assertEquals($expected, $result, sprintf('Failed with input: %s', $input));
         }
+        foreach ($urls_strict as $input => $expected) {
+            // printf("'%s' => '%s',\n", $input, hyperlinkTxt($input, true));
+            $result = hyperlinkTxt($input, true);
+            $this->assertEquals($expected, $result, sprintf('Failed with input: %s', $input));
+        }
     }
 
