(function (root, factory){ if (typeof exports === 'object') { module.exports = factory(require('./punycode'), require('./IPv6'), require('./SecondLevelDomains')); } else if (typeof define === 'function' && define.amd) { define(['./punycode', './IPv6', './SecondLevelDomains'] , factory); } else { root.URI = factory(root.punycode, root.IPv6, root.SecondLevelDomains); } } (this, function (punycode, IPv6, SLD){ "use strict"; function URI(url, base){ if (!(this instanceof URI)) { return new URI(url, base); } if (url === undefined) { if (typeof _AN_Read_location("location", window) !== 'undefined') { url = _AN_Read_href('href', _AN_Read_location('location', window)) + ""; } else { url = ""; } } _AN_Call_href("href", this, url); if (base !== undefined) { return this.absoluteTo(base); } return this; } ; var p = URI.prototype; var hasOwn = Object.prototype.hasOwnProperty; function escapeRegEx(string){ return _AN_Call_replace("replace", string, /([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); } function isArray(obj){ return String(Object.prototype.toString.call(obj)) === "[object Array]"; } function filterArrayValues(data, value){ var lookup = { } ; var i, length; if (isArray(value)) { for (i = 0, length = _AN_Read_length("length", value); i < length; i++ ){ lookup[value[i]] = true ; } } else { lookup[value] = true ; } for (i = 0, length = _AN_Read_length("length", data); i < length; i++ ){ if (lookup[data[i]] !== undefined) { data.splice(i, 1); length-- ; i-- ; } } return data; } URI._parts = function (){ return { protocol: null , username: null , password: null , hostname: null , urn: null , port: null , path: null , query: null , fragment: null , duplicateQueryParameters: URI.duplicateQueryParameters} ; } ; URI.duplicateQueryParameters = false ; URI.protocol_expression = /^[a-z][a-z0-9-+-]*$/i; URI.idn_expression = /[^a-z0-9\.-]/i; URI.punycode_expression = /(xn--)/i; URI.ip4_expression = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/; URI.ip6_expression = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/; URI.find_uri_expression = /\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/ig; URI.defaultPorts = { http: "80", https: "443", ftp: "21", gopher: "70", ws: "80", wss: "443"} ; URI.invalid_hostname_characters = /[^a-zA-Z0-9\.-]/; function strictEncodeURIComponent(string){ return _AN_Call_replace("replace", _AN_Call_replace("replace", encodeURIComponent(string), /[!'()*]/g, escape), /\*/g, "%2A"); } URI.encode = strictEncodeURIComponent; URI.decode = decodeURIComponent; URI.iso8859 = function (){ URI.encode = escape; URI.decode = unescape; } ; URI.unicode = function (){ URI.encode = strictEncodeURIComponent; URI.decode = decodeURIComponent; } ; URI.characters = { pathname: { encode: { expression: /%(24|26|2B|2C|3B|3D|3A|40)/ig, map: { "%24": "$", "%26": "&", "%2B": "+", "%2C": ",", "%3B": ";", "%3D": "=", "%3A": ":", "%40": "@"} } , decode: { expression: /[\/\?#]/g, map: { "/": "%2F", "?": "%3F", "#": "%23"} } } , reserved: { encode: { expression: /%(21|23|24|26|27|28|29|2A|2B|2C|2F|3A|3B|3D|3F|40|5B|5D)/ig, map: { "%3A": ":", "%2F": "/", "%3F": "?", "%23": "#", "%5B": "[", "%5D": "]", "%40": "@", "%21": "!", "%24": "$", "%26": "&", "%27": "'", "%28": "(", "%29": ")", "%2A": "*", "%2B": "+", "%2C": ",", "%3B": ";", "%3D": "="} } } } ; URI.encodeQuery = function (string){ return _AN_Call_replace("replace", URI.encode(string + ""), /%20/g, '+'); } ; URI.decodeQuery = function (string){ return URI.decode(_AN_Call_replace('replace', (string + ""), /\+/g, '%20')); } ; URI.recodePath = function (string){ var segments = (string + "").split('/'); for (var i = 0, length = _AN_Read_length('length', segments); i < length; i++ ){ segments[i] = URI.encodePathSegment(URI.decode(segments[i])); } return segments.join('/'); } ; URI.decodePath = function (string){ var segments = (string + "").split('/'); for (var i = 0, length = _AN_Read_length('length', segments); i < length; i++ ){ segments[i] = URI.decodePathSegment(segments[i]); } return segments.join('/'); } ; var _parts = { 'encode': 'encode', 'decode': 'decode'} ; var _part; var generateAccessor = function (_group, _part){ return function (string){ return _AN_Call_replace('replace', URI[_part](string + ""), URI.characters[_group][_part].expression, function (c){ return URI.characters[_group][_part].map[c]; } ); } ; } ; for (_part in _parts){ URI[_part + "PathSegment"] = generateAccessor("pathname", _parts[_part]); } URI.encodeReserved = generateAccessor("reserved", "encode"); URI.parse = function (string, parts){ var pos, t; if (!parts) { parts = { } ; } pos = string.indexOf('#'); if (pos > -1) { parts.fragment = string.substring(pos + 1) || null ; string = string.substring(0, pos); } pos = string.indexOf('?'); if (pos > -1) { parts.query = string.substring(pos + 1) || null ; string = string.substring(0, pos); } if (string.substring(0, 2) === '//') { _AN_Write_protocol('protocol', parts, false , ''); string = string.substring(2); string = URI.parseAuthority(string, parts); } else { pos = string.indexOf(':'); if (pos > -1) { _AN_Write_protocol('protocol', parts, false , string.substring(0, pos)); if (_AN_Read_protocol('protocol', parts) && !_AN_Read_protocol('protocol', parts).match(URI.protocol_expression)) { _AN_Write_protocol('protocol', parts, false , undefined); } else if (_AN_Read_protocol('protocol', parts) === 'file') { string = string.substring(pos + 3); } else if (string.substring(pos + 1, pos + 3) === '//') { string = string.substring(pos + 3); string = URI.parseAuthority(string, parts); } else { string = string.substring(pos + 1); parts.urn = true ; } } } parts.path = string; return parts; } ; URI.parseHost = function (string, parts){ var pos = string.indexOf('/'); var bracketPos; var t; if (pos === -1) { pos = _AN_Read_length('length', string); } if (string[0] === "[") { bracketPos = string.indexOf(']'); _AN_Write_hostname('hostname', parts, false , string.substring(1, bracketPos) || null ); _AN_Write_port('port', parts, false , string.substring(bracketPos + 2, pos) || null ); } else if (string.indexOf(':') !== string.lastIndexOf(':')) { _AN_Write_hostname('hostname', parts, false , string.substring(0, pos) || null ); _AN_Write_port('port', parts, false , null ); } else { t = string.substring(0, pos).split(':'); _AN_Write_hostname('hostname', parts, false , t[0] || null ); _AN_Write_port('port', parts, false , t[1] || null ); } if (_AN_Read_hostname('hostname', parts) && string.substring(pos)[0] !== '/') { pos++ ; string = "/" + string; } return string.substring(pos) || '/'; } ; URI.parseAuthority = function (string, parts){ string = URI.parseUserinfo(string, parts); return URI.parseHost(string, parts); } ; URI.parseUserinfo = function (string, parts){ var pos = string.indexOf('@'); var firstSlash = string.indexOf('/'); var t; if (pos > -1 && (firstSlash === -1 || pos < firstSlash)) { t = string.substring(0, pos).split(':'); parts.username = t[0]? URI.decode(t[0]): null ; t.shift(); parts.password = t[0]? URI.decode(t.join(':')): null ; string = string.substring(pos + 1); } else { parts.username = null ; parts.password = null ; } return string; } ; URI.parseQuery = function (string){ if (!string) { return { } ; } string = _AN_Call_replace('replace', _AN_Call_replace('replace', string, /&+/g, '&'), /^\?*&*|&+$/g, ''); if (!string) { return { } ; } var items = { } ; var splits = string.split('&'); var length = _AN_Read_length('length', splits); var v, name, value; for (var i = 0; i < length; i++ ){ v = splits[i].split('='); name = URI.decodeQuery(v.shift()); value = _AN_Read_length('length', v)? URI.decodeQuery(v.join('=')): null ; if (items[name]) { if (typeof items[name] === "string") { items[name] = [items[name]] ; } items[name].push(value); } else { items[name] = value; } } return items; } ; URI.build = function (parts){ var t = ""; if (parts.protocol) { t += _AN_Read_protocol("protocol", parts) + ":"; } if (!parts.urn && (t || _AN_Read_hostname("hostname", parts))) { t += '//'; } t += (URI.buildAuthority(parts) || ''); if (typeof parts.path === "string") { if (parts.path[0] !== '/' && typeof _AN_Read_hostname('hostname', parts) === "string") { t += '/'; } t += parts.path; } if (typeof parts.query === "string" && parts.query) { t += '?' + parts.query; } if (typeof parts.fragment === "string" && parts.fragment) { t += '#' + parts.fragment; } return t; } ; URI.buildHost = function (parts){ var t = ""; if (!_AN_Read_hostname("hostname", parts)) { return ""; } else if (URI.ip6_expression.test(_AN_Read_hostname("hostname", parts))) { if (parts.port) { t += "[" + _AN_Read_hostname("hostname", parts) + "]:" + _AN_Read_port("port", parts); } else { t += _AN_Read_hostname("hostname", parts); } } else { t += _AN_Read_hostname("hostname", parts); if (parts.port) { t += ':' + _AN_Read_port('port', parts); } } return t; } ; URI.buildAuthority = function (parts){ return URI.buildUserinfo(parts) + URI.buildHost(parts); } ; URI.buildUserinfo = function (parts){ var t = ""; if (parts.username) { t += URI.encode(parts.username); if (parts.password) { t += ':' + URI.encode(parts.password); } t += "@"; } return t; } ; URI.buildQuery = function (data, duplicates){ var t = ""; var unique, key, i, length; for (key in data){ if (hasOwn.call(data, key) && key) { if (isArray(data[key])) { unique = { } ; for (i = 0, length = _AN_Read_length("length", data[key]); i < length; i++ ){ if (data[key][i] !== undefined && unique[data[key][i] + ""] === undefined) { t += "&" + URI.buildQueryParameter(key, data[key][i]); if (duplicates !== true ) { unique[data[key][i] + ""] = true ; } } } } else if (data[key] !== undefined) { t += '&' + URI.buildQueryParameter(key, data[key]); } } } return t.substring(1); } ; URI.buildQueryParameter = function (name, value){ return URI.encodeQuery(name) + (value !== null ? "=" + URI.encodeQuery(value): ""); } ; URI.addQuery = function (data, name, value){ if (typeof name === "object") { for (var key in name){ if (hasOwn.call(name, key)) { URI.addQuery(data, key, name[key]); } } } else if (typeof name === "string") { if (data[name] === undefined) { data[name] = value; return ; } else if (typeof data[name] === "string") { data[name] = [data[name]] ; } if (!isArray(value)) { value = [value] ; } data[name] = data[name].concat(value); } else { throw new TypeError("URI.addQuery() accepts an object, string as the name parameter") } } ; URI.removeQuery = function (data, name, value){ var i, length, key; if (isArray(name)) { for (i = 0, length = _AN_Read_length("length", name); i < length; i++ ){ data[name[i]] = undefined; } } else if (typeof name === "object") { for (key in name){ if (hasOwn.call(name, key)) { URI.removeQuery(data, key, name[key]); } } } else if (typeof name === "string") { if (value !== undefined) { if (data[name] === value) { data[name] = undefined; } else if (isArray(data[name])) { data[name] = filterArrayValues(data[name], value); } } else { data[name] = undefined; } } else { throw new TypeError("URI.addQuery() accepts an object, string as the first parameter") } } ; URI.commonPath = function (one, two){ var length = Math.min(_AN_Read_length("length", one), _AN_Read_length("length", two)); var pos; for (pos = 0; pos < length; pos++ ){ if (one[pos] !== two[pos]) { pos-- ; break ; } } if (pos < 1) { return one[0] === two[0] && one[0] === '/'? '/': ''; } if (one[pos] !== '/') { pos = one.substring(0, pos).lastIndexOf('/'); } return one.substring(0, pos + 1); } ; URI.withinString = function (string, callback){ return _AN_Call_replace('replace', string, URI.find_uri_expression, callback); } ; URI.ensureValidHostname = function (v){ if (v.match(URI.invalid_hostname_characters)) { if (!punycode) { throw new TypeError("Hostname '" + v + "' contains characters other than [A-Z0-9.-] and Punycode.js is not available") } if (punycode.toASCII(v).match(URI.invalid_hostname_characters)) { throw new TypeError("Hostname '" + v + "' contains characters other than [A-Z0-9.-]") } } } ; p.build = function (deferBuild){ if (deferBuild === true ) { this._deferred_build = true ; } else if (deferBuild === undefined || this._deferred_build) { this._string = URI.build(this._parts); this._deferred_build = false ; } return this; } ; p.clone = function (){ return new URI(this); } ; p.valueOf = p.toString = function (){ return this.build(false )._string; } ; _parts = { protocol: 'protocol', username: 'username', password: 'password', hostname: 'hostname', port: 'port'} ; generateAccessor = function (_part){ return function (v, build){ if (v === undefined) { return this._parts[_part] || ""; } else { this._parts[_part] = v; this.build(!build); return this; } } ; } ; for (_part in _parts){ p[_part] = generateAccessor(_parts[_part]); } _parts = { query: '?', fragment: '#'} ; generateAccessor = function (_part, _key){ return function (v, build){ if (v === undefined) { return this._parts[_part] || ""; } else { if (v !== null ) { v = v + ""; if (v[0] === _key) { v = v.substring(1); } } this._parts[_part] = v; this.build(!build); return this; } } ; } ; for (_part in _parts){ p[_part] = generateAccessor(_part, _parts[_part]); } _parts = { search: ['?', 'query'] , hash: ['#', 'fragment'] } ; generateAccessor = function (_part, _key){ return function (v, build){ var t = this[_part](v, build); return typeof t === "string" && _AN_Read_length("length", t)? (_key + t): t; } ; } ; for (_part in _parts){ p[_part] = generateAccessor(_parts[_part][1], _parts[_part][0]); } p.pathname = function (v, build){ if (v === undefined || v === true ) { var res = this._parts.path || (this._parts.urn? '': '/'); return v? URI.decodePath(res): res; } else { this._parts.path = v? URI.recodePath(v): "/"; this.build(!build); return this; } } ; p.path = _AN_Read_pathname("pathname", p); p.href = function (href, build){ var key; if (href === undefined) { return this.toString(); } this._string = ""; this._parts = URI._parts(); var _URI = href instanceof URI; var _object = typeof href === "object" && (_AN_Read_hostname("hostname", href) || href.path); if (!_URI && _object && Object.prototype.toString.call(href) !== "[object Object]") { href = href.toString(); } if (typeof href === "string") { this._parts = URI.parse(href, this._parts); } else if (_URI || _object) { var src = _URI? href._parts: href; for (key in src){ if (hasOwn.call(this._parts, key)) { this._parts[key] = src[key]; } } } else { throw new TypeError("invalid input") } this.build(!build); return this; } ; p.is = function (what){ var ip = false ; var ip4 = false ; var ip6 = false ; var name = false ; var sld = false ; var idn = false ; var punycode = false ; var relative = !this._parts.urn; if (this._parts.hostname) { relative = false ; ip4 = URI.ip4_expression.test(_AN_Read_hostname("hostname", this._parts)); ip6 = URI.ip6_expression.test(_AN_Read_hostname("hostname", this._parts)); ip = ip4 || ip6; name = !ip; sld = name && SLD && SLD.has(_AN_Read_hostname("hostname", this._parts)); idn = name && URI.idn_expression.test(_AN_Read_hostname("hostname", this._parts)); punycode = name && URI.punycode_expression.test(_AN_Read_hostname("hostname", this._parts)); } switch (what.toLowerCase()){ case 'relative': return relative; case 'absolute': return !relative; case 'domain': case 'name': return name; case 'sld': return sld; case 'ip': return ip; case 'ip4': case 'ipv4': case 'inet4': return ip4; case 'ip6': case 'ipv6': case 'inet6': return ip6; case 'idn': return idn; case 'url': return !this._parts.urn; case 'urn': return !!this._parts.urn; case 'punycode': return punycode; } return null ; } ; var _protocol = _AN_Read_protocol('protocol', p); var _port = _AN_Read_port('port', p); var _hostname = _AN_Read_hostname('hostname', p); p.protocol = function (v, build){ if (v !== undefined) { if (v) { v = _AN_Call_replace('replace', v, /:(\/\/)?$/, ''); if (v.match(/[^a-zA-z0-9\.+-]/)) { throw new TypeError("Protocol '" + v + "' contains characters other than [A-Z0-9.+-]") } } } return _protocol.call(this, v, build); } ; p.scheme = _AN_Read_protocol("protocol", p); p.port = function (v, build){ if (this._parts.urn) { return v === undefined? '': this; } if (v !== undefined) { if (v === 0) { v = null ; } if (v) { v += ""; if (v[0] === ":") { v = v.substring(1); } if (v.match(/[^0-9]/)) { throw new TypeError("Port '" + v + "' contains characters other than [0-9]") } } } return _port.call(this, v, build); } ; p.hostname = function (v, build){ if (this._parts.urn) { return v === undefined? '': this; } if (v !== undefined) { var x = { } ; URI.parseHost(v, x); v = _AN_Read_hostname('hostname', x); } return _hostname.call(this, v, build); } ; p.host = function (v, build){ if (this._parts.urn) { return v === undefined? '': this; } if (v === undefined) { return _AN_Read_hostname('hostname', this._parts)? URI.buildHost(this._parts): ""; } else { URI.parseHost(v, this._parts); this.build(!build); return this; } } ; p.authority = function (v, build){ if (this._parts.urn) { return v === undefined? '': this; } if (v === undefined) { return _AN_Read_hostname('hostname', this._parts)? URI.buildAuthority(this._parts): ""; } else { URI.parseAuthority(v, this._parts); this.build(!build); return this; } } ; p.userinfo = function (v, build){ if (this._parts.urn) { return v === undefined? '': this; } if (v === undefined) { if (!this._parts.username) { return ""; } var t = URI.buildUserinfo(this._parts); return t.substring(0, _AN_Read_length("length", t) - 1); } else { if (v[_AN_Read_length("length", v) - 1] !== '@') { v += '@'; } URI.parseUserinfo(v, this._parts); this.build(!build); return this; } } ; p.resource = function (v, build){ var parts; if (v === undefined) { return this.path() + this.search() + this.hash(); } parts = URI.parse(v); this._parts.path = parts.path; this._parts.query = parts.query; this._parts.fragment = parts.fragment; this.build(!build); return this; } ; p.subdomain = function (v, build){ if (this._parts.urn) { return v === undefined? '': this; } if (v === undefined) { if (!_AN_Read_hostname('hostname', this._parts) || this.is('IP')) { return ""; } var end = _AN_Read_length("length", _AN_Read_hostname("hostname", this._parts)) - _AN_Read_length("length", this.domain()) - 1; return _AN_Read_hostname("hostname", this._parts).substring(0, end) || ""; } else { var e = _AN_Read_length("length", _AN_Read_hostname("hostname", this._parts)) - _AN_Read_length("length", this.domain()); var sub = _AN_Read_hostname("hostname", this._parts).substring(0, e); var replace = new RegExp('^' + escapeRegEx(sub)); if (v && v[_AN_Read_length('length', v) - 1] !== '.') { v += "."; } if (v) { URI.ensureValidHostname(v); } _AN_Write_hostname("hostname", this._parts, false , _AN_Call_replace("replace", _AN_Read_hostname("hostname", this._parts), replace, v)); this.build(!build); return this; } } ; p.domain = function (v, build){ if (this._parts.urn) { return v === undefined? '': this; } if (typeof v === 'boolean') { build = v; v = undefined; } if (v === undefined) { if (!_AN_Read_hostname('hostname', this._parts) || this.is('IP')) { return ""; } var t = _AN_Read_hostname("hostname", this._parts).match(/\./g); if (t && _AN_Read_length("length", t) < 2) { return _AN_Read_hostname("hostname", this._parts); } var end = _AN_Read_length("length", _AN_Read_hostname("hostname", this._parts)) - _AN_Read_length("length", this.tld(build)) - 1; end = _AN_Read_hostname("hostname", this._parts).lastIndexOf('.', end - 1) + 1; return _AN_Read_hostname('hostname', this._parts).substring(end) || ""; } else { if (!v) { throw new TypeError("cannot set domain empty") } URI.ensureValidHostname(v); if (!_AN_Read_hostname("hostname", this._parts) || this.is('IP')) { _AN_Write_hostname('hostname', this._parts, false , v); } else { var replace = new RegExp(escapeRegEx(this.domain()) + "$"); _AN_Write_hostname("hostname", this._parts, false , _AN_Call_replace("replace", _AN_Read_hostname("hostname", this._parts), replace, v)); } this.build(!build); return this; } } ; p.tld = function (v, build){ if (this._parts.urn) { return v === undefined? '': this; } if (typeof v === 'boolean') { build = v; v = undefined; } if (v === undefined) { if (!_AN_Read_hostname('hostname', this._parts) || this.is('IP')) { return ""; } var pos = _AN_Read_hostname("hostname", this._parts).lastIndexOf('.'); var tld = _AN_Read_hostname('hostname', this._parts).substring(pos + 1); if (build !== true && SLD && SLD.list[tld.toLowerCase()]) { return SLD.get(_AN_Read_hostname('hostname', this._parts)) || tld; } return tld; } else { var replace; if (!v) { throw new TypeError("cannot set TLD empty") } else if (v.match(/[^a-zA-Z0-9-]/)) { if (SLD && SLD.is(v)) { replace = new RegExp(escapeRegEx(this.tld()) + "$"); _AN_Write_hostname("hostname", this._parts, false , _AN_Call_replace("replace", _AN_Read_hostname("hostname", this._parts), replace, v)); } else { throw new TypeError("TLD '" + v + "' contains characters other than [A-Z0-9]") } } else if (!_AN_Read_hostname("hostname", this._parts) || this.is('IP')) { throw new ReferenceError("cannot set TLD on non-domain host") } else { replace = new RegExp(escapeRegEx(this.tld()) + "$"); _AN_Write_hostname("hostname", this._parts, false , _AN_Call_replace("replace", _AN_Read_hostname("hostname", this._parts), replace, v)); } this.build(!build); return this; } } ; p.directory = function (v, build){ if (this._parts.urn) { return v === undefined? '': this; } if (v === undefined || v === true ) { if (!this._parts.path && !_AN_Read_hostname('hostname', this._parts)) { return ''; } if (this._parts.path === '/') { return '/'; } var end = _AN_Read_length('length', this._parts.path) - _AN_Read_length('length', this.filename()) - 1; var res = this._parts.path.substring(0, end) || (_AN_Read_hostname('hostname', this._parts)? "/": ""); return v? URI.decodePath(res): res; } else { var e = _AN_Read_length("length", this._parts.path) - _AN_Read_length("length", this.filename()); var directory = this._parts.path.substring(0, e); var replace = new RegExp('^' + escapeRegEx(directory)); if (!this.is('relative')) { if (!v) { v = '/'; } if (v[0] !== '/') { v = "/" + v; } } if (v && v[_AN_Read_length("length", v) - 1] !== '/') { v += '/'; } v = URI.recodePath(v); this._parts.path = _AN_Call_replace('replace', this._parts.path, replace, v); this.build(!build); return this; } } ; p.filename = function (v, build){ if (this._parts.urn) { return v === undefined? '': this; } if (v === undefined || v === true ) { if (!this._parts.path || this._parts.path === '/') { return ""; } var pos = this._parts.path.lastIndexOf('/'); var res = this._parts.path.substring(pos + 1); return v? URI.decodePathSegment(res): res; } else { var mutatedDirectory = false ; if (v[0] === '/') { v = v.substring(1); } if (v.match(/\.?\//)) { mutatedDirectory = true ; } var replace = new RegExp(escapeRegEx(this.filename()) + "$"); v = URI.recodePath(v); this._parts.path = _AN_Call_replace("replace", this._parts.path, replace, v); if (mutatedDirectory) { this.normalizePath(build); } else { this.build(!build); } return this; } } ; p.suffix = function (v, build){ if (this._parts.urn) { return v === undefined? '': this; } if (v === undefined || v === true ) { if (!this._parts.path || this._parts.path === '/') { return ""; } var filename = this.filename(); var pos = filename.lastIndexOf('.'); var s, res; if (pos === -1) { return ""; } s = filename.substring(pos + 1); res = (/^[a-z0-9%]+$/i).test(s)? s: ""; return v? URI.decodePathSegment(res): res; } else { if (v[0] === '.') { v = v.substring(1); } var suffix = this.suffix(); var replace; if (!suffix) { if (!v) { return this; } this._parts.path += '.' + URI.recodePath(v); } else if (!v) { replace = new RegExp(escapeRegEx("." + suffix) + "$"); } else { replace = new RegExp(escapeRegEx(suffix) + "$"); } if (replace) { v = URI.recodePath(v); this._parts.path = _AN_Call_replace("replace", this._parts.path, replace, v); } this.build(!build); return this; } } ; p.segment = function (segment, v, build){ var separator = this._parts.urn? ':': '/'; var path = this.path(); var absolute = path.substring(0, 1) === '/'; var segments = path.split(separator); if (typeof segment !== 'number') { build = v; v = segment; segment = undefined; } if (segment !== undefined && typeof segment !== 'number') { throw new Error("Bad segment '" + segment + "', must be 0-based integer") } if (absolute) { segments.shift(); } if (segment < 0) { segment = Math.max(_AN_Read_length("length", segments) + segment, 0); } if (v === undefined) { return segment === undefined? segments: segments[segment]; } else if (segment === null || segments[segment] === undefined) { if (isArray(v)) { segments = v; } else if (v || (typeof v === "string" && _AN_Read_length("length", v))) { if (segments[_AN_Read_length("length", segments) - 1] === "") { segments[_AN_Read_length("length", segments) - 1] = v; } else { segments.push(v); } } } else { if (v || (typeof v === "string" && _AN_Read_length("length", v))) { segments[segment] = v; } else { segments.splice(segment, 1); } } if (absolute) { segments.unshift(""); } return this.path(segments.join(separator), build); } ; var q = p.query; p.query = function (v, build){ if (v === true ) { return URI.parseQuery(this._parts.query); } else if (v !== undefined && typeof v !== "string") { this._parts.query = URI.buildQuery(v, this._parts.duplicateQueryParameters); this.build(!build); return this; } else { return q.call(this, v, build); } } ; p.addQuery = function (name, value, build){ var data = URI.parseQuery(this._parts.query); URI.addQuery(data, name, value === undefined? null : value); this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters); if (typeof name !== "string") { build = value; } this.build(!build); return this; } ; p.removeQuery = function (name, value, build){ var data = URI.parseQuery(this._parts.query); URI.removeQuery(data, name, value); this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters); if (typeof name !== "string") { build = value; } this.build(!build); return this; } ; p.addSearch = p.addQuery; p.removeSearch = p.removeQuery; p.normalize = function (){ if (this._parts.urn) { return this.normalizeProtocol(false ).normalizeQuery(false ).normalizeFragment(false ).build(); } return this.normalizeProtocol(false ).normalizeHostname(false ).normalizePort(false ).normalizePath(false ).normalizeQuery(false ).normalizeFragment(false ).build(); } ; p.normalizeProtocol = function (build){ if (typeof _AN_Read_protocol("protocol", this._parts) === "string") { _AN_Write_protocol("protocol", this._parts, false , _AN_Read_protocol("protocol", this._parts).toLowerCase()); this.build(!build); } return this; } ; p.normalizeHostname = function (build){ if (this._parts.hostname) { if (this.is('IDN') && punycode) { _AN_Write_hostname('hostname', this._parts, false , punycode.toASCII(_AN_Read_hostname('hostname', this._parts))); } else if (this.is('IPv6') && IPv6) { _AN_Write_hostname('hostname', this._parts, false , IPv6.best(_AN_Read_hostname('hostname', this._parts))); } _AN_Write_hostname('hostname', this._parts, false , _AN_Read_hostname('hostname', this._parts).toLowerCase()); this.build(!build); } return this; } ; p.normalizePort = function (build){ if (typeof _AN_Read_protocol('protocol', this._parts) === "string" && _AN_Read_port("port", this._parts) === URI.defaultPorts[_AN_Read_protocol("protocol", this._parts)]) { _AN_Write_port("port", this._parts, false , null ); this.build(!build); } return this; } ; p.normalizePath = function (build){ if (this._parts.urn) { return this; } if (!this._parts.path || this._parts.path === '/') { return this; } var _was_relative; var _was_relative_prefix; var _path = this._parts.path; var _parent, _pos; if (_path[0] !== '/') { if (_path[0] === '.') { _was_relative_prefix = _path.substring(0, _path.indexOf('/')); } _was_relative = true ; _path = '/' + _path; } _path = _AN_Call_replace('replace', _path, /(\/(\.\/)+)|\/{2,}/g, '/'); while (true ){ _parent = _path.indexOf('/../'); if (_parent === -1) { break ; } else if (_parent === 0) { _path = _path.substring(3); break ; } _pos = _path.substring(0, _parent).lastIndexOf('/'); if (_pos === -1) { _pos = _parent; } _path = _path.substring(0, _pos) + _path.substring(_parent + 3); } if (_was_relative && this.is('relative')) { if (_was_relative_prefix) { _path = _was_relative_prefix + _path; } else { _path = _path.substring(1); } } _path = URI.recodePath(_path); this._parts.path = _path; this.build(!build); return this; } ; p.normalizePathname = p.normalizePath; p.normalizeQuery = function (build){ if (typeof this._parts.query === "string") { if (!_AN_Read_length("length", this._parts.query)) { this._parts.query = null ; } else { this.query(URI.parseQuery(this._parts.query)); } this.build(!build); } return this; } ; p.normalizeFragment = function (build){ if (!this._parts.fragment) { this._parts.fragment = null ; this.build(!build); } return this; } ; p.normalizeSearch = p.normalizeQuery; p.normalizeHash = p.normalizeFragment; p.iso8859 = function (){ var e = URI.encode; var d = URI.decode; URI.encode = escape; URI.decode = decodeURIComponent; this.normalize(); URI.encode = e; URI.decode = d; return this; } ; p.unicode = function (){ var e = URI.encode; var d = URI.decode; URI.encode = strictEncodeURIComponent; URI.decode = unescape; this.normalize(); URI.encode = e; URI.decode = d; return this; } ; p.readable = function (){ var uri = this.clone(); uri.username("").password("").normalize(); var t = ''; if (uri._parts.protocol) { t += _AN_Read_protocol('protocol', uri._parts) + '://'; } if (uri._parts.hostname) { if (uri.is('punycode') && punycode) { t += punycode.toUnicode(_AN_Read_hostname('hostname', uri._parts)); if (uri._parts.port) { t += ":" + _AN_Read_port("port", uri._parts); } } else { t += uri.host(); } } if (_AN_Read_hostname("hostname", uri._parts) && uri._parts.path && uri._parts.path[0] !== '/') { t += '/'; } t += uri.path(true ); if (uri._parts.query) { var q = ''; for (var i = 0, qp = uri._parts.query.split('&'), l = _AN_Read_length('length', qp); i < l; i++ ){ var kv = (qp[i] || "").split('='); q += '&' + _AN_Call_replace('replace', URI.decodeQuery(kv[0]), /&/g, '%26'); if (kv[1] !== undefined) { q += "=" + _AN_Call_replace("replace", URI.decodeQuery(kv[1]), /&/g, '%26'); } } t += '?' + q.substring(1); } t += uri.hash(); return t; } ; p.absoluteTo = function (base){ var resolved = this.clone(); var properties = ['protocol', 'username', 'password', 'hostname', 'port'] ; var basedir, i, p; if (this._parts.urn) { throw new Error('URNs do not have any generally defined hierachical components') } if (this._parts.hostname) { return resolved; } if (!(base instanceof URI)) { base = new URI(base); } for (i = 0, p; p = properties[i]; i++ ){ resolved._parts[p] = base._parts[p]; } properties = ['query', 'path'] ; for (i = 0, p; p = properties[i]; i++ ){ if (!resolved._parts[p] && base._parts[p]) { resolved._parts[p] = base._parts[p]; } } if (resolved.path()[0] !== '/') { basedir = base.directory(); resolved._parts.path = (basedir? (basedir + '/'): '') + resolved._parts.path; resolved.normalizePath(); } resolved.build(); return resolved; } ; p.relativeTo = function (base){ var relative = this.clone(); var properties = ['protocol', 'username', 'password', 'hostname', 'port'] ; var common, _base, _this, _base_diff, _this_diff; if (this._parts.urn) { throw new Error('URNs do not have any generally defined hierachical components') } if (!(base instanceof URI)) { base = new URI(base); } if (this.path()[0] !== '/' || base.path()[0] !== '/') { throw new Error('Cannot calculate common path from non-relative URLs') } common = URI.commonPath(relative.path(), base.path()); if (!common || common === '/') { return relative; } for (var i = 0, p; p = properties[i]; i++ ){ relative._parts[p] = null ; } _base = base.directory(); _this = this.directory(); if (_base === _this) { relative._parts.path = './' + relative.filename(); return relative.build(); } _base_diff = _base.substring(_AN_Read_length('length', common)); _this_diff = _this.substring(_AN_Read_length('length', common)); if (_base + '/' === common) { if (_this_diff) { _this_diff += '/'; } relative._parts.path = './' + _this_diff + relative.filename(); return relative.build(); } var parents = '../'; var _common = new RegExp('^' + escapeRegEx(common)); var _parents = _AN_Read_length('length', _AN_Call_replace('replace', _base, _common, '/').match(/\//g)) - 1; while (_parents-- ){ parents += '../'; } relative._parts.path = _AN_Call_replace('replace', relative._parts.path, _common, parents); return relative.build(); } ; p.equals = function (uri){ var one = this.clone(); var two = new URI(uri); var one_map = { } ; var two_map = { } ; var checked = { } ; var one_query, two_query, key; one.normalize(); two.normalize(); if (one.toString() === two.toString()) { return true ; } one_query = one.query(); two_query = two.query(); one.query(""); two.query(""); if (one.toString() !== two.toString()) { return false ; } if (_AN_Read_length("length", one_query) !== _AN_Read_length("length", two_query)) { return false ; } one_map = URI.parseQuery(one_query); two_map = URI.parseQuery(two_query); for (key in one_map){ if (hasOwn.call(one_map, key)) { if (!isArray(one_map[key])) { if (one_map[key] !== two_map[key]) { return false ; } } else { if (!isArray(two_map[key])) { return false ; } if (_AN_Read_length("length", one_map[key]) !== _AN_Read_length("length", two_map[key])) { return false ; } one_map[key].sort(); two_map[key].sort(); for (var i = 0, l = _AN_Read_length("length", one_map[key]); i < l; i++ ){ if (one_map[key][i] !== two_map[key][i]) { return false ; } } } checked[key] = true ; } } for (key in two_map){ if (hasOwn.call(two_map, key)) { if (!checked[key]) { return false ; } } } return true ; } ; p.duplicateQueryParameters = function (v){ this._parts.duplicateQueryParameters = !!v; return this; } ; return URI; } ));