Script Preparation code:
x
 
window.rfc2396 = (function () {
function isURI (input) {
  return URI_reference(input, 0) === input.length
}
// URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
function URI_reference (input, next) {
  var next2 = absoluteURI(input, next) || relativeURI(input, next)
  if (next2) {
    if (input.charAt(next2) === '#') {
      return fragment(input, next2 + 1) || next2
    }
    return next2
  }
  if (input.charAt(next) === '#') {
    return fragment(input, next + 1) || next
  }
  return next
}
// absoluteURI   = scheme ":" ( hier_part | opaque_part )
function absoluteURI (input, next) {
  next = scheme(input, next)
  if (next && input.charAt(next) === ':') {
    return hier_part(input, ++next) || opaque_part(input, next)
  }
}
// relativeURI   = ( net_path | abs_path | rel_path ) [ "?" query ]
function relativeURI (input, next) {
  next = net_path(input, next) || abs_path(input, next) ||
    rel_path(input, next)
  if (next && input.charAt(next) === '?') {
    return query(input, next + 1) || next
  }
  return next
}
// hier_part     = ( net_path | abs_path ) [ "?" query ]
function hier_part (input, next) {
  next = net_path(input, next) || abs_path(input, next)
  if (next && input.charAt(next) === '?') {
    return query(input, next + 1) || next
  }
  return next
}
// opaque_part   = uric_no_slash *uric
function opaque_part (input, next) {
  next = uric_no_slash(input, next)
  if (next) {
    for (;;) {
      var next2 = uric(input, next)
      if (!next2) {
        break
      }
      next = next2
    }
    return next
  }
}
// uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" |
//                 "&" | "=" | "+" | "$" | ","
function uric_no_slash (input, next) {
  return unreserved(input, next) || escaped(input, next) ||
    [';', '?', ':', '@', '&', '=', '+', '$', ','].indexOf(
      input.charAt(next)) >= 0 ? next + 1 : 0
}
// net_path      = "//" authority [ abs_path ]
function net_path (input, next) {
  if (input.charAt(next) === '/' && input.charAt(next + 1) === '/') {
    next = authority(input, next + 2)
    return abs_path(input, next) || next
  }
}
// abs_path      = "/"  path_segments
function abs_path (input, next) {
  return input.charAt(next) === '/' && path_segments(input, next + 1)
}
// rel_path      = rel_segment [ abs_path ]
function rel_path (input, next) {
  next = rel_segment(input, next)
  if (next) {
    return abs_path(input, next) || next
  }
}
// rel_segment   = 1*( unreserved | escaped |
//                     ";" | "@" | "&" | "=" | "+" | "$" | "," )
function rel_segment (input, next) {
  next = check()
  if (next) {
    for (;;) {
      var next2 = check()
      if (!next2) {
        break
      }
      next = next2
    }
    return next
  }
  function check () {
    return unreserved(input, next) || escaped(input, next) || [';', '@', '&',
      '=', '+', '$', ','].indexOf(input.charAt(next)) >= 0 ? next + 1 : 0
  }
}
// scheme        = alpha *( alpha | digit | "+" | "-" | "." )
function scheme (input, next) {
  next = alpha(input, next)
  if (next) {
    for (;;) {
      var next2 = alpha(input, next) || digit(input, next) || ['+', '-',
        '.', ].indexOf(input.charAt(next)) >= 0 ? next + 1 : 0
      if (!next2) {
        break
      }
      next = next2
    }
    return next
  }
}
// authority     = server | reg_name
function authority (input, next) {
  return server(input, next) || reg_name(input, next)
}
// reg_name      = 1*( unreserved | escaped | "$" | "," |
//                     ";" | ":" | "@" | "&" | "=" | "+" )
function reg_name (input, next) {
  next = check()
  if (next) {
    for (;;) {
      var next2 = check()
      if (!next2) {
        break
      }
      next = next2
    }
    return next
  }
  function check () {
    return unreserved(input, next) || escaped(input, next) || ['$', ',', ';',
      ':', '@', '&', '=', '+'].indexOf(input.charAt(next)) >= 0 ? next + 1 : 0
  }
}
// server        = [ [ userinfo "@" ] hostport ]
function server (input, next) {
  var next2 = userinfo(input, next)
  if (next2 && input.charAt(next2) === '@') {
    next = next2 + 1
  }
  return hostport(input, next) || next
}
// userinfo      = *( unreserved | escaped |
//                    ";" | ":" | "&" | "=" | "+" | "$" | "," )
function userinfo (input, next) {
  for (;;) {
    var next2 = unreserved(input, next) || escaped(input, next) || [';', ':',
      '&', '=', '+', '$', ','].indexOf(input.charAt(next)) >= 0 ? next + 1 : 0
    if (!next2) {
      break
    }
    next = next2
  }
  return next
}
// hostport      = host [ ":" port ]
function hostport (input, next) {
  next = host(input, next)
  if (next && input.charAt(next) === ':') {
    return port(input, next + 1) || next
  }
  return next
}
// host          = hostname | IPv4address
function host (input, next) {
  return hostname(input, next) || IPv4address(input, next)
}
// hostname      = *( domainlabel "." ) toplabel [ "." ]
function hostname (input, next) {
  for (;;) {
    var next2 = domainlabel(input, next)
    if (!next2 || input.charAt(next2) !== '.') {
      break
    }
    next = next2 + 1
  }
  next = toplabel(input, next)
  if (next && input.charAt(next) === '.') {
    ++next
  }
  return next
}
// domainlabel   = alphanum | alphanum *( alphanum | "-" ) alphanum
function domainlabel (input, next) {
  next = alphanum(input, next)
  if (next) {
    for (;;) {
      var next2 = alphanum(input, next)
      if (!next2 && input.charAt(next) === '.') {
        next2 = next + 1
      }
      if (!next2) {
        break
      }
      next = next2
    }
    return alphanum(input, next) || next
  }
}
// toplabel      = alpha | alpha *( alphanum | "-" ) alphanum
function toplabel (input, next) {
  next = alpha(input, next)
  if (next) {
    for (;;) {
      var next2 = alphanum(input, next)
      if (!next2 && input.charAt(next) === '.') {
        next2 = next + 1
      }
      if (!next2) {
        break
      }
      next = next2
    }
    return alphanum(input, next) || next
  }
}
// IPv4address   = 1*digit "." 1*digit "." 1*digit "." 1*digit
function IPv4address (input, next) {
  next = check()
  if (next && input.charAt(next) === '.') {
    ++next
    next = check()
    if (next && input.charAt(next) === '.') {
      ++next
      next = check()
      if (next && input.charAt(next) === '.') {
        ++next
        return check()
      }
    }
  }
  function check () {
    next = digit(input, next)
    if (next) {
      for (;;) {
        var next2 = digit(input, next)
        if (!next2) {
          break
        }
        next = next2
      }
      return next
    }
  }
}
// port          = *digit
function port (input, next) {
  for (;;) {
    var next2 = digit(input, next)
    if (!next2) {
      break
    }
    next = next2
  }
  return next
}
// path          = [ abs_path | opaque_part ]
function path (input, next) {
  return abs_path(input, next) || opaque_part(input, next) || next
}
// path_segments = segment *( "/" segment )
function path_segments (input, next) {
  next = segment(input, next)
  if (next) {
    for (;;) {
      if (input.charAt(next) !== '/') {
        break
      }
      var next2 = segment(input, next + 1)
      if (!next2) {
        break
      }
      next = next2
    }
    return next
  }
}
// segment       = *pchar *( ";" param )
function segment (input, next) {
  for (;;) {
    var next2 = pchar(input, next)
    if (!next2) {
      break
    }
    next = next2
  }
  for (;;) {
    if (input.charAt(next) !== '/') {
      break
    }
    var next2 = segment(input, next + 1)
    if (!next2) {
      break
    }
    next = next2
  }
  return next
}
// param         = *pchar
function param (input, next) {
  for (;;) {
    var next2 = pchar(input, next)
    if (!next2) {
      break
    }
    next = next2
  }
  return next
}
// pchar         = unreserved | escaped |
//                 ":" | "@" | "&" | "=" | "+" | "$" | ","
function pchar (input, next) {
  return unreserved(input, next) || escaped(input, next) || [':', '@', '&',
    '=', '+', '$', ','].indexOf(input.charAt(next)) >= 0 ? next + 1 : 0
}
// query         = *uric
function query (input, next) {
  for (;;) {
    var next2 = uric(input, next)
    if (!next2) {
      break
    }
    next = next2
  }
  return next
}
// fragment      = *uric
function fragment (input, next) {
  for (;;) {
    var next2 = uric(input, next)
    if (!next2) {
      break
    }
    next = next2
  }
  return next
}
// uric          = reserved | unreserved | escaped
function uric (input, next) {
  return reserved(input, next) || unreserved(input, next) ||
    escaped(input, next)
}
// reserved      = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
//                 "$" | ","
function reserved (input, next) {
  return [';', '/', '?', ':', '@', '&', '=', '+', '$', ','].indexOf(
    input.charAt(next)) >= 0 ? next + 1 : 0
}
// unreserved    = alphanum | mark
function unreserved (input, next) {
  return alphanum(input, next) || mark(input, next)
}
// mark          = "-" | "_" | "." | "!" | "~" | "*" | "'" |
//                 "(" | ")"
function mark (input, next) {
  return ['-', '_', '.', '!', '~', '*', '\'', '(', ')'].indexOf(
    input.charAt(next)) >= 0 ? next + 1 : 0
}
// escaped       = "%" hex hex
function escaped (input, next) {
  if (input.charAt(next) === '%') {
    next = hex(input, next + 1)
    return next && hex(input, next)
  }
}
// hex           = digit | "A" | "B" | "C" | "D" | "E" | "F" |
//                         "a" | "b" | "c" | "d" | "e" | "f"
function hex (input, next) {
  return digit(input, next) || ['A', 'B', 'C', 'D', 'E', 'F', 'a', 'b', 'c',
    'd', 'e', 'f'].indexOf(input.charAt(next)) >= 0 ? next + 1 : 0
}
// alphanum      = alpha | digit
function alphanum (input, next) {
  return alpha(input, next) || digit(input, next)
}
// alpha         = lowalpha | upalpha
function alpha (input, next) {
  return lowalpha(input, next) || upalpha(input, next)
}
// lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
//            "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
//            "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
function lowalpha (input, next) {
  return ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'].indexOf(
      input.charAt(next)) >= 0 ? next + 1 : 0
}
// upalpha  = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" |
//            "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" |
//            "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
function upalpha (input, next) {
  return ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'].indexOf(
      input.charAt(next)) >= 0 ? next + 1 : 0
}
// digit    = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
//            "8" | "9"
function digit (input, next) {
  return ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'].indexOf(
    input.charAt(next)) >= 0 ? next + 1 : 0
}
return {
  isURI: isURI
}
}())
window.rfc3986 = (function () {
function isURI (input) {
  return URI(input, 0) === input.length
}
// URI           = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
function URI (input, next) {
  var next2
  next = scheme(input, next)
  if (next && input.charAt(next) === ':') {
    next = hier_part(input, next + 1)
    if (next) {
      if (input.charAt(next) === '?') {
        next2 = query(input, next + 1)
        if (next2) {
          next = next2
        }
      }
      if (input.charAt(next) === '#') {
        next2 = fragment(input, next + 1)
        if (next2) {
          next = next2
        }
      }
    }
    return next
  }
}
// hier-part     = "//" authority path-abempty
//               / path-absolute
//               / path-rootless
//               / path-empty
function hier_part (input, next) {
  if (input.charAt(next) === '/' && input.charAt(next + 1) === '/') {
    var next2 = authority(input, next + 2)
    if (next2) {
      next2 = path_abempty(input, next2)
      if (next2) {
        return next2
      }
    }
  }
  return path_absolute(input, next) || path_rootless(input, next) ||
    path_empty(input, next)
}
// URI-reference = URI / relative-ref
function URI_reference (input, next) {
  return URI(input, next) || relative_ref(input, next)
}
// absolute-URI  = scheme ":" hier-part [ "?" query ]
function absoluteURI (input, next) {
  next = scheme(input, next)
  if (next && input.charAt(next) === ':') {
    next = hier_part(input, next + 1)
    if (next && input.charAt(next) === '?') {
      return query(input, next + 1) || next
    }
    return next
  }
}
// relative-ref  = relative-part [ "?" query ] [ "#" fragment ]
function relative_ref (input, next) {
  var next2
  next = relative_part(input, next)
  if (next) {
    if (input.charAt(next) === '?') {
      next2 = query(input, next + 1)
      if (next2) {
        next = next2
      }
    }
    if (input.charAt(next) === '#') {
      next2 = fragment(input, next + 1)
      if (next2) {
        next = next2
      }
    }
  }
  return next
}
// relative-part = "//" authority path-abempty
//               / path-absolute
//               / path-noscheme
//               / path-empty
function relative_part (input, next) {
  if (input.charAt(next) === '/' && input.charAt(next + 1) === '/') {
    var next2 = authority(input, next + 2)
    if (next2) {
      next2 = path_abempty(input, next2)
      if (next2) {
        return next2
      }
    }
  }
  return path_absolute(input, next) || path_noscheme(input, next) ||
    path_empty(input, next)
}
// scheme        = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
function scheme (input, next) {
  next = alpha(input, next)
  if (next) {
    for (;;) {
      var next2 = alpha(input, next) || digit(input, next) || (['+', '-',
        '.', ].indexOf(input.charAt(next)) >= 0 ? next + 1 : 0)
      if (!next2) {
        break
      }
      next = next2
    }
    return next
  }
}
// authority     = [ userinfo "@" ] host [ ":" port ]
function authority (input, next) {
  var next2 = userinfo(input, next)
  if (next2 && input.charAt(next2) === '@') {
    next = next2 + 1
  }
  next = host(input, next)
  if (next) {
    if (input.charAt(next) === ':') {
      return port(input, next + 1) || next
    }
    return next
  }
}
// userinfo      = *( unreserved / pct-encoded / sub-delims / ":" )
function userinfo (input, next) {
  for (;;) {
    var next2 = unreserved(input, next) || pct_encoded(input, next) ||
      sub_delims(input, next) || (input.charAt(next) === ':' ? next + 1 : 0)
    if (!next2) {
      break
    }
    next = next2
  }
  return next
}
// host          = IP-literal / IPv4address / reg-name
function host (input, next) {
  return IP_literal(input, next) || IPv4address(input, next) ||
      reg_name(input, next)
}
// port          = *DIGIT
function port (input, next) {
  for (;;) {
    var next2 = digit(input, next)
    if (!next2) {
      break
    }
    next = next2
  }
  return next
}
// IP-literal    = "[" ( IPv6address / IPvFuture  ) "]"
function IP_literal (input, next) {
  if (input.charAt(next) === '[') {
    next = IPv6address(input, next) || IPvFuture(input, next)
    if (next && input.charAt(next) === ']') {
      return next + 1
    }
  }
}
// IPvFuture     = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
function IPvFuture (input, next) {
  var next2
  if (input.charAt(next) === 'v') {
    next = hexdig(input, next + 1)
    if (next) {
      for (;;) {
        next2 = hexdig(input, next)
        if (!next2) {
          break
        }
        next = next2
      }
      if (input.charAt(next) === '.') {
        ++next
        next = check()
        if (next) {
          for (;;) {
            next2 = check()
            if (!next2) {
              break
            }
            next = next2
          }
          return next
        }
      }
    }
  }
}
// IPv6address   =                            6( h16 ":" ) ls32
//               /                       "::" 5( h16 ":" ) ls32
//               / [               h16 ] "::" 4( h16 ":" ) ls32
//               / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
//               / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
//               / [ *3( h16 ":" ) h16 ] "::"    h16 ":"   ls32
//               / [ *4( h16 ":" ) h16 ] "::"              ls32
//               / [ *5( h16 ":" ) h16 ] "::"              h16
//               / [ *6( h16 ":" ) h16 ] "::"
function IPv6address (input, next) {
  return 0
}
// h16           = 1*4HEXDIG
function h16 (input, next) {
  next = pchar(input, next)
  if (next) {
    for (var i = 0; i < 3; ++i) {
      var next2 = pchar(input, next)
      if (!next2) {
        break
      }
      next = next2
    }
    return next
  }
}
// ls32          = ( h16 ":" h16 ) / IPv4address
function ls32 (input, next) {
  var next2 = h16(input, next)
  if (next2) {
    next2 = input.charAt(next2) === '.' && h16(input, next2 + 1)
    if (next2) {
      return next2
    }
  }
  return IPv4address(input, next)
}
// IPv4address   = dec-octet "." dec-octet "." dec-octet "." dec-octet
function IPv4address (input, next) {
  next = dec_octet(input, next)
  if (next && input.charAt(next) === '.') {
    next = dec_octet(input, next + 1)
    if (next && input.charAt(next) === '.') {
      next = dec_octet(input, next + 1)
      if (next && input.charAt(next) === '.') {
        return dec_octet(input, next + 1)
      }
    }
  }
}
// dec-octet     = DIGIT                 ; 0-9
//               / %x31-39 DIGIT         ; 10-99
//               / "1" 2DIGIT            ; 100-199
//               / "2" %x30-34 DIGIT     ; 200-249
//               / "25" %x30-35          ; 250-255
function dec_octet (input, next) {
  var next2 = digit(input, next)
  if (next2) {
    return next2
  }
  next2 = ['1', '2', '3', '4', '5', '6', '7', '8', '9'].indexOf(
    input.charAt(next)) >= 0 ? next + 1 : 0
  if (next2) {
    next2 = digit(input, next2)
    if (next2) {
      return next2
    }
  }
  if (input.charAt(next) === '1') {
    next2 = twodigit(input, next + 1)
    if (next2) {
      return next2
    }
  }
  if (input.charAt(next) === '2') {
    next2 = ['0', '1', '2', '3', '4'].indexOf(
      input.charAt(next + 1)) >= 0 ? next + 1 : 0
    if (next2) {
      next2 = digit(input, next2)
      if (next2) {
        return next2
      }
    }
  }
  if (input.charAt(next) === '2' && input.charAt(next) === '5') {
    next2 = ['0', '1', '2', '3', '4', '5'].indexOf(
      input.charAt(next + 2)) >= 0 ? next + 1 : 0
    if (next2) {
      return next2
    }
  }
}
// reg-name      = *( unreserved / pct-encoded / sub-delims )
function reg_name (input, next) {
  for (;;) {
    var next2 = unreserved(input, next) || pct_encoded(input, next) ||
      sub_delims(input, next)
    if (!next2) {
      break
    }
    next = next2
  }
  return next
}
// path          = path-abempty    ; begins with "/" or is empty
//               / path-absolute   ; begins with "/" but not "//"
//               / path-noscheme   ; begins with a non-colon segment
//               / path-rootless   ; begins with a segment
//               / path-empty      ; zero characters
function path (input, next) {
  return path_abempty(input, next) || path_absolute(input, next) ||
    path_noscheme(input, next) || path_rootless(input, next) ||
    path_empty(input, next)
}
// path-abempty  = *( "/" segment )
function path_abempty (input, next) {
  for (;;) {
    if (input.charAt(next) !== '/') {
      break
    }
    var next2 = segment(input, next + 1)
    if (!next2) {
      break
    }
    next = next2
  }
  return next
}
// path-absolute = "/" [ segment-nz *( "/" segment ) ]
function path_absolute (input, next) {
  if (input.charAt(next) === '/') {
    var next2 = segment_nz(input, ++next)
    if (next2) {
      for (;;) {
        if (input.charAt(next2) !== '/') {
          break
        }
        var next3 = segment(input, next2 + 1)
        if (!next3) {
          break
        }
        next2 = next3
      }
      return next2
    }
    return next
  }
}
// path-noscheme = segment-nz-nc *( "/" segment )
function path_noscheme (input, next) {
  var next = segment_nz_nc(input, next)
  if (next) {
    for (;;) {
      if (input.charAt(next) !== '/') {
        break
      }
      var next2 = segment(input, next + 1)
      if (!next2) {
        break
      }
      next = next2
    }
    return next
  }
}
// path-rootless = segment-nz *( "/" segment )
function path_rootless (input, next) {
  var next = segment_nz(input, next)
  if (next) {
    for (;;) {
      if (input.charAt(next) !== '/') {
        break
      }
      var next2 = segment(input, next + 1)
      if (!next2) {
        break
      }
      next = next2
    }
    return next
  }
}
// path-empty    = 0<pchar>
function path_empty (input, next) {
  return input.length === next ? next : 0
}
// segment       = *pchar
function segment (input, next) {
  for (;;) {
    var next2 = pchar(input, next)
    if (!next2) {
      break
    }
    next = next2
  }
  return next
}
// segment-nz    = 1*pchar
function segment_nz (input, next) {
  next = pchar(input, next)
  if (next) {
    for (;;) {
      var next2 = pchar(input, next)
      if (!next2) {
        break
      }
      next = next2
    }
    return next
  }
}
// segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
//               ; non-zero-length segment without any colon ":"
function segment_nz_nc (input, next) {
  next = check()
  if (next) {
    for (;;) {
      var next2 = check()
      if (!next2) {
        break
      }
      next = next2
    }
    return next
  }
  function check () {
    return unreserved(input, next) || pct_encoded(input, next) ||
      sub_delims(input, next) || (input.charAt(next) === '@' ? next + 1 : 0)
  }
}
// pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
function pchar (input, next) {
  return unreserved(input, next) || pct_encoded(input, next) ||
    sub_delims(input, next) || ([':', '@'].indexOf(
      input.charAt(next)) >= 0 ? next + 1 : 0)
}
// query         = *( pchar / "/" / "?" )
function query (input, next) {
  for (;;) {
    var next2 = pchar(input, next)
    if (!next2) {
      next2 = ['/', '?'].indexOf(input.charAt(next)) >= 0 ? next + 1 : 0
      if (!next2) {
        break
      }
    }
    next = next2
  }
  return next
}
// fragment      = *( pchar / "/" / "?" )
function fragment (input, next) {
  for (;;) {
    var next2 = pchar(input, next)
    if (!next2) {
      next2 = ['/', '?'].indexOf(input.charAt(next)) >= 0 ? next + 1 : 0
      if (!next2) {
        break
      }
    }
    next = next2
  }
  return next
}
// pct-encoded   = "%" HEXDIG HEXDIG
function pct_encoded (input, next) {
  if (input.charAt(next) === '%') {
    next = hexdig(input, next + 1)
    return next && hexdig(input, next)
  }
}
// unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
function unreserved (input, next) {
  return alpha(input, next) || digit(input, next) || ['-', '.', '_', '~'
    ].indexOf(input.charAt(next)) >= 0 ? next + 1 : 0
}
// reserved      = gen-delims / sub-delims
function reserved (input, next) {
  return gen_delims(input, next) || sub_delims(input, next)
}
// gen-delims    = ":" / "/" / "?" / "#" / "[" / "]" / "@"
function gen_delims (input, next) {
  return [':', '/', '?', '#', '[', ']', '@'].indexOf(
      input.charAt(next)) >= 0 ? next + 1 : 0
}
// sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
//               / "*" / "+" / "," / ";" / "="
function sub_delims (input, next) {
  return ['!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '='].indexOf(
      input.charAt(next)) >= 0 ? next + 1 : 0
}
// hexdig        = digit / "A" / "B" / "C" / "D" / "E" / "F" /
//                         "a" / "b" / "c" / "d" / "e" / "f"
function hexdig (input, next) {
  return digit(input, next) || (['A', 'B', 'C', 'D', 'E', 'F', 'a', 'b', 'c',
    'd', 'e', 'f'].indexOf(input.charAt(next)) >= 0 ? next + 1 : 0)
}
// alpha         = lowalpha / upalpha
function alpha (input, next) {
  return lowalpha(input, next) || upalpha(input, next)
}
// lowalpha = "a" / "b" / "c" / "d" / "e" / "f" / "g" / "h" / "i" /
//            "j" / "k" / "l" / "m" / "n" / "o" / "p" / "q" / "r" /
//            "s" / "t" / "u" / "v" / "w" / "x" / "y" / "z"
function lowalpha (input, next) {
  return ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'].indexOf(
      input.charAt(next)) >= 0 ? next + 1 : 0
}
// upalpha  = "A" / "B" / "C" / "D" / "E" / "F" / "G" / "H" / "I" /
//            "J" / "K" / "L" / "M" / "N" / "O" / "P" / "Q" / "R" /
//            "S" / "T" / "U" / "V" / "W" / "X" / "Y" / "Z"
function upalpha (input, next) {
  return ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'].indexOf(
      input.charAt(next)) >= 0 ? next + 1 : 0
}
// digit    = "0" / "1" / "2" / "3" / "4" / "5" / "6" / "7" /
//            "8" / "9"
function digit (input, next) {
  return ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'].indexOf(
    input.charAt(next)) >= 0 ? next + 1 : 0
}
return {
  isURI: isURI
}
}())
window.regexp = (function () {
// URI         = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
// hier-part   = "//" authority path-abempty
//             / path-absolute
//             / path-rootless
//             / path-empty
// ^(([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
//  12                 3          4       5  6        7 8
// ^(?:([^:/?#]+):)?(?:(//)([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?
//     1               2   3          4            5            6
var uriRegExp = new RegExp(
  '^(?:([^:/?#]+):)?(?:(//)([^/?#]*))?([^?#]*)(?:\\?([^#]*))?(?:#(.*))?$')
// scheme      = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
var schemeRegExp = new RegExp('^[a-zA-Z](?:[a-zA-Z]|[0-9]|[-+.])*$')
// authority   = [ userinfo "@" ] host [ ":" port ]
var authorityRegExp = new RegExp('^(?:([^@]+)@)?([^:]+)(?::([0-9]+))?$')
// userinfo    = *( unreserved / pct-encoded / sub-delims / ":" )
var userinfoRegExp = new RegExp('^[-a-zA-Z0-9._~%!$&\'()*+,;=:]*$')
// host        = IP-literal / IPv4address / reg-name
// IP-literal = "[" ( IPv6address / IPvFuture  ) "]"
// IPvFuture  = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
// IPv6address =                            6( h16 ":" ) ls32
//             /                       "::" 5( h16 ":" ) ls32
//             / [               h16 ] "::" 4( h16 ":" ) ls32
//             / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
//             / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
//             / [ *3( h16 ":" ) h16 ] "::"    h16 ":"   ls32
//             / [ *4( h16 ":" ) h16 ] "::"              ls32
//             / [ *5( h16 ":" ) h16 ] "::"              h16
//             / [ *6( h16 ":" ) h16 ] "::"
// ls32        = ( h16 ":" h16 ) / IPv4address
//             ; least-significant 32 bits of address
// h16         = 1*4HEXDIG
//             ; 16 bits of address represented in hexadecimal
// IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
var IPv4addressRegExp = new RegExp('^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$')
// dec-octet   = DIGIT                 ; 0-9
//             / %x31-39 DIGIT         ; 10-99
//             / "1" 2DIGIT            ; 100-199
//             / "2" %x30-34 DIGIT     ; 200-249
//             / "25" %x30-35          ; 250-255
// reg-name    = *( unreserved / pct-encoded / sub-delims )
var regnameRegExp = new RegExp('^[-a-zA-Z0-9._~%!$&\'()*+,;=]*$')
// port        = *DIGIT
// unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
// reserved    = gen-delims / sub-delims
// gen-delims  = ":" / "/" / "?" / "#" / "[" / "]" / "@"
// sub-delims  = "!" / "$" / "&" / "'" / "(" / ")"
//               / "*" / "+" / "," / ";" / "="
// pct-encoded = "%" HEXDIG HEXDIG
// path          = path-abempty    ; begins with "/" or is empty
//               / path-absolute   ; begins with "/" but not "//"
//               / path-noscheme   ; begins with a non-colon segment
//               / path-rootless   ; begins with a segment
//               / path-empty      ; zero characters
// path-abempty  = *( "/" segment )
// path-absolute = "/" [ segment-nz *( "/" segment ) ]
// path-noscheme = segment-nz-nc *( "/" segment )
// path-rootless = segment-nz *( "/" segment )
// path-empty    = 0<pchar>
// segment       = *pchar
var segmentRegExp = new RegExp('^[-a-zA-Z0-9._~%!$&\'()*+,;=:@]*$')
// segment-nz    = 1*pchar
var segmentNzRegExp = new RegExp('^[-a-zA-Z0-9._~%!$&\'()*+,;=:@]+')
// segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
//               ; non-zero-length segment without any colon ":"
// pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
// query       = *( pchar / "/" / "?" )
var queryRegExp = new RegExp('^[-a-zA-Z0-9._~%!$&\'()*+,;=:@/?]*$')
// fragment    = *( pchar / "/" / "?" )
var fragmentRegExp = queryRegExp
function parseURI (input) {
  var match = uriRegExp.exec(input)
  if (!match) {
    throw new SyntaxError('Invalid URI.')
  }
  var uri = convertMatch(match)
  return checkParts(uri)
}
function isURI (input) {
  try {
    parseURI(input)
    return true
  } catch (error) {
    return false
  }
}
function validateURI (input) {
  parseURI(input)
}
function convertMatch (match) {
  return {
    scheme: match[1],
    location: match[2],
    authority: match[3],
    path: match[4],
    query: match[5],
    fragment: match[6]
  }
}
function checkParts (uri) {
  checkScheme(uri.scheme)
  if (uri.location) {
    delete uri.location
    var authority = checkAuthority(uri.authority)
    uri.userinfo = authority.userinfo
    uri.host = authority.host
    uri.port = authority.port
    checkRestOfPath(uri.path)
  } else {
    checkBeginOfPath(uri.path)
  }
  checkQuery(uri.query)
  checkFragment(uri.fragment)
  return uri
}
function checkScheme (scheme) {
  if (!scheme) {
    throw new SyntaxError('Missing URI scheme.')
  }
  if (!schemeRegExp.test(scheme)) {
    throw new SyntaxError('Invalid URI scheme.')
  }
}
function checkAuthority (authority) {
  var match = authorityRegExp.exec(authority)
  if (!match) {
    throw new SyntaxError('Invalid URI authority.')
  }
  var userinfo = match[1]
  checkUserinfo(userinfo)
  var host = match[2]
  checkHost(host)
  var port = match[3]
  return {
    userinfo: userinfo,
    host: host,
    port: port
  }
}
function checkUserinfo (userinfo) {
  if (userinfo) {
    if (!userinfoRegExp.test(userinfo)) {
      throw new SyntaxError('Invalid URI userinfo.')
    }
    checkPercents(userinfo)
  }
}
function checkHost (host) {
  if (!host) {
    throw new SyntaxError('Missing URI host.')
  }
  if (checkIPv4address(host)) {
    return true
  }
  checkHostname(host)
}
function checkIPv4address (address) {
  var match = IPv4addressRegExp.exec(address)
  if (match) {
    if (match.some(function (octet, index) {
          return index && octet > 255
        })) {
      throw new SyntaxError('Invalid IPv4 address.')
    }
    return true
  }
}
function checkHostname (host) {
  if (!regnameRegExp.test(host)) {
    throw new SyntaxError('Invalid URI hostname.')
  }
}
function checkBeginOfPath (path) {
  if (path) {
    if (path[0] === '/') {
      path = path.substr(1)
    }
    var match = segmentNzRegExp.exec(path)
    if (!match) {
      throw new SyntaxError('Invalid URI path.')
    }
    match = match[0]
    checkPercents(match)
    checkRestOfPath(path.substr(match.length))
  }
}
function checkRestOfPath (path) {
  if (path) {
    path.split('/').forEach(checkPathSegment)
    checkPercents(path)
  }
}
function checkPathSegment (segment) {
  if (!segmentRegExp.test(segment)) {
    throw new SyntaxError('Invalid URI path segment.')
  }
}
function checkQuery (query) {
  if (query) {
    if (!queryRegExp.test(query)) {
      throw new SyntaxError('Invalid URI query.')
    }
    checkPercents(query)
  }
}
function checkFragment (fragment) {
  if (fragment) {
    if (!fragmentRegExp.test(fragment)) {
      throw new SyntaxError('Invalid URI fragment.')
    }
    checkPercents(fragment)
  }
}
function checkPercents (part) {
  for (var start = 0, length = part.length;;) {
    var percent = part.indexOf('%', start)
    if (percent < 0) {
      break
    }
    percent += 3
    if (percent <= length && check(percent - 2) && check(percent - 1)) {
      start = percent
      continue
    }
    throw new SyntaxError('Invalid percent encoding.')
  }
  function check(index) {
    code = part.codePointAt(index)
    if (code >= 48 && code <= 57) {
      return true
    }
    code &= ~32
    if (code >= 65 && code <= 70) {
      return true
    }
  }
}
return {
  isURI: isURI
}
}())
window.builtin = (function () {
function parseURI (input) {
  return new URL(input)
}
function isURI (input) {
  try {
    parseURI(input)
    return true
  } catch (error) {
    return false
  }
}
return {
  isURI: isURI
}
}())
window.url_parse = (function () {
var /*required = require('requires-port')
  , qs = require('querystringify')
  ,*/ protocolre = /^([a-z][a-z0-9.+-]*:)?(\/\/)?([\S\s]*)/i
  , slashes = /^[A-Za-z][A-Za-z0-9+-.]*:\/\//;
/**
 * These are the parse rules for the URL parser, it informs the parser
 * about:
 *
 * 0. The char it Needs to parse, if it's a string it should be done using
 *    indexOf, RegExp using exec and NaN means set as current value.
 * 1. The property we should set when parsing this value.
 * 2. Indication if it's backwards or forward parsing, when set as number it's
 *    the value of extra chars that should be split off.
 * 3. Inherit from location if non existing in the parser.
 * 4. `toLowerCase` the resulting value.
 */
var rules = [
  ['#', 'hash'],                        // Extract from the back.
  ['?', 'query'],                       // Extract from the back.
  ['/', 'pathname'],                    // Extract from the back.
  ['@', 'auth', 1],                     // Extract from the front.
  [NaN, 'host', undefined, 1, 1],       // Set left over value.
  [/:(\d+)$/, 'port', undefined, 1],    // RegExp the back.
  [NaN, 'hostname', undefined, 1, 1]    // Set left over.
];
/**
 * These properties should not be copied or inherited from. This is only needed
 * for all non blob URL's as a blob URL does not include a hash, only the
 * origin.
 *
 * @type {Object}
 * @private
 */
var ignore = { hash: 1, query: 1 };
/**
 * The location object differs when your code is loaded through a normal page,
 * Worker or through a worker using a blob. And with the blobble begins the
 * trouble as the location object will contain the URL of the blob, not the
 * location of the page where our code is loaded in. The actual origin is
 * encoded in the `pathname` so we can thankfully generate a good "default"
 * location from it so we can generate proper relative URL's again.
 *
 * @param {Object|String} loc Optional default location object.
 * @returns {Object} lolcation object.
 * @api public
 */
function lolcation(loc) {
  loc = loc || global.location || {};
  var finaldestination = {}
    , type = typeof loc
    , key;
  if ('blob:' === loc.protocol) {
    finaldestination = new URL(unescape(loc.pathname), {});
  } else if ('string' === type) {
    finaldestination = new URL(loc, {});
    for (key in ignore) delete finaldestination[key];
  } else if ('object' === type) {
    for (key in loc) {
      if (key in ignore) continue;
      finaldestination[key] = loc[key];
    }
    if (finaldestination.slashes === undefined) {
      finaldestination.slashes = slashes.test(loc.href);
    }
  }
  return finaldestination;
}
/**
 * @typedef ProtocolExtract
 * @type Object
 * @property {String} protocol Protocol matched in the URL, in lowercase.
 * @property {Boolean} slashes `true` if protocol is followed by "//", else `false`.
 * @property {String} rest Rest of the URL that is not part of the protocol.
 */
/**
 * Extract protocol information from a URL with/without double slash ("//").
 *
 * @param {String} address URL we want to extract from.
 * @return {ProtocolExtract} Extracted information.
 * @api private
 */
function extractProtocol(address) {
  var match = protocolre.exec(address);
  return {
    protocol: match[1] ? match[1].toLowerCase() : '',
    slashes: !!match[2],
    rest: match[3]
  };
}
/**
 * Resolve a relative URL pathname against a base URL pathname.
 *
 * @param {String} relative Pathname of the relative URL.
 * @param {String} base Pathname of the base URL.
 * @return {String} Resolved pathname.
 * @api private
 */
function resolve(relative, base) {
  var path = (base || '/').split('/').slice(0, -1).concat(relative.split('/'))
    , i = path.length
    , last = path[i - 1]
    , unshift = false
    , up = 0;
  while (i--) {
    if (path[i] === '.') {
      path.splice(i, 1);
    } else if (path[i] === '..') {
      path.splice(i, 1);
      up++;
    } else if (up) {
      if (i === 0) unshift = true;
      path.splice(i, 1);
      up--;
    }
  }
  if (unshift) path.unshift('');
  if (last === '.' || last === '..') path.push('');
  return path.join('/');
}
/**
 * The actual URL instance. Instead of returning an object we've opted-in to
 * create an actual constructor as it's much more memory efficient and
 * faster and it pleases my OCD.
 *
 * @constructor
 * @param {String} address URL we want to parse.
 * @param {Object|String} location Location defaults for relative paths.
 * @param {Boolean|Function} parser Parser for the query string.
 * @api public
 */
function URL(address, location, parser) {
  if (!(this instanceof URL)) {
    return new URL(address, location, parser);
  }
  var relative, extracted, parse, instruction, index, key
    , instructions = rules.slice()
    , type = typeof location
    , url = this
    , i = 0;
  //
  // The following if statements allows this module two have compatibility with
  // 2 different API:
  //
  // 1. Node.js's `url.parse` api which accepts a URL, boolean as arguments
  //    where the boolean indicates that the query string should also be parsed.
  //
  // 2. The `URL` interface of the browser which accepts a URL, object as
  //    arguments. The supplied object will be used as default values / fall-back
  //    for relative paths.
  //
  if ('object' !== type && 'string' !== type) {
    parser = location;
    location = null;
  }
  //if (parser && 'function' !== typeof parser) parser = qs.parse;
  location = lolcation(location);
  //
  // Extract protocol information before running the instructions.
  //
  extracted = extractProtocol(address || '');
  relative = !extracted.protocol && !extracted.slashes;
  url.slashes = extracted.slashes || relative && location.slashes;
  url.protocol = extracted.protocol || location.protocol || '';
  address = extracted.rest;
  //
  // When the authority component is absent the URL starts with a path
  // component.
  //
  if (!extracted.slashes) instructions[2] = [/(.*)/, 'pathname'];
  for (; i < instructions.length; i++) {
    instruction = instructions[i];
    parse = instruction[0];
    key = instruction[1];
    if (parse !== parse) {
      url[key] = address;
    } else if ('string' === typeof parse) {
      if (~(index = address.indexOf(parse))) {
        if ('number' === typeof instruction[2]) {
          url[key] = address.slice(0, index);
          address = address.slice(index + instruction[2]);
        } else {
          url[key] = address.slice(index);
          address = address.slice(0, index);
        }
      }
    } else if ((index = parse.exec(address))) {
      url[key] = index[1];
      address = address.slice(0, index.index);
    }
    url[key] = url[key] || (
      relative && instruction[3] ? location[key] || '' : ''
    );
    //
    // Hostname, host and protocol should be lowercased so they can be used to
    // create a proper `origin`.
    //
    if (instruction[4]) url[key] = url[key].toLowerCase();
  }
  //
  // Also parse the supplied query string in to an object. If we're supplied
  // with a custom parser as function use that instead of the default build-in
  // parser.
  //
  if (parser) url.query = parser(url.query);
  //
  // If the URL is relative, resolve the pathname against the base URL.
  //
  if (
      relative
    && location.slashes
    && url.pathname.charAt(0) !== '/'
    && (url.pathname !== '' || location.pathname !== '')
  ) {
    url.pathname = resolve(url.pathname, location.pathname);
  }
  //
  // We should not add port numbers if they are already the default port number
  // for a given protocol. As the host also contains the port number we're going
  // override it with the hostname which contains no port number.
  //
  //if (!required(url.port, url.protocol)) {
  //  url.host = url.hostname;
  //  url.port = '';
  //}
  //
  // Parse down the `auth` for the username and password.
  //
  url.username = url.password = '';
  if (url.auth) {
    instruction = url.auth.split(':');
    url.username = instruction[0] || '';
    url.password = instruction[1] || '';
  }
  url.origin = url.protocol && url.host && url.protocol !== 'file:'
    ? url.protocol +'//'+ url.host
    : 'null';
  //
  // The href is just the compiled result.
  //
  url.href = url.toString();
}
/**
 * This is convenience method for changing properties in the URL instance to
 * insure that they all propagate correctly.
 *
 * @param {String} part          Property we need to adjust.
 * @param {Mixed} value          The newly assigned value.
 * @param {Boolean|Function} fn  When setting the query, it will be the function
 *                               used to parse the query.
 *                               When setting the protocol, double slash will be
 *                               removed from the final url if it is true.
 * @returns {URL}
 * @api public
 */
function set(part, value, fn) {
  var url = this;
  switch (part) {
    case 'query':
      //if ('string' === typeof value && value.length) {
      //  value = (fn || qs.parse)(value);
      //}
      url[part] = value;
      break;
    case 'port':
      url[part] = value;
      //if (!required(value, url.protocol)) {
      //  url.host = url.hostname;
      //  url[part] = '';
      //} else if (value) {
        url.host = url.hostname +':'+ value;
      //}
      break;
    case 'hostname':
      url[part] = value;
      if (url.port) value += ':'+ url.port;
      url.host = value;
      break;
    case 'host':
      url[part] = value;
      if (/:\d+$/.test(value)) {
        value = value.split(':');
        url.port = value.pop();
        url.hostname = value.join(':');
      } else {
        url.hostname = value;
        url.port = '';
      }
      break;
    case 'protocol':
      url.protocol = value.toLowerCase();
      url.slashes = !fn;
      break;
    case 'pathname':
    case 'hash':
      if (value) {
        var char = part === 'pathname' ? '/' : '#';
        url[part] = value.charAt(0) !== char ? char + value : value;
      } else {
        url[part] = value;
      }
      break;
    default:
      url[part] = value;
  }
  for (var i = 0; i < rules.length; i++) {
    var ins = rules[i];
    if (ins[4]) url[ins[1]] = url[ins[1]].toLowerCase();
  }
  url.origin = url.protocol && url.host && url.protocol !== 'file:'
    ? url.protocol +'//'+ url.host
    : 'null';
  url.href = url.toString();
  return url;
}
/**
 * Transform the properties back in to a valid and full URL string.
 *
 * @param {Function} stringify Optional query stringify function.
 * @returns {String}
 * @api public
 */
function toString(stringify) {
  //if (!stringify || 'function' !== typeof stringify) stringify = qs.stringify;
  var query
    , url = this
    , protocol = url.protocol;
  if (protocol && protocol.charAt(protocol.length - 1) !== ':') protocol += ':';
  var result = protocol + (url.slashes ? '//' : '');
  if (url.username) {
    result += url.username;
    if (url.password) result += ':'+ url.password;
    result += '@';
  }
  result += url.host + url.pathname;
  query = 'object' === typeof url.query ? stringify(url.query) : url.query;
  if (query) result += '?' !== query.charAt(0) ? '?'+ query : query;
  if (url.hash) result += url.hash;
  return result;
}
URL.prototype = { set: set, toString: toString };
//
// Expose the URL parser and some additional properties that might be useful for
// others or testing.
//
URL.extractProtocol = extractProtocol;
URL.location = lolcation;
//URL.qs = qs;
function isURI (input) {
  try {
    new URL(input)
    return true
  } catch (error) {
    return false
  }
}
return {
  isURI: isURI
}
}())
window.urlparser = (function () {
/*
Copyright (c) 2014 Petka Antonov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
function Url() {
    //For more efficient internal representation and laziness.
    //The non-underscore versions of these properties are accessor functions
    //defined on the prototype.
    this._protocol = null;
    this._href = "";
    this._port = -1;
    this._query = null;
    this.auth = null;
    this.slashes = null;
    this.host = null;
    this.hostname = null;
    this.hash = null;
    this.search = null;
    this.pathname = null;
    this._prependSlash = false;
}
var querystring /*= require("querystring")*/;
Url.queryString = querystring;
Url.prototype.parse =
function Url$parse(str, parseQueryString, hostDenotesSlash, disableAutoEscapeChars) {
    if (typeof str !== "string") {
        throw new TypeError("Parameter 'url' must be a string, not " +
            typeof str);
    }
    var start = 0;
    var end = str.length - 1;
    //Trim leading and trailing ws
    while (str.charCodeAt(start) <= 0x20 /*' '*/) start++;
    while (str.charCodeAt(end) <= 0x20 /*' '*/) end--;
    start = this._parseProtocol(str, start, end);
    //Javascript doesn't have host
    if (this._protocol !== "javascript") {
        start = this._parseHost(str, start, end, hostDenotesSlash);
        var proto = this._protocol;
        if (!this.hostname &&
            (this.slashes || (proto && !slashProtocols[proto]))) {
            this.hostname = this.host = "";
        }
    }
    if (start <= end) {
        var ch = str.charCodeAt(start);
        if (ch === 0x2F /*'/'*/ || ch === 0x5C /*'\'*/) {
            this._parsePath(str, start, end, disableAutoEscapeChars);
        }
        else if (ch === 0x3F /*'?'*/) {
            this._parseQuery(str, start, end, disableAutoEscapeChars);
        }
        else if (ch === 0x23 /*'#'*/) {
          this._parseHash(str, start, end, disableAutoEscapeChars);
        }
        else if (this._protocol !== "javascript") {
            this._parsePath(str, start, end, disableAutoEscapeChars);
        }
        else { //For javascript the pathname is just the rest of it
            this.pathname = str.slice(start, end + 1 );
        }
    }
    if (!this.pathname && this.hostname &&
        this._slashProtocols[this._protocol]) {
        this.pathname = "/";
    }
    if (parseQueryString) {
        var search = this.search;
        if (search == null) {
            search = this.search = "";
        }
        if (search.charCodeAt(0) === 0x3F /*'?'*/) {
            search = search.slice(1);
        }
        //This calls a setter function, there is no .query data property
        this.query = Url.queryString.parse(search);
    }
};
Url.prototype.resolve = function Url$resolve(relative) {
    return this.resolveObject(Url.parse(relative, false, true)).format();
};
Url.prototype.format = function Url$format() {
    var auth = this.auth || "";
    if (auth) {
        auth = encodeURIComponent(auth);
        auth = auth.replace(/%3A/i, ":");
        auth += "@";
    }
    var protocol = this.protocol || "";
    var pathname = this.pathname || "";
    var hash = this.hash || "";
    var search = this.search || "";
    var query = "";
    var hostname = this.hostname || "";
    var port = this.port || "";
    var host = false;
    var scheme = "";
    //Cache the result of the getter function
    var q = this.query;
    if (q && typeof q === "object") {
        query = Url.queryString.stringify(q);
    }
    if (!search) {
        search = query ? "?" + query : "";
    }
    if (protocol && protocol.charCodeAt(protocol.length - 1) !== 0x3A /*':'*/)
        protocol += ":";
    if (this.host) {
        host = auth + this.host;
    }
    else if (hostname) {
        var ip6 = hostname.indexOf(":") > -1;
        if (ip6) hostname = "[" + hostname + "]";
        host = auth + hostname + (port ? ":" + port : "");
    }
    var slashes = this.slashes ||
        ((!protocol ||
        slashProtocols[protocol]) && host !== false);
    if (protocol) scheme = protocol + (slashes ? "//" : "");
    else if (slashes) scheme = "//";
    if (slashes && pathname && pathname.charCodeAt(0) !== 0x2F /*'/'*/) {
        pathname = "/" + pathname;
    }
    if (search && search.charCodeAt(0) !== 0x3F /*'?'*/)
        search = "?" + search;
    if (hash && hash.charCodeAt(0) !== 0x23 /*'#'*/)
        hash = "#" + hash;
    pathname = escapePathName(pathname);
    search = escapeSearch(search);
    return scheme + (host === false ? "" : host) + pathname + search + hash;
};
Url.prototype.resolveObject = function Url$resolveObject(relative) {
    if (typeof relative === "string")
        relative = Url.parse(relative, false, true);
    var result = this._clone();
    // hash is always overridden, no matter what.
    // even href="" will remove it.
    result.hash = relative.hash;
    // if the relative url is empty, then there"s nothing left to do here.
    if (!relative.href) {
        result._href = "";
        return result;
    }
    // hrefs like //foo/bar always cut to the protocol.
    if (relative.slashes && !relative._protocol) {
        relative._copyPropsTo(result, true);
        if (slashProtocols[result._protocol] &&
            result.hostname && !result.pathname) {
            result.pathname = "/";
        }
        result._href = "";
        return result;
    }
    if (relative._protocol && relative._protocol !== result._protocol) {
        // if it"s a known url protocol, then changing
        // the protocol does weird things
        // first, if it"s not file:, then we MUST have a host,
        // and if there was a path
        // to begin with, then we MUST have a path.
        // if it is file:, then the host is dropped,
        // because that"s known to be hostless.
        // anything else is assumed to be absolute.
        if (!slashProtocols[relative._protocol]) {
            relative._copyPropsTo(result, false);
            result._href = "";
            return result;
        }
        result._protocol = relative._protocol;
        if (!relative.host && relative._protocol !== "javascript") {
            var relPath = (relative.pathname || "").split("/");
            while (relPath.length && !(relative.host = relPath.shift()));
            if (!relative.host) relative.host = "";
            if (!relative.hostname) relative.hostname = "";
            if (relPath[0] !== "") relPath.unshift("");
            if (relPath.length < 2) relPath.unshift("");
            result.pathname = relPath.join("/");
        } else {
            result.pathname = relative.pathname;
        }
        result.search = relative.search;
        result.host = relative.host || "";
        result.auth = relative.auth;
        result.hostname = relative.hostname || relative.host;
        result._port = relative._port;
        result.slashes = result.slashes || relative.slashes;
        result._href = "";
        return result;
    }
    var isSourceAbs =
        (result.pathname && result.pathname.charCodeAt(0) === 0x2F /*'/'*/);
    var isRelAbs = (
            relative.host ||
            (relative.pathname &&
            relative.pathname.charCodeAt(0) === 0x2F /*'/'*/)
        );
    var mustEndAbs = (isRelAbs || isSourceAbs ||
                        (result.host && relative.pathname));
    var removeAllDots = mustEndAbs;
    var srcPath = result.pathname && result.pathname.split("/") || [];
    var relPath = relative.pathname && relative.pathname.split("/") || [];
    var psychotic = result._protocol && !slashProtocols[result._protocol];
    // if the url is a non-slashed url, then relative
    // links like ../.. should be able
    // to crawl up to the hostname, as well.  This is strange.
    // result.protocol has already been set by now.
    // Later on, put the first path part into the host field.
    if (psychotic) {
        result.hostname = "";
        result._port = -1;
        if (result.host) {
            if (srcPath[0] === "") srcPath[0] = result.host;
            else srcPath.unshift(result.host);
        }
        result.host = "";
        if (relative._protocol) {
            relative.hostname = "";
            relative._port = -1;
            if (relative.host) {
                if (relPath[0] === "") relPath[0] = relative.host;
                else relPath.unshift(relative.host);
            }
            relative.host = "";
        }
        mustEndAbs = mustEndAbs && (relPath[0] === "" || srcPath[0] === "");
    }
    if (isRelAbs) {
        // it"s absolute.
        result.host = relative.host ?
            relative.host : result.host;
        result.hostname = relative.hostname ?
            relative.hostname : result.hostname;
        result.search = relative.search;
        srcPath = relPath;
        // fall through to the dot-handling below.
    } else if (relPath.length) {
        // it"s relative
        // throw away the existing file, and take the new path instead.
        if (!srcPath) srcPath = [];
        srcPath.pop();
        srcPath = srcPath.concat(relPath);
        result.search = relative.search;
    } else if (relative.search) {
        // just pull out the search.
        // like href="?foo".
        // Put this after the other two cases because it simplifies the booleans
        if (psychotic) {
            result.hostname = result.host = srcPath.shift();
            //occationaly the auth can get stuck only in host
            //this especialy happens in cases like
            //url.resolveObject("mailto:local1@domain1", "local2@domain2")
            var authInHost = result.host && result.host.indexOf("@") > 0 ?
                result.host.split("@") : false;
            if (authInHost) {
                result.auth = authInHost.shift();
                result.host = result.hostname = authInHost.shift();
            }
        }
        result.search = relative.search;
        result._href = "";
        return result;
    }
    if (!srcPath.length) {
        // no path at all.  easy.
        // we"ve already handled the other stuff above.
        result.pathname = null;
        result._href = "";
        return result;
    }
    // if a url ENDs in . or .., then it must get a trailing slash.
    // however, if it ends in anything else non-slashy,
    // then it must NOT get a trailing slash.
    var last = srcPath.slice(-1)[0];
    var hasTrailingSlash = (
        (result.host || relative.host) && (last === "." || last === "..") ||
        last === "");
    // strip single dots, resolve double dots to parent dir
    // if the path tries to go above the root, `up` ends up > 0
    var up = 0;
    for (var i = srcPath.length; i >= 0; i--) {
        last = srcPath[i];
        if (last === ".") {
            srcPath.splice(i, 1);
        } else if (last === "..") {
            srcPath.splice(i, 1);
            up++;
        } else if (up) {
            srcPath.splice(i, 1);
            up--;
        }
    }
    // if the path is allowed to go above the root, restore leading ..s
    if (!mustEndAbs && !removeAllDots) {
        for (; up--; up) {
            srcPath.unshift("..");
        }
    }
    if (mustEndAbs && srcPath[0] !== "" &&
        (!srcPath[0] || srcPath[0].charCodeAt(0) !== 0x2F /*'/'*/)) {
        srcPath.unshift("");
    }
    if (hasTrailingSlash && (srcPath.join("/").substr(-1) !== "/")) {
        srcPath.push("");
    }
    var isAbsolute = srcPath[0] === "" ||
        (srcPath[0] && srcPath[0].charCodeAt(0) === 0x2F /*'/'*/);
    // put the host back
    if (psychotic) {
        result.hostname = result.host = isAbsolute ? "" :
            srcPath.length ? srcPath.shift() : "";
        //occationaly the auth can get stuck only in host
        //this especialy happens in cases like
        //url.resolveObject("mailto:local1@domain1", "local2@domain2")
        var authInHost = result.host && result.host.indexOf("@") > 0 ?
            result.host.split("@") : false;
        if (authInHost) {
            result.auth = authInHost.shift();
            result.host = result.hostname = authInHost.shift();
        }
    }
    mustEndAbs = mustEndAbs || (result.host && srcPath.length);
    if (mustEndAbs && !isAbsolute) {
        srcPath.unshift("");
    }
    result.pathname = srcPath.length === 0 ? null : srcPath.join("/");
    result.auth = relative.auth || result.auth;
    result.slashes = result.slashes || relative.slashes;
    result._href = "";
    return result;
};
var punycode /*= require("punycode")*/;
Url.prototype._hostIdna = function Url$_hostIdna(hostname) {
    // IDNA Support: Returns a punycoded representation of "domain".
    // It only converts parts of the domain name that
    // have non-ASCII characters, i.e. it doesn't matter if
    // you call it with a domain that already is ASCII-only.
    return hostname;//punycode.toASCII(hostname);
};
var escapePathName = Url.prototype._escapePathName =
function Url$_escapePathName(pathname) {
    if (!containsCharacter2(pathname, 0x23 /*'#'*/, 0x3F /*'?'*/)) {
        return pathname;
    }
    //Avoid closure creation to keep this inlinable
    return _escapePath(pathname);
};
var escapeSearch = Url.prototype._escapeSearch =
function Url$_escapeSearch(search) {
    if (!containsCharacter2(search, 0x23 /*'#'*/, -1)) return search;
    //Avoid closure creation to keep this inlinable
    return _escapeSearch(search);
};
Url.prototype._parseProtocol = function Url$_parseProtocol(str, start, end) {
    var doLowerCase = false;
    var protocolCharacters = this._protocolCharacters;
    for (var i = start; i <= end; ++i) {
        var ch = str.charCodeAt(i);
        if (ch === 0x3A /*':'*/) {
            var protocol = str.slice(start, i);
            if (doLowerCase) protocol = protocol.toLowerCase();
            this._protocol = protocol;
            return i + 1;
        }
        else if (protocolCharacters[ch] === 1) {
            if (ch < 0x61 /*'a'*/)
                doLowerCase = true;
        }
        else {
            return start;
        }
    }
    return start;
};
Url.prototype._parseAuth = function Url$_parseAuth(str, start, end, decode) {
    var auth = str.slice(start, end + 1);
    if (decode) {
        auth = decodeURIComponent(auth);
    }
    this.auth = auth;
};
Url.prototype._parsePort = function Url$_parsePort(str, start, end) {
    //Internal format is integer for more efficient parsing
    //and for efficient trimming of leading zeros
    var port = 0;
    //Distinguish between :0 and : (no port number at all)
    var hadChars = false;
    var validPort = true;
    for (var i = start; i <= end; ++i) {
        var ch = str.charCodeAt(i);
        if (0x30 /*'0'*/ <= ch && ch <= 0x39 /*'9'*/) {
            port = (10 * port) + (ch - 0x30 /*'0'*/);
            hadChars = true;
        }
        else {
            validPort = false;
            if (ch === 0x5C/*'\'*/ || ch === 0x2F/*'/'*/) {
                validPort = true;
            }
            break;
        }
    }
    if ((port === 0 && !hadChars) || !validPort) {
        if (!validPort) {
            this._port = -2;
        }
        return 0;
    }
    this._port = port;
    return i - start;
};
Url.prototype._parseHost =
function Url$_parseHost(str, start, end, slashesDenoteHost) {
    var hostEndingCharacters = this._hostEndingCharacters;
    var first = str.charCodeAt(start);
    var second = str.charCodeAt(start + 1);
    if ((first === 0x2F /*'/'*/ || first === 0x5C /*'\'*/) &&
        (second === 0x2F /*'/'*/ || second === 0x5C /*'\'*/)) {
        this.slashes = true;
        //The string starts with //
        if (start === 0) {
            //The string is just "//"
            if (end < 2) return start;
            //If slashes do not denote host and there is no auth,
            //there is no host when the string starts with //
            var hasAuth =
                containsCharacter(str, 0x40 /*'@'*/, 2, hostEndingCharacters);
            if (!hasAuth && !slashesDenoteHost) {
                this.slashes = null;
                return start;
            }
        }
        //There is a host that starts after the //
        start += 2;
    }
    //If there is no slashes, there is no hostname if
    //1. there was no protocol at all
    else if (!this._protocol ||
        //2. there was a protocol that requires slashes
        //e.g. in 'http:asd' 'asd' is not a hostname
        slashProtocols[this._protocol]
    ) {
        return start;
    }
    var doLowerCase = false;
    var idna = false;
    var hostNameStart = start;
    var hostNameEnd = end;
    var lastCh = -1;
    var portLength = 0;
    var charsAfterDot = 0;
    var authNeedsDecoding = false;
    var j = -1;
    //Find the last occurrence of an @-sign until hostending character is met
    //also mark if decoding is needed for the auth portion
    for (var i = start; i <= end; ++i) {
        var ch = str.charCodeAt(i);
        if (ch === 0x40 /*'@'*/) {
            j = i;
        }
        //This check is very, very cheap. Unneeded decodeURIComponent is very
        //very expensive
        else if (ch === 0x25 /*'%'*/) {
            authNeedsDecoding = true;
        }
        else if (hostEndingCharacters[ch] === 1) {
            break;
        }
    }
    //@-sign was found at index j, everything to the left from it
    //is auth part
    if (j > -1) {
        this._parseAuth(str, start, j - 1, authNeedsDecoding);
        //hostname starts after the last @-sign
        start = hostNameStart = j + 1;
    }
    //Host name is starting with a [
    if (str.charCodeAt(start) === 0x5B /*'['*/) {
        for (var i = start + 1; i <= end; ++i) {
            var ch = str.charCodeAt(i);
            //Assume valid IP6 is between the brackets
            if (ch === 0x5D /*']'*/) {
                if (str.charCodeAt(i + 1) === 0x3A /*':'*/) {
                    portLength = this._parsePort(str, i + 2, end) + 1;
                }
                var hostname = str.slice(start + 1, i).toLowerCase();
                this.hostname = hostname;
                this.host = this._port > 0 ?
                    "[" + hostname + "]:" + this._port :
                    "[" + hostname + "]";
                this.pathname = "/";
                return i + portLength + 1;
            }
        }
        //Empty hostname, [ starts a path
        return start;
    }
    for (var i = start; i <= end; ++i) {
        if (charsAfterDot > 62) {
            this.hostname = this.host = str.slice(start, i);
            return i;
        }
        var ch = str.charCodeAt(i);
        if (ch === 0x3A /*':'*/) {
            portLength = this._parsePort(str, i + 1, end) + 1;
            hostNameEnd = i - 1;
            break;
        }
        else if (ch < 0x61 /*'a'*/) {
            if (ch === 0x2E /*'.'*/) {
                //Node.js ignores this error
                /*
                if (lastCh === DOT || lastCh === -1) {
                    this.hostname = this.host = "";
                    return start;
                }
                */
                charsAfterDot = -1;
            }
            else if (0x41 /*'A'*/ <= ch && ch <= 0x5A /*'Z'*/) {
                doLowerCase = true;
            }
            //Valid characters other than ASCII letters -, _, +, 0-9
            else if (!(ch === 0x2D /*'-'*/ ||
                       ch === 0x5F /*'_'*/ ||
                       ch === 0x2B /*'+'*/ ||
                       (0x30 /*'0'*/ <= ch && ch <= 0x39 /*'9'*/))
                ) {
                if (hostEndingCharacters[ch] === 0 &&
                    this._noPrependSlashHostEnders[ch] === 0) {
                    this._prependSlash = true;
                }
                hostNameEnd = i - 1;
                break;
            }
        }
        else if (ch >= 0x7B /*'{'*/) {
            if (ch <= 0x7E /*'~'*/) {
                if (this._noPrependSlashHostEnders[ch] === 0) {
                    this._prependSlash = true;
                }
                hostNameEnd = i - 1;
                break;
            }
            idna = true;
        }
        lastCh = ch;
        charsAfterDot++;
    }
    //Node.js ignores this error
    /*
    if (lastCh === DOT) {
        hostNameEnd--;
    }
    */
    if (hostNameEnd + 1 !== start &&
        hostNameEnd - hostNameStart <= 256) {
        var hostname = str.slice(hostNameStart, hostNameEnd + 1);
        if (doLowerCase) hostname = hostname.toLowerCase();
        if (idna) hostname = this._hostIdna(hostname);
        this.hostname = hostname;
        this.host = this._port > 0 ? hostname + ":" + this._port : hostname;
    }
    return hostNameEnd + 1 + portLength;
};
Url.prototype._copyPropsTo = function Url$_copyPropsTo(input, noProtocol) {
    if (!noProtocol) {
        input._protocol = this._protocol;
    }
    input._href = this._href;
    input._port = this._port;
    input._prependSlash = this._prependSlash;
    input.auth = this.auth;
    input.slashes = this.slashes;
    input.host = this.host;
    input.hostname = this.hostname;
    input.hash = this.hash;
    input.search = this.search;
    input.pathname = this.pathname;
};
Url.prototype._clone = function Url$_clone() {
    var ret = new Url();
    ret._protocol = this._protocol;
    ret._href = this._href;
    ret._port = this._port;
    ret._prependSlash = this._prependSlash;
    ret.auth = this.auth;
    ret.slashes = this.slashes;
    ret.host = this.host;
    ret.hostname = this.hostname;
    ret.hash = this.hash;
    ret.search = this.search;
    ret.pathname = this.pathname;
    return ret;
};
Url.prototype._getComponentEscaped =
function Url$_getComponentEscaped(str, start, end, isAfterQuery) {
    var cur = start;
    var i = start;
    var ret = "";
    var autoEscapeMap = isAfterQuery ?
        this._afterQueryAutoEscapeMap : this._autoEscapeMap;
    for (; i <= end; ++i) {
        var ch = str.charCodeAt(i);
        var escaped = autoEscapeMap[ch];
        if (escaped !== "" && escaped !== undefined) {
            if (cur < i) ret += str.slice(cur, i);
            ret += escaped;
            cur = i + 1;
        }
    }
    if (cur < i + 1) ret += str.slice(cur, i);
    return ret;
};
Url.prototype._parsePath =
function Url$_parsePath(str, start, end, disableAutoEscapeChars) {
    var pathStart = start;
    var pathEnd = end;
    var escape = false;
    var autoEscapeCharacters = this._autoEscapeCharacters;
    var prePath = this._port === -2 ? "/:" : "";
    for (var i = start; i <= end; ++i) {
        var ch = str.charCodeAt(i);
        if (ch === 0x23 /*'#'*/) {
          this._parseHash(str, i, end, disableAutoEscapeChars);
            pathEnd = i - 1;
            break;
        }
        else if (ch === 0x3F /*'?'*/) {
            this._parseQuery(str, i, end, disableAutoEscapeChars);
            pathEnd = i - 1;
            break;
        }
        else if (!disableAutoEscapeChars && !escape && autoEscapeCharacters[ch] === 1) {
            escape = true;
        }
    }
    if (pathStart > pathEnd) {
        this.pathname = prePath === "" ? "/" : prePath;
        return;
    }
    var path;
    if (escape) {
        path = this._getComponentEscaped(str, pathStart, pathEnd, false);
    }
    else {
        path = str.slice(pathStart, pathEnd + 1);
    }
    this.pathname = prePath === ""
        ? (this._prependSlash ? "/" + path : path)
        : prePath + path;
};
Url.prototype._parseQuery = function Url$_parseQuery(str, start, end, disableAutoEscapeChars) {
    var queryStart = start;
    var queryEnd = end;
    var escape = false;
    var autoEscapeCharacters = this._autoEscapeCharacters;
    for (var i = start; i <= end; ++i) {
        var ch = str.charCodeAt(i);
        if (ch === 0x23 /*'#'*/) {
            this._parseHash(str, i, end, disableAutoEscapeChars);
            queryEnd = i - 1;
            break;
        }
        else if (!disableAutoEscapeChars && !escape && autoEscapeCharacters[ch] === 1) {
            escape = true;
        }
    }
    if (queryStart > queryEnd) {
        this.search = "";
        return;
    }
    var query;
    if (escape) {
        query = this._getComponentEscaped(str, queryStart, queryEnd, true);
    }
    else {
        query = str.slice(queryStart, queryEnd + 1);
    }
    this.search = query;
};
Url.prototype._parseHash = function Url$_parseHash(str, start, end, disableAutoEscapeChars) {
    if (start > end) {
        this.hash = "";
        return;
    }
    this.hash = disableAutoEscapeChars ?
        str.slice(start, end + 1) : this._getComponentEscaped(str, start, end, true);
};
Object.defineProperty(Url.prototype, "port", {
    get: function() {
        if (this._port >= 0) {
            return ("" + this._port);
        }
        return null;
    },
    set: function(v) {
        if (v == null) {
            this._port = -1;
        }
        else {
            this._port = parseInt(v, 10);
        }
    }
});
Object.defineProperty(Url.prototype, "query", {
    get: function() {
        var query = this._query;
        if (query != null) {
            return query;
        }
        var search = this.search;
        if (search) {
            if (search.charCodeAt(0) === 0x3F /*'?'*/) {
                search = search.slice(1);
            }
            if (search !== "") {
                this._query = search;
                return search;
            }
        }
        return search;
    },
    set: function(v) {
        this._query = v;
    }
});
Object.defineProperty(Url.prototype, "path", {
    get: function() {
        var p = this.pathname || "";
        var s = this.search || "";
        if (p || s) {
            return p + s;
        }
        return (p == null && s) ? ("/" + s) : null;
    },
    set: function() {}
});
Object.defineProperty(Url.prototype, "protocol", {
    get: function() {
        var proto = this._protocol;
        return proto ? proto + ":" : proto;
    },
    set: function(v) {
        if (typeof v === "string") {
            var end = v.length - 1;
            if (v.charCodeAt(end) === 0x3A /*':'*/) {
                this._protocol = v.slice(0, end);
            }
            else {
                this._protocol = v;
            }
        }
        else if (v == null) {
            this._protocol = null;
        }
    }
});
Object.defineProperty(Url.prototype, "href", {
    get: function() {
        var href = this._href;
        if (!href) {
            href = this._href = this.format();
        }
        return href;
    },
    set: function(v) {
        this._href = v;
    }
});
Url.parse = function Url$Parse(str, parseQueryString, hostDenotesSlash, disableAutoEscapeChars) {
    if (str instanceof Url) return str;
    var ret = new Url();
    ret.parse(str, !!parseQueryString, !!hostDenotesSlash, !!disableAutoEscapeChars);
    return ret;
};
Url.format = function Url$Format(obj) {
    if (typeof obj === "string") {
        obj = Url.parse(obj);
    }
    if (!(obj instanceof Url)) {
        return Url.prototype.format.call(obj);
    }
    return obj.format();
};
Url.resolve = function Url$Resolve(source, relative) {
    return Url.parse(source, false, true).resolve(relative);
};
Url.resolveObject = function Url$ResolveObject(source, relative) {
    if (!source) return relative;
    return Url.parse(source, false, true).resolveObject(relative);
};
function _escapePath(pathname) {
    return pathname.replace(/[?#]/g, function(match) {
        return encodeURIComponent(match);
    });
}
function _escapeSearch(search) {
    return search.replace(/#/g, function(match) {
        return encodeURIComponent(match);
    });
}
//Search `char1` (integer code for a character) in `string`
//starting from `fromIndex` and ending at `string.length - 1`
//or when a stop character is found
function containsCharacter(string, char1, fromIndex, stopCharacterTable) {
    var len = string.length;
    for (var i = fromIndex; i < len; ++i) {
        var ch = string.charCodeAt(i);
        if (ch === char1) {
            return true;
        }
        else if (stopCharacterTable[ch] === 1) {
            return false;
        }
    }
    return false;
}
//See if `char1` or `char2` (integer codes for characters)
//is contained in `string`
function containsCharacter2(string, char1, char2) {
    for (var i = 0, len = string.length; i < len; ++i) {
        var ch = string.charCodeAt(i);
        if (ch === char1 || ch === char2) return true;
    }
    return false;
}
//Makes an array of 128 uint8's which represent boolean values.
//Spec is an array of ascii code points or ascii code point ranges
//ranges are expressed as [start, end]
//Create a table with the characters 0x30-0x39 (decimals '0' - '9') and
//0x7A (lowercaseletter 'z') as `true`:
//
//var a = makeAsciiTable([[0x30, 0x39], 0x7A]);
//a[0x30]; //1
//a[0x15]; //0
//a[0x35]; //1
function makeAsciiTable(spec) {
    var ret = new Uint8Array(128);
    spec.forEach(function(item){
        if (typeof item === "number") {
            ret[item] = 1;
        }
        else {
            var start = item[0];
            var end = item[1];
            for (var j = start; j <= end; ++j) {
                ret[j] = 1;
            }
        }
    });
    return ret;
}
var autoEscape = ["<", ">", "\"", "`", " ", "\r", "\n",
    "\t", "{", "}", "|", "\\", "^", "`", "'"];
var autoEscapeMap = new Array(128);
for (var i = 0, len = autoEscapeMap.length; i < len; ++i) {
    autoEscapeMap[i] = "";
}
for (var i = 0, len = autoEscape.length; i < len; ++i) {
    var c = autoEscape[i];
    var esc = encodeURIComponent(c);
    if (esc === c) {
        esc = escape(c);
    }
    autoEscapeMap[c.charCodeAt(0)] = esc;
}
var afterQueryAutoEscapeMap = autoEscapeMap.slice();
autoEscapeMap[0x5C /*'\'*/] = "/";
var slashProtocols = Url.prototype._slashProtocols = {
    http: true,
    https: true,
    gopher: true,
    file: true,
    ftp: true,
    "http:": true,
    "https:": true,
    "gopher:": true,
    "file:": true,
    "ftp:": true
};
//Optimize back from normalized object caused by non-identifier keys
function f(){}
f.prototype = slashProtocols;
Url.prototype._protocolCharacters = makeAsciiTable([
    [0x61 /*'a'*/, 0x7A /*'z'*/],
    [0x41 /*'A'*/, 0x5A /*'Z'*/],
    0x2E /*'.'*/, 0x2B /*'+'*/, 0x2D /*'-'*/
]);
Url.prototype._hostEndingCharacters = makeAsciiTable([
    0x23 /*'#'*/, 0x3F /*'?'*/, 0x2F /*'/'*/, 0x5C /*'\'*/
]);
Url.prototype._autoEscapeCharacters = makeAsciiTable(
    autoEscape.map(function(v) {
        return v.charCodeAt(0);
    })
);
//If these characters end a host name, the path will not be prepended a /
Url.prototype._noPrependSlashHostEnders = makeAsciiTable(
    [
        "<", ">", "'", "`", " ", "\r",
        "\n", "\t", "{", "}", "|",
        "^", "`", "\"", "%", ";"
    ].map(function(v) {
        return v.charCodeAt(0);
    })
);
Url.prototype._autoEscapeMap = autoEscapeMap;
Url.prototype._afterQueryAutoEscapeMap = afterQueryAutoEscapeMap;
Url.replace = function Url$Replace() {
    require.cache.url = {
        exports: Url
    };
};
function isURI (input) {
  try {
    new Url(input)
    return true
  } catch (error) {
    return false
  }
}
return {
  isURI: isURI
}
}())
window.uri_parse = (function () {
/**
 * Created by hustcc on 17/11/11.
 * Contract: i@hust.cc
 */
/*
 * graph from https://github.com/Xsoda/url
 * parse url like this
 *
 * schema://username:password@host:port/path?key=value#fragment;key=value
 * \____/   \______/ \______/ \__/ \__/ \__/ \_______/ \______/ \______/
 *   |         |        |       |    |    |      |         |       |
 * schema      |     password   |   port  |    query    fragment   |
 *          username          host      path                     extension
 *
 * note:
 *   - username, password, port, path, query, fragment, extension is optional.
 *   - scheme, host must be setting.
 *   - username and password must be paired.
 */
function URI(uri) {
  this.uri = uri;
  this._pos = 0;
  // the instance has properties below:
  //
  // this.schema
  // this.username
  // this.password
  // this.host
  // this.port
  // this.path
  // this.query
  // this.fragment
  // this.extension
  this._parse();
}
URI.prototype._end = function() {
  return this._pos >= this.uri.length;
};
URI.prototype._next = function() {
  return this.uri[this._pos += 1];
};
URI.prototype._current = function() {
  return this.uri[this._pos];
};
URI.prototype._skip = function(s) {
  if (!s) this._pos = this.uri.length;
  // skip all char without keyword
  else while (s.indexOf(this._next()) === -1 && !this._end());
};
URI.prototype._sub = function(i) {
  return this.uri.substring(i, this._pos);
};
URI.prototype.all = function() {
  return {
    schema: this.schema,
    host: this.host,
    port: this.port,
    username: this.username,
    password: this.password,
    path: this.path,
    query: this.query,
    fragment: this.fragment,
    extension: this.extension
  };
};
URI.prototype.toURI = function() {
  var uri = '', _t;
  uri += this.schema + '://';
  uri += this.username && this.password ? this.username + ':' + this.password + '@' : '';
  uri += this.host;
  uri += this.port ? ':' + this.port : '';
  uri += this.path ? '/' + this.path : '';
  _t = this._stringifyQuery(this.query);
  uri += _t ? '?' + _t : '';
  uri += this.fragment ? '#' + this.fragment : '';
  _t = this._stringifyQuery(this.extension);
  uri += _t ? ';' + _t : '';
  return uri;
};
URI.prototype._parseQuery = function(query) {
  var qs = query.split('&'),
    len = qs.length,
    r = {},
    t;
  for (var i = 0; i < len; i ++) {
    t = qs[i].split('=');
    if (t[0]) r[t[0]] = t[1];
  }
  return r;
};
URI.prototype._stringifyQuery = function(query) {
  if (!query) return '';
  var q = [];
  Object.keys(query).forEach(function(key) {
    q.push(key + '=' + (query[key] ? query[key] : ''));
  });
  return q.join('&');
};
URI.prototype._parse = function() {
  var i = 0;
  // 1. scheme
  var index = this.uri.indexOf('://');
  if (index === -1) throw new Error('scheme should followed by "://".');
  this._pos = index;
  this.schema = this._sub(i);
  this._pos = index + 3; // skip ://
  i = this._pos;
  // 2. user:pass
  if (this.uri.indexOf('@', this._pos) !== -1) {
    this._skip('@');
    const up = this._sub(i).split(':');
    if (up.length !== 2) throw new Error('username and password must be paired.');
    this.username = up[0];
    this.password = up[1];
    this._next(); // skip @
    i = this._pos;
  }
  // 3. host:port
  this._skip('/?#;');
  const hp = this._sub(i).split(':');
  this.host = hp[0];
  this.port = hp[1];
  i = this._pos;
  // /path, ?query, #fragment, ;extension
  // 4. path
  if (this._current() === '/') {
    this._skip('?#;');
    this.path = this._sub(i + 1);
    i = this._pos;
  }
  // 5. query
  if (this._current() === '?') {
    this._skip('#;');
    this.query = this._parseQuery(this._sub(i + 1));
    i = this._pos;
  }
  // 6. fragment
  if (this._current() === '#') {
    this._skip(';');
    this.fragment = this._sub(i + 1);
    i = this._pos;
  }
  // 7. extension
  if (this._current() === ';') {
    this._skip();
    this.extension = this._parseQuery(this._sub(i + 1));
  }
};
function isURI (input) {
  try {
    new URI(input)
    return true
  } catch (error) {
    return false
  }
}
return {
  isURI: isURI
}
}())
window.webcomponents = (function (scope) {
  'use strict';
  var relative = Object.create(null);
  relative['ftp'] = 21;
  relative['file'] = 0;
  relative['gopher'] = 70;
  relative['http'] = 80;
  relative['https'] = 443;
  relative['ws'] = 80;
  relative['wss'] = 443;
  var relativePathDotMapping = Object.create(null);
  relativePathDotMapping['%2e'] = '.';
  relativePathDotMapping['.%2e'] = '..';
  relativePathDotMapping['%2e.'] = '..';
  relativePathDotMapping['%2e%2e'] = '..';
  function isRelativeScheme(scheme) {
    return relative[scheme] !== undefined;
  }
  function invalid() {
    clear.call(this);
    this._isInvalid = true;
  }
  function IDNAToASCII(h) {
    if ('' == h) {
      invalid.call(this)
    }
    // XXX
    return h.toLowerCase()
  }
  function percentEscape(c) {
    var unicode = c.charCodeAt(0);
    if (unicode > 0x20 &&
       unicode < 0x7F &&
       // " # < > ? `
       [0x22, 0x23, 0x3C, 0x3E, 0x3F, 0x60].indexOf(unicode) == -1
      ) {
      return c;
    }
    return encodeURIComponent(c);
  }
  function percentEscapeQuery(c) {
    // XXX This actually needs to encode c using encoding and then
    // convert the bytes one-by-one.
    var unicode = c.charCodeAt(0);
    if (unicode > 0x20 &&
       unicode < 0x7F &&
       // " # < > ` (do not escape '?')
       [0x22, 0x23, 0x3C, 0x3E, 0x60].indexOf(unicode) == -1
      ) {
      return c;
    }
    return encodeURIComponent(c);
  }
  var EOF = undefined,
      ALPHA = /[a-zA-Z]/,
      ALPHANUMERIC = /[a-zA-Z0-9\+\-\.]/;
  function parse(input, stateOverride, base) {
    function err(message) {
      errors.push(message)
    }
    var state = stateOverride || 'scheme start',
        cursor = 0,
        buffer = '',
        seenAt = false,
        seenBracket = false,
        errors = [];
    loop: while ((input[cursor - 1] != EOF || cursor == 0) && !this._isInvalid) {
      var c = input[cursor];
      switch (state) {
        case 'scheme start':
          if (c && ALPHA.test(c)) {
            buffer += c.toLowerCase(); // ASCII-safe
            state = 'scheme';
          } else if (!stateOverride) {
            buffer = '';
            state = 'no scheme';
            continue;
          } else {
            err('Invalid scheme.');
            break loop;
          }
          break;
        case 'scheme':
          if (c && ALPHANUMERIC.test(c)) {
            buffer += c.toLowerCase(); // ASCII-safe
          } else if (':' == c) {
            this._scheme = buffer;
            buffer = '';
            if (stateOverride) {
              break loop;
            }
            if (isRelativeScheme(this._scheme)) {
              this._isRelative = true;
            }
            if ('file' == this._scheme) {
              state = 'relative';
            } else if (this._isRelative && base && base._scheme == this._scheme) {
              state = 'relative or authority';
            } else if (this._isRelative) {
              state = 'authority first slash';
            } else {
              state = 'scheme data';
            }
          } else if (!stateOverride) {
            buffer = '';
            cursor = 0;
            state = 'no scheme';
            continue;
          } else if (EOF == c) {
            break loop;
          } else {
            err('Code point not allowed in scheme: ' + c)
            break loop;
          }
          break;
        case 'scheme data':
          if ('?' == c) {
            this._query = '?';
            state = 'query';
          } else if ('#' == c) {
            this._fragment = '#';
            state = 'fragment';
          } else {
            // XXX error handling
            if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
              this._schemeData += percentEscape(c);
            }
          }
          break;
        case 'no scheme':
          if (!base || !(isRelativeScheme(base._scheme))) {
            err('Missing scheme.');
            invalid.call(this);
          } else {
            state = 'relative';
            continue;
          }
          break;
        case 'relative or authority':
          if ('/' == c && '/' == input[cursor+1]) {
            state = 'authority ignore slashes';
          } else {
            err('Expected /, got: ' + c);
            state = 'relative';
            continue
          }
          break;
        case 'relative':
          this._isRelative = true;
          if ('file' != this._scheme)
            this._scheme = base._scheme;
          if (EOF == c) {
            this._host = base._host;
            this._port = base._port;
            this._path = base._path.slice();
            this._query = base._query;
            this._username = base._username;
            this._password = base._password;
            break loop;
          } else if ('/' == c || '\\' == c) {
            if ('\\' == c)
              err('\\ is an invalid code point.');
            state = 'relative slash';
          } else if ('?' == c) {
            this._host = base._host;
            this._port = base._port;
            this._path = base._path.slice();
            this._query = '?';
            this._username = base._username;
            this._password = base._password;
            state = 'query';
          } else if ('#' == c) {
            this._host = base._host;
            this._port = base._port;
            this._path = base._path.slice();
            this._query = base._query;
            this._fragment = '#';
            this._username = base._username;
            this._password = base._password;
            state = 'fragment';
          } else {
            var nextC = input[cursor+1]
            var nextNextC = input[cursor+2]
            if (
              'file' != this._scheme || !ALPHA.test(c) ||
              (nextC != ':' && nextC != '|') ||
              (EOF != nextNextC && '/' != nextNextC && '\\' != nextNextC && '?' != nextNextC && '#' != nextNextC)) {
              this._host = base._host;
              this._port = base._port;
              this._username = base._username;
              this._password = base._password;
              this._path = base._path.slice();
              this._path.pop();
            }
            state = 'relative path';
            continue;
          }
          break;
        case 'relative slash':
          if ('/' == c || '\\' == c) {
            if ('\\' == c) {
              err('\\ is an invalid code point.');
            }
            if ('file' == this._scheme) {
              state = 'file host';
            } else {
              state = 'authority ignore slashes';
            }
          } else {
            if ('file' != this._scheme) {
              this._host = base._host;
              this._port = base._port;
              this._username = base._username;
              this._password = base._password;
            }
            state = 'relative path';
            continue;
          }
          break;
        case 'authority first slash':
          if ('/' == c) {
            state = 'authority second slash';
          } else {
            err("Expected '/', got: " + c);
            state = 'authority ignore slashes';
            continue;
          }
          break;
        case 'authority second slash':
          state = 'authority ignore slashes';
          if ('/' != c) {
            err("Expected '/', got: " + c);
            continue;
          }
          break;
        case 'authority ignore slashes':
          if ('/' != c && '\\' != c) {
            state = 'authority';
            continue;
          } else {
            err('Expected authority, got: ' + c);
          }
          break;
        case 'authority':
          if ('@' == c) {
            if (seenAt) {
              err('@ already seen.');
              buffer += '%40';
            }
            seenAt = true;
            for (var i = 0; i < buffer.length; i++) {
              var cp = buffer[i];
              if ('\t' == cp || '\n' == cp || '\r' == cp) {
                err('Invalid whitespace in authority.');
                continue;
              }
              // XXX check URL code points
              if (':' == cp && null === this._password) {
                this._password = '';
                continue;
              }
              var tempC = percentEscape(cp);
              (null !== this._password) ? this._password += tempC : this._username += tempC;
            }
            buffer = '';
          } else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
            cursor -= buffer.length;
            buffer = '';
            state = 'host';
            continue;
          } else {
            buffer += c;
          }
          break;
        case 'file host':
          if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
            if (buffer.length == 2 && ALPHA.test(buffer[0]) && (buffer[1] == ':' || buffer[1] == '|')) {
              state = 'relative path';
            } else if (buffer.length == 0) {
              state = 'relative path start';
            } else {
              this._host = IDNAToASCII.call(this, buffer);
              buffer = '';
              state = 'relative path start';
            }
            continue;
          } else if ('\t' == c || '\n' == c || '\r' == c) {
            err('Invalid whitespace in file host.');
          } else {
            buffer += c;
          }
          break;
        case 'host':
        case 'hostname':
          if (':' == c && !seenBracket) {
            // XXX host parsing
            this._host = IDNAToASCII.call(this, buffer);
            buffer = '';
            state = 'port';
            if ('hostname' == stateOverride) {
              break loop;
            }
          } else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
            this._host = IDNAToASCII.call(this, buffer);
            buffer = '';
            state = 'relative path start';
            if (stateOverride) {
              break loop;
            }
            continue;
          } else if ('\t' != c && '\n' != c && '\r' != c) {
            if ('[' == c) {
              seenBracket = true;
            } else if (']' == c) {
              seenBracket = false;
            }
            buffer += c;
          } else {
            err('Invalid code point in host/hostname: ' + c);
          }
          break;
        case 'port':
          if (/[0-9]/.test(c)) {
            buffer += c;
          } else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c || stateOverride) {
            if ('' != buffer) {
              var temp = parseInt(buffer, 10);
              if (temp != relative[this._scheme]) {
                this._port = temp + '';
              }
              buffer = '';
            }
            if (stateOverride) {
              break loop;
            }
            state = 'relative path start';
            continue;
          } else if ('\t' == c || '\n' == c || '\r' == c) {
            err('Invalid code point in port: ' + c);
          } else {
            invalid.call(this);
          }
          break;
        case 'relative path start':
          if ('\\' == c)
            err("'\\' not allowed in path.");
          state = 'relative path';
          if ('/' != c && '\\' != c) {
            continue;
          }
          break;
        case 'relative path':
          if (EOF == c || '/' == c || '\\' == c || (!stateOverride && ('?' == c || '#' == c))) {
            if ('\\' == c) {
              err('\\ not allowed in relative path.');
            }
            var tmp;
            if (tmp = relativePathDotMapping[buffer.toLowerCase()]) {
              buffer = tmp;
            }
            if ('..' == buffer) {
              this._path.pop();
              if ('/' != c && '\\' != c) {
                this._path.push('');
              }
            } else if ('.' == buffer && '/' != c && '\\' != c) {
              this._path.push('');
            } else if ('.' != buffer) {
              if ('file' == this._scheme && this._path.length == 0 && buffer.length == 2 && ALPHA.test(buffer[0]) && buffer[1] == '|') {
                buffer = buffer[0] + ':';
              }
              this._path.push(buffer);
            }
            buffer = '';
            if ('?' == c) {
              this._query = '?';
              state = 'query';
            } else if ('#' == c) {
              this._fragment = '#';
              state = 'fragment';
            }
          } else if ('\t' != c && '\n' != c && '\r' != c) {
            buffer += percentEscape(c);
          }
          break;
        case 'query':
          if (!stateOverride && '#' == c) {
            this._fragment = '#';
            state = 'fragment';
          } else if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
            this._query += percentEscapeQuery(c);
          }
          break;
        case 'fragment':
          if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
            this._fragment += c;
          }
          break;
      }
      cursor++;
    }
  }
  function clear() {
    this._scheme = '';
    this._schemeData = '';
    this._username = '';
    this._password = null;
    this._host = '';
    this._port = '';
    this._path = [];
    this._query = '';
    this._fragment = '';
    this._isInvalid = false;
    this._isRelative = false;
  }
  // Does not process domain names or IP addresses.
  // Does not handle encoding for the query parameter.
  function jURL(url, base /* , encoding */) {
    if (base !== undefined && !(base instanceof jURL))
      base = new jURL(String(base));
    this._url = url;
    clear.call(this);
    var input = url.replace(/^[ \t\r\n\f]+|[ \t\r\n\f]+$/g, '');
    // encoding = encoding || 'utf-8'
    parse.call(this, input, null, base);
  }
  jURL.prototype = {
    toString: function() {
      return this.href;
    },
    get href() {
      if (this._isInvalid)
        return this._url;
      var authority = '';
      if ('' != this._username || null != this._password) {
        authority = this._username +
            (null != this._password ? ':' + this._password : '') + '@';
      }
      return this.protocol +
          (this._isRelative ? '//' + authority + this.host : '') +
          this.pathname + this._query + this._fragment;
    },
    set href(href) {
      clear.call(this);
      parse.call(this, href);
    },
    get protocol() {
      return this._scheme + ':';
    },
    set protocol(protocol) {
      if (this._isInvalid)
        return;
      parse.call(this, protocol + ':', 'scheme start');
    },
    get host() {
      return this._isInvalid ? '' : this._port ?
          this._host + ':' + this._port : this._host;
    },
    set host(host) {
      if (this._isInvalid || !this._isRelative)
        return;
      parse.call(this, host, 'host');
    },
    get hostname() {
      return this._host;
    },
    set hostname(hostname) {
      if (this._isInvalid || !this._isRelative)
        return;
      parse.call(this, hostname, 'hostname');
    },
    get port() {
      return this._port;
    },
    set port(port) {
      if (this._isInvalid || !this._isRelative)
        return;
      parse.call(this, port, 'port');
    },
    get pathname() {
      return this._isInvalid ? '' : this._isRelative ?
          '/' + this._path.join('/') : this._schemeData;
    },
    set pathname(pathname) {
      if (this._isInvalid || !this._isRelative)
        return;
      this._path = [];
      parse.call(this, pathname, 'relative path start');
    },
    get search() {
      return this._isInvalid || !this._query || '?' == this._query ?
          '' : this._query;
    },
    set search(search) {
      if (this._isInvalid || !this._isRelative)
        return;
      this._query = '?';
      if ('?' == search[0])
        search = search.slice(1);
      parse.call(this, search, 'query');
    },
    get hash() {
      return this._isInvalid || !this._fragment || '#' == this._fragment ?
          '' : this._fragment;
    },
    set hash(hash) {
      if (this._isInvalid)
        return;
      this._fragment = '#';
      if ('#' == hash[0])
        hash = hash.slice(1);
      parse.call(this, hash, 'fragment');
    },
    get origin() {
      var host;
      if (this._isInvalid || !this._scheme) {
        return '';
      }
      // javascript: Gecko returns String(""), WebKit/Blink String("null")
      // Gecko throws error for "data://"
      // data: Gecko returns "", Blink returns "data://", WebKit returns "null"
      // Gecko returns String("") for file: mailto:
      // WebKit/Blink returns String("SCHEME://") for file: mailto:
      switch (this._scheme) {
        case 'data':
        case 'file':
        case 'javascript':
        case 'mailto':
          return 'null';
      }
      host = this.host;
      if (!host) {
        return '';
      }
      return this._scheme + '://' + host;
    }
  };
  // Copy over the static methods
  var OriginalURL = scope.URL;
  if (OriginalURL) {
    jURL.createObjectURL = function(blob) {
      // IE extension allows a second optional options argument.
      // http://msdn.microsoft.com/en-us/library/ie/hh772302(v=vs.85).aspx
      return OriginalURL.createObjectURL.apply(OriginalURL, arguments);
    };
    jURL.revokeObjectURL = function(url) {
      OriginalURL.revokeObjectURL(url);
    };
  }
  scope.URL = jURL;
function isURI (input) {
  try {
    new jURL(input)
    return true
  } catch (error) {
    return false
  }
}
return {
  isURI: isURI
}
}(window))
window.native = (function () {
function isURI (input) {
  try {
    new URL(input)
  } catch (error) {}
}
return {
  isURI: isURI
}
}())
Tests:
  • webcomponents/URL module

     
    webcomponents.isURI('http://localhost/')
    webcomponents.isURI('http://example.w3.org/path%20with%20spaces.html')
    webcomponents.isURI('http://example.w3.org/%20')
    webcomponents.isURI('ftp://ftp.is.co.za/rfc/rfc1808.txt')
    webcomponents.isURI('ftp://ftp.is.co.za/../../../rfc/rfc1808.txt')
    webcomponents.isURI('http://www.ietf.org/rfc/webcomponents.isURI.txt')
    webcomponents.isURI('mailto:John.Doe@example.com')
    webcomponents.isURI('news:comp.infosystems.www.servers.unix')
    webcomponents.isURI('tel:+1-816-555-1212')
    webcomponents.isURI('telnet://192.0.2.16:80/')
    webcomponents.isURI('urn:oasis:names:specification:docbook:dtd:xml:4.1.2')
  • uri-parse module

     
    uri_parse.isURI('http://localhost/')
    uri_parse.isURI('http://example.w3.org/path%20with%20spaces.html')
    uri_parse.isURI('http://example.w3.org/%20')
    uri_parse.isURI('ftp://ftp.is.co.za/rfc/rfc1808.txt')
    uri_parse.isURI('ftp://ftp.is.co.za/../../../rfc/rfc1808.txt')
    uri_parse.isURI('http://www.ietf.org/rfc/uri_parse.isURI.txt')
    uri_parse.isURI('mailto:John.Doe@example.com')
    uri_parse.isURI('news:comp.infosystems.www.servers.unix')
    uri_parse.isURI('tel:+1-816-555-1212')
    uri_parse.isURI('telnet://192.0.2.16:80/')
    uri_parse.isURI('urn:oasis:names:specification:docbook:dtd:xml:4.1.2')
  • url-parse module

     
    url_parse.isURI('http://localhost/')
    url_parse.isURI('http://example.w3.org/path%20with%20spaces.html')
    url_parse.isURI('http://example.w3.org/%20')
    url_parse.isURI('ftp://ftp.is.co.za/rfc/rfc1808.txt')
    url_parse.isURI('ftp://ftp.is.co.za/../../../rfc/rfc1808.txt')
    url_parse.isURI('http://www.ietf.org/rfc/url_parse.isURI.txt')
    url_parse.isURI('mailto:John.Doe@example.com')
    url_parse.isURI('news:comp.infosystems.www.servers.unix')
    url_parse.isURI('tel:+1-816-555-1212')
    url_parse.isURI('telnet://192.0.2.16:80/')
    url_parse.isURI('urn:oasis:names:specification:docbook:dtd:xml:4.1.2')
  • urlparser module

     
    urlparser.isURI('http://localhost/')
    urlparser.isURI('http://example.w3.org/path%20with%20spaces.html')
    urlparser.isURI('http://example.w3.org/%20')
    urlparser.isURI('ftp://ftp.is.co.za/rfc/rfc1808.txt')
    urlparser.isURI('ftp://ftp.is.co.za/../../../rfc/rfc1808.txt')
    urlparser.isURI('http://www.ietf.org/rfc/urlparser.isURI.txt')
    urlparser.isURI('mailto:John.Doe@example.com')
    urlparser.isURI('news:comp.infosystems.www.servers.unix')
    urlparser.isURI('tel:+1-816-555-1212')
    urlparser.isURI('telnet://192.0.2.16:80/')
    urlparser.isURI('urn:oasis:names:specification:docbook:dtd:xml:4.1.2')
  • BNF from RFC 3986

     
    rfc3986.isURI('http://localhost/')
    rfc3986.isURI('http://example.w3.org/path%20with%20spaces.html')
    rfc3986.isURI('http://example.w3.org/%20')
    rfc3986.isURI('ftp://ftp.is.co.za/rfc/rfc1808.txt')
    rfc3986.isURI('ftp://ftp.is.co.za/../../../rfc/rfc1808.txt')
    rfc3986.isURI('http://www.ietf.org/rfc/rfc3986.isURI.txt')
    rfc3986.isURI('mailto:John.Doe@example.com')
    rfc3986.isURI('news:comp.infosystems.www.servers.unix')
    rfc3986.isURI('tel:+1-816-555-1212')
    rfc3986.isURI('telnet://192.0.2.16:80/')
    rfc3986.isURI('urn:oasis:names:specification:docbook:dtd:xml:4.1.2')
  • RegExp from RFC 3986 plus additional checks

     
    regexp.isURI('http://localhost/')
    regexp.isURI('http://example.w3.org/path%20with%20spaces.html')
    regexp.isURI('http://example.w3.org/%20')
    regexp.isURI('ftp://ftp.is.co.za/rfc/rfc1808.txt')
    regexp.isURI('ftp://ftp.is.co.za/../../../rfc/rfc1808.txt')
    regexp.isURI('http://www.ietf.org/rfc/regexp.isURI.txt')
    regexp.isURI('mailto:John.Doe@example.com')
    regexp.isURI('news:comp.infosystems.www.servers.unix')
    regexp.isURI('tel:+1-816-555-1212')
    regexp.isURI('telnet://192.0.2.16:80/')
    regexp.isURI('urn:oasis:names:specification:docbook:dtd:xml:4.1.2')
  • BNF from RFC 2396

     
    rfc2396.isURI('http://localhost/')
    rfc2396.isURI('http://example.w3.org/path%20with%20spaces.html')
    rfc2396.isURI('http://example.w3.org/%20')
    rfc2396.isURI('ftp://ftp.is.co.za/rfc/rfc1808.txt')
    rfc2396.isURI('ftp://ftp.is.co.za/../../../rfc/rfc1808.txt')
    rfc2396.isURI('http://www.ietf.org/rfc/rfc3986.isURI.txt')
    rfc2396.isURI('mailto:John.Doe@example.com')
    rfc2396.isURI('news:comp.infosystems.www.servers.unix')
    rfc2396.isURI('tel:+1-816-555-1212')
    rfc2396.isURI('telnet://192.0.2.16:80/')
    rfc2396.isURI('urn:oasis:names:specification:docbook:dtd:xml:4.1.2')
  • native browser URL

     
    native.isURI('http://localhost/')
    native.isURI('http://example.w3.org/path%20with%20spaces.html')
    native.isURI('http://example.w3.org/%20')
    native.isURI('ftp://ftp.is.co.za/rfc/rfc1808.txt')
    native.isURI('ftp://ftp.is.co.za/../../../rfc/rfc1808.txt')
    native.isURI('http://www.ietf.org/rfc/native.isURI.txt')
    native.isURI('mailto:John.Doe@example.com')
    native.isURI('news:comp.infosystems.www.servers.unix')
    native.isURI('tel:+1-816-555-1212')
    native.isURI('telnet://192.0.2.16:80/')
    native.isURI('urn:oasis:names:specification:docbook:dtd:xml:4.1.2')
Rendered benchmark preparation results:

Suite status: <idle, ready to run>

Previous results

Experimental features:

  • Test case name Result
    webcomponents/URL module
    uri-parse module
    url-parse module
    urlparser module
    BNF from RFC 3986
    RegExp from RFC 3986 plus additional checks
    BNF from RFC 2396
    native browser URL

    Fastest: N/A

    Slowest: N/A

Latest run results:
Run details: (Test run date: 3 years ago)
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36
Chrome 99 on Mac OS X 10.15.7
View result in a separate tab
Test name Executions per second
webcomponents/URL module 15528.2 Ops/sec
uri-parse module 25423.6 Ops/sec
url-parse module 12276.9 Ops/sec
urlparser module 606363.9 Ops/sec
BNF from RFC 3986 5284.0 Ops/sec
RegExp from RFC 3986 plus additional checks 54491.9 Ops/sec
BNF from RFC 2396 3966.2 Ops/sec
native browser URL 13536.6 Ops/sec