aboutsummaryrefslogtreecommitdiff
path: root/node_modules/relateurl
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2017-05-03 15:35:00 +0200
committerFlorian Dold <florian.dold@gmail.com>2017-05-03 15:35:00 +0200
commitde98e0b232509d5f40c135d540a70e415272ff85 (patch)
treea79222a5b58484ab3b80d18efcaaa7ccc4769b33 /node_modules/relateurl
parente0c9d480a73fa629c1e4a47d3e721f1d2d345406 (diff)
downloadwallet-core-de98e0b232509d5f40c135d540a70e415272ff85.tar.xz
node_modules
Diffstat (limited to 'node_modules/relateurl')
-rw-r--r--node_modules/relateurl/README.md159
-rw-r--r--node_modules/relateurl/lib/constants.js10
-rw-r--r--node_modules/relateurl/lib/format.js174
-rw-r--r--node_modules/relateurl/lib/index.js94
-rw-r--r--node_modules/relateurl/lib/options.js57
-rw-r--r--node_modules/relateurl/lib/parse/host.js26
-rw-r--r--node_modules/relateurl/lib/parse/hrefInfo.js20
-rw-r--r--node_modules/relateurl/lib/parse/index.js58
-rw-r--r--node_modules/relateurl/lib/parse/path.js100
-rw-r--r--node_modules/relateurl/lib/parse/port.js32
-rw-r--r--node_modules/relateurl/lib/parse/query.js53
-rw-r--r--node_modules/relateurl/lib/parse/urlstring.js146
-rw-r--r--node_modules/relateurl/lib/relate/absolutize.js89
-rw-r--r--node_modules/relateurl/lib/relate/findRelation.js79
-rw-r--r--node_modules/relateurl/lib/relate/index.js18
-rw-r--r--node_modules/relateurl/lib/relate/relativize.js67
-rw-r--r--node_modules/relateurl/lib/util/devlog.js25
-rw-r--r--node_modules/relateurl/lib/util/object.js64
-rw-r--r--node_modules/relateurl/lib/util/path.js49
-rw-r--r--node_modules/relateurl/license21
-rw-r--r--node_modules/relateurl/package.json46
21 files changed, 1387 insertions, 0 deletions
diff --git a/node_modules/relateurl/README.md b/node_modules/relateurl/README.md
new file mode 100644
index 000000000..fb65fca3d
--- /dev/null
+++ b/node_modules/relateurl/README.md
@@ -0,0 +1,159 @@
+# relateurl [![NPM Version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Dependency Status][david-image]][david-url]
+
+> Minify URLs by converting them from absolute to relative.
+
+If you were to use this library on a website like `http://example.com/dir1/dir1-1/`, you would get results such as:
+
+| Before | After |
+| :------------------------------------------ | :----------------------------------- |
+| `http://example.com/dir1/dir1-2/index.html` | `../dir1-2/` |
+| `http://example.com/dir2/dir2-1/` | `/dir2/dir2-1/` |
+| `http://example.com/dir1/dir1-1/` | ` ` |
+| `https://example.com/dir1/dir1-1/` | `https://example.com/dir1/dir1-1/` |
+| `http://google.com:80/dir/` | `//google.com/dir/` |
+| `../../../../../../../../#anchor` | `/#anchor` |
+
+**All string parsing.** *No* directory browsing. It is thoroughly tested, very fast and lightweight with zero external dependencies.
+
+## Getting Started
+
+This utility requires [Node.js](http://nodejs.org/) `>= 0.10`. To install, type this at the command line:
+```
+npm install relateurl --save-dev
+```
+
+### Options
+
+#### options.defaultPorts
+Type: `Object`
+Default value: `{ftp:21, http:80, https:443}`
+
+Extend the list with any ports you need. Any URLs containing these default ports will have them removed. Example: `http://example.com:80/` will become `http://example.com/`.
+
+#### options.directoryIndexes
+Type: `Array`
+Default value: `["index.html"]`
+
+Extend the list with any resources you need. Works with [`options.removeDirectoryIndexes`](#options.removeDirectoryIndexes).
+
+#### options.ignore_www
+Type: `Boolean`
+Default value: `false`
+
+This will, for example, consider any domains containing `http://www.example.com/` to be related to any that contain `http://example.com/`.
+
+#### options.output
+Type: constant or `String`
+Choices: `RelateUrl.ABSOLUTE`,`RelateUrl.PATH_RELATIVE`,`RelateUrl.ROOT_RELATIVE`,`RelateUrl.SHORTEST`
+Choices: `"absolute"`,`"pathRelative"`,`"rootRelative"`,`"shortest"`
+Default value: `RelateUrl.SHORTEST`
+
+`RelateUrl.ABSOLUTE` will produce an absolute URL. Overrides [`options.schemeRelative`](#options.schemeRelative) with a value of `false`.
+`RelateUrl.PATH_RELATIVE` will produce something like `../child-of-parent/etc/`.
+`RelateUrl.ROOT_RELATIVE` will produce something like `/child-of-root/etc/`.
+`RelateUrl.SHORTEST` will choose whichever is shortest between root- and path-relative.
+
+#### options.rejectedSchemes
+Type: `Array`
+Default value: `["data","javascript","mailto"]`
+
+Extend the list with any additional schemes. Example: `javascript:something` will not be modified.
+
+#### options.removeAuth
+Type: `Boolean`
+Default value: `false`
+
+Remove user authentication information from the output URL.
+
+#### options.removeDirectoryIndexes
+Type: `Boolean`
+Default value: `true`
+
+Remove any resources that match any found in [`options.directoryIndexes`](#options.directoryIndexes).
+
+#### options.removeEmptyQueries
+Type: `Boolean`
+Default value: `false`
+
+Remove empty query variables. Example: `http://domain.com/?var1&var2=&var3=asdf` will become `http://domain.com/?var3=adsf`. This does not apply to unrelated URLs (with other protocols, auths, hosts and/or ports).
+
+#### options.removeRootTrailingSlash
+Type: `Boolean`
+Default value: `true`
+
+Remove trailing slashes from root paths. Example: `http://domain.com/?var` will become `http://domain.com?var` while `http://domain.com/dir/?var` will not be modified.
+
+#### options.schemeRelative
+Type: `Boolean`
+Default value: `true`
+
+Output URLs relative to the scheme. Example: `http://example.com/` will become `//example.com/`.
+
+#### options.site
+Type: `String`
+Default value: `undefined`
+
+An options-based version of the [`from`](#examples) argument. If both are specified, `from` takes priority.
+
+#### options.slashesDenoteHost
+Type: `Boolean`
+Default value: `true`
+
+Passed to Node's [`url.parse`](http://nodejs.org/api/url.html#url_url_parse_urlstr_parsequerystring_slashesdenotehost).
+
+### Examples
+This library can be used as a [function for single-use](#single-instance) or as a [class for multiple conversions](#reusable-instances).
+
+Upon successful conversion, a `String` will be returned. If an issue is encountered while parsing `from`, an error will be thrown.
+
+#### Single Instance
+```js
+var RelateUrl = require("relateurl");
+
+var result = RelateUrl.relate(from, to, options);
+```
+
+#### Reusable Instances
+```js
+var RelateUrl = require("relateurl");
+
+var instance = new RelateUrl(from, options);
+
+var result1 = instance.relate(to1);
+var result2 = instance.relate(to2, customOptions);
+var result3 = instance.relate(to3);
+```
+
+## FAQ
+1. **Why bother writing/using this?**
+To aid in further minifying HTML, mainly for the purpose of faster page loads and SEO. It's been integrated into [HTMLMinifier](https://github.com/kangax/html-minifier).
+
+2. **Why not just use Node's `url.parse`, `url.resolve` and `path.relative`?**
+`url.parse` *is* used, but `url.resolve` and `path.relative` are both slower and less powerful than this library.
+
+
+## Release History
+* 0.2.7 Node v6 support
+* 0.2.6 minor enhancements
+* 0.2.5 added `options.removeRootTrailingSlash`
+* 0.2.4 added `options.site`
+* 0.2.3 added browserify npm-script
+* 0.2.2 removed task runner
+* 0.2.1 shorten resource- and query-relative URLs, test variations list with other site URLs
+* 0.2.0 code cleanup, `options.removeEmptyQueries=true` only applied to unrelated URLs
+* 0.1.0 initial release
+
+
+## Roadmap
+* 0.2.8 check if queries are the same, regardless of param order
+* 0.2.8 possible [scheme exclusions](http://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml) such as `tel:`
+* 0.2.8 decipher and return invalid input (special cases) to complete test suite
+* 0.3.0 test `options.slashesDenoteHost=false`, add something like `options.externalDirectoryIndexes=[]` for external sites
+
+
+[npm-image]: https://img.shields.io/npm/v/relateurl.svg
+[npm-url]: https://npmjs.org/package/relateurl
+[travis-image]: https://img.shields.io/travis/stevenvachon/relateurl.svg
+[travis-url]: https://travis-ci.org/stevenvachon/relateurl
+[david-image]: https://img.shields.io/david/stevenvachon/relateurl.svg
+[david-url]: https://david-dm.org/stevenvachon/relateurl
diff --git a/node_modules/relateurl/lib/constants.js b/node_modules/relateurl/lib/constants.js
new file mode 100644
index 000000000..d4cc8dd69
--- /dev/null
+++ b/node_modules/relateurl/lib/constants.js
@@ -0,0 +1,10 @@
+"use strict";
+
+module.exports =
+{
+ // Output
+ ABSOLUTE: "absolute",
+ PATH_RELATIVE: "pathRelative",
+ ROOT_RELATIVE: "rootRelative",
+ SHORTEST: "shortest"
+};
diff --git a/node_modules/relateurl/lib/format.js b/node_modules/relateurl/lib/format.js
new file mode 100644
index 000000000..4dd5ddc08
--- /dev/null
+++ b/node_modules/relateurl/lib/format.js
@@ -0,0 +1,174 @@
+"use strict";
+
+var constants = require("./constants");
+
+
+
+function formatAuth(urlObj, options)
+{
+ if (urlObj.auth && !options.removeAuth && (urlObj.extra.relation.maximumHost || options.output===constants.ABSOLUTE))
+ {
+ return urlObj.auth + "@";
+ }
+
+ return "";
+}
+
+
+
+function formatHash(urlObj, options)
+{
+ return urlObj.hash ? urlObj.hash : "";
+}
+
+
+
+function formatHost(urlObj, options)
+{
+ if (urlObj.host.full && (urlObj.extra.relation.maximumAuth || options.output===constants.ABSOLUTE))
+ {
+ return urlObj.host.full;
+ }
+
+ return "";
+}
+
+
+
+function formatPath(urlObj, options)
+{
+ var str = "";
+
+ var absolutePath = urlObj.path.absolute.string;
+ var relativePath = urlObj.path.relative.string;
+ var resource = showResource(urlObj, options);
+
+ if (urlObj.extra.relation.maximumHost || options.output===constants.ABSOLUTE || options.output===constants.ROOT_RELATIVE)
+ {
+ str = absolutePath;
+ }
+ else if (relativePath.length<=absolutePath.length && options.output===constants.SHORTEST || options.output===constants.PATH_RELATIVE)
+ {
+ str = relativePath;
+
+ if (str === "")
+ {
+ var query = showQuery(urlObj,options) && !!getQuery(urlObj,options);
+
+ if (urlObj.extra.relation.maximumPath && !resource)
+ {
+ str = "./";
+ }
+ else if (urlObj.extra.relation.overridesQuery && !resource && !query)
+ {
+ str = "./";
+ }
+ }
+ }
+ else
+ {
+ str = absolutePath;
+ }
+
+ if ( str==="/" && !resource && options.removeRootTrailingSlash && (!urlObj.extra.relation.minimumPort || options.output===constants.ABSOLUTE) )
+ {
+ str = "";
+ }
+
+ return str;
+}
+
+
+
+function formatPort(urlObj, options)
+{
+ if (urlObj.port && !urlObj.extra.portIsDefault && urlObj.extra.relation.maximumHost)
+ {
+ return ":" + urlObj.port;
+ }
+
+ return "";
+}
+
+
+
+function formatQuery(urlObj, options)
+{
+ return showQuery(urlObj,options) ? getQuery(urlObj, options) : "";
+}
+
+
+
+function formatResource(urlObj, options)
+{
+ return showResource(urlObj,options) ? urlObj.resource : "";
+}
+
+
+
+function formatScheme(urlObj, options)
+{
+ var str = "";
+
+ if (urlObj.extra.relation.maximumHost || options.output===constants.ABSOLUTE)
+ {
+ if (!urlObj.extra.relation.minimumScheme || !options.schemeRelative || options.output===constants.ABSOLUTE)
+ {
+ str += urlObj.scheme + "://";
+ }
+ else
+ {
+ str += "//";
+ }
+ }
+
+ return str;
+}
+
+
+
+function formatUrl(urlObj, options)
+{
+ var url = "";
+
+ url += formatScheme(urlObj, options);
+ url += formatAuth(urlObj, options);
+ url += formatHost(urlObj, options);
+ url += formatPort(urlObj, options);
+ url += formatPath(urlObj, options);
+ url += formatResource(urlObj, options);
+ url += formatQuery(urlObj, options);
+ url += formatHash(urlObj, options);
+
+ return url;
+}
+
+
+
+function getQuery(urlObj, options)
+{
+ var stripQuery = options.removeEmptyQueries && urlObj.extra.relation.minimumPort;
+
+ return urlObj.query.string[ stripQuery ? "stripped" : "full" ];
+}
+
+
+
+function showQuery(urlObj, options)
+{
+ return !urlObj.extra.relation.minimumQuery || options.output===constants.ABSOLUTE || options.output===constants.ROOT_RELATIVE;
+}
+
+
+
+function showResource(urlObj, options)
+{
+ var removeIndex = options.removeDirectoryIndexes && urlObj.extra.resourceIsIndex;
+ var removeMatchingResource = urlObj.extra.relation.minimumResource && options.output!==constants.ABSOLUTE && options.output!==constants.ROOT_RELATIVE;
+
+ return !!urlObj.resource && !removeMatchingResource && !removeIndex;
+}
+
+
+
+module.exports = formatUrl;
diff --git a/node_modules/relateurl/lib/index.js b/node_modules/relateurl/lib/index.js
new file mode 100644
index 000000000..714237d59
--- /dev/null
+++ b/node_modules/relateurl/lib/index.js
@@ -0,0 +1,94 @@
+"use strict";
+
+var constants = require("./constants");
+var formatUrl = require("./format");
+var getOptions = require("./options");
+var objUtils = require("./util/object");
+var parseUrl = require("./parse");
+var relateUrl = require("./relate");
+
+
+
+function RelateUrl(from, options)
+{
+ this.options = getOptions(options,
+ {
+ defaultPorts: {ftp:21, http:80, https:443},
+ directoryIndexes: ["index.html"],
+ ignore_www: false,
+ output: RelateUrl.SHORTEST,
+ rejectedSchemes: ["data","javascript","mailto"],
+ removeAuth: false,
+ removeDirectoryIndexes: true,
+ removeEmptyQueries: false,
+ removeRootTrailingSlash: true,
+ schemeRelative: true,
+ site: undefined,
+ slashesDenoteHost: true
+ });
+
+ this.from = parseUrl.from(from, this.options, null);
+}
+
+
+
+/*
+ Usage: instance=new RelateUrl(); instance.relate();
+*/
+RelateUrl.prototype.relate = function(from, to, options)
+{
+ // relate(to,options)
+ if ( objUtils.isPlainObject(to) )
+ {
+ options = to;
+ to = from;
+ from = null;
+ }
+ // relate(to)
+ else if (!to)
+ {
+ to = from;
+ from = null;
+ }
+
+ options = getOptions(options, this.options);
+ from = from || options.site;
+ from = parseUrl.from(from, options, this.from);
+
+ if (!from || !from.href)
+ {
+ throw new Error("from value not defined.");
+ }
+ else if (from.extra.hrefInfo.minimumPathOnly)
+ {
+ throw new Error("from value supplied is not absolute: "+from.href);
+ }
+
+ to = parseUrl.to(to, options);
+
+ if (to.valid===false) return to.href;
+
+ to = relateUrl(from, to, options);
+ to = formatUrl(to, options);
+
+ return to;
+}
+
+
+
+/*
+ Usage: RelateUrl.relate();
+*/
+RelateUrl.relate = function(from, to, options)
+{
+ return new RelateUrl().relate(from, to, options);
+}
+
+
+
+// Make constants accessible from API
+objUtils.shallowMerge(RelateUrl, constants);
+
+
+
+module.exports = RelateUrl;
diff --git a/node_modules/relateurl/lib/options.js b/node_modules/relateurl/lib/options.js
new file mode 100644
index 000000000..fe8910f71
--- /dev/null
+++ b/node_modules/relateurl/lib/options.js
@@ -0,0 +1,57 @@
+"use strict";
+
+var objUtils = require("./util/object");
+
+
+
+function getOptions(options, defaults)
+{
+ if ( objUtils.isPlainObject(options) )
+ {
+ var newOptions = {};
+
+ for (var i in defaults)
+ {
+ if ( defaults.hasOwnProperty(i) )
+ {
+ if (options[i] !== undefined)
+ {
+ newOptions[i] = mergeOption(options[i], defaults[i]);
+ }
+ else
+ {
+ newOptions[i] = defaults[i];
+ }
+ }
+ }
+
+ return newOptions;
+ }
+ else
+ {
+ return defaults;
+ }
+}
+
+
+
+function mergeOption(newValues, defaultValues)
+{
+ if (defaultValues instanceof Object && newValues instanceof Object)
+ {
+ if (defaultValues instanceof Array && newValues instanceof Array)
+ {
+ return defaultValues.concat(newValues);
+ }
+ else
+ {
+ return objUtils.shallowMerge(newValues, defaultValues);
+ }
+ }
+
+ return newValues;
+}
+
+
+
+module.exports = getOptions;
diff --git a/node_modules/relateurl/lib/parse/host.js b/node_modules/relateurl/lib/parse/host.js
new file mode 100644
index 000000000..21f04ff98
--- /dev/null
+++ b/node_modules/relateurl/lib/parse/host.js
@@ -0,0 +1,26 @@
+"use strict";
+
+function parseHost(urlObj, options)
+{
+ // TWEAK :: condition only for speed optimization
+ if (options.ignore_www)
+ {
+ var host = urlObj.host.full;
+
+ if (host)
+ {
+ var stripped = host;
+
+ if (host.indexOf("www.") === 0)
+ {
+ stripped = host.substr(4);
+ }
+
+ urlObj.host.stripped = stripped;
+ }
+ }
+}
+
+
+
+module.exports = parseHost;
diff --git a/node_modules/relateurl/lib/parse/hrefInfo.js b/node_modules/relateurl/lib/parse/hrefInfo.js
new file mode 100644
index 000000000..8cac2bd82
--- /dev/null
+++ b/node_modules/relateurl/lib/parse/hrefInfo.js
@@ -0,0 +1,20 @@
+"use strict";
+
+function hrefInfo(urlObj)
+{
+ var minimumPathOnly = (!urlObj.scheme && !urlObj.auth && !urlObj.host.full && !urlObj.port);
+ var minimumResourceOnly = (minimumPathOnly && !urlObj.path.absolute.string);
+ var minimumQueryOnly = (minimumResourceOnly && !urlObj.resource);
+ var minimumHashOnly = (minimumQueryOnly && !urlObj.query.string.full.length);
+ var empty = (minimumHashOnly && !urlObj.hash);
+
+ urlObj.extra.hrefInfo.minimumPathOnly = minimumPathOnly;
+ urlObj.extra.hrefInfo.minimumResourceOnly = minimumResourceOnly;
+ urlObj.extra.hrefInfo.minimumQueryOnly = minimumQueryOnly;
+ urlObj.extra.hrefInfo.minimumHashOnly = minimumHashOnly;
+ urlObj.extra.hrefInfo.empty = empty;
+}
+
+
+
+module.exports = hrefInfo;
diff --git a/node_modules/relateurl/lib/parse/index.js b/node_modules/relateurl/lib/parse/index.js
new file mode 100644
index 000000000..9f3677818
--- /dev/null
+++ b/node_modules/relateurl/lib/parse/index.js
@@ -0,0 +1,58 @@
+"use strict";
+
+var hrefInfo = require("./hrefInfo");
+var parseHost = require("./host");
+var parsePath = require("./path");
+var parsePort = require("./port");
+var parseQuery = require("./query");
+var parseUrlString = require("./urlstring");
+var pathUtils = require("../util/path");
+
+
+
+function parseFromUrl(url, options, fallback)
+{
+ if (url)
+ {
+ var urlObj = parseUrl(url, options);
+
+ // Because the following occurs in the relate stage for "to" URLs,
+ // such had to be mostly duplicated here
+
+ var pathArray = pathUtils.resolveDotSegments(urlObj.path.absolute.array);
+
+ urlObj.path.absolute.array = pathArray;
+ urlObj.path.absolute.string = "/" + pathUtils.join(pathArray);
+
+ return urlObj;
+ }
+ else
+ {
+ return fallback;
+ }
+}
+
+
+
+function parseUrl(url, options)
+{
+ var urlObj = parseUrlString(url, options);
+
+ if (urlObj.valid===false) return urlObj;
+
+ parseHost(urlObj, options);
+ parsePort(urlObj, options);
+ parsePath(urlObj, options);
+ parseQuery(urlObj, options);
+ hrefInfo(urlObj);
+
+ return urlObj;
+}
+
+
+
+module.exports =
+{
+ from: parseFromUrl,
+ to: parseUrl
+};
diff --git a/node_modules/relateurl/lib/parse/path.js b/node_modules/relateurl/lib/parse/path.js
new file mode 100644
index 000000000..093c00c69
--- /dev/null
+++ b/node_modules/relateurl/lib/parse/path.js
@@ -0,0 +1,100 @@
+"use strict";
+
+function isDirectoryIndex(resource, options)
+{
+ var verdict = false;
+
+ options.directoryIndexes.every( function(index)
+ {
+ if (index === resource)
+ {
+ verdict = true;
+ return false;
+ }
+
+ return true;
+ });
+
+ return verdict;
+}
+
+
+
+function parsePath(urlObj, options)
+{
+ var path = urlObj.path.absolute.string;
+
+ if (path)
+ {
+ var lastSlash = path.lastIndexOf("/");
+
+ if (lastSlash > -1)
+ {
+ if (++lastSlash < path.length)
+ {
+ var resource = path.substr(lastSlash);
+
+ if (resource!=="." && resource!=="..")
+ {
+ urlObj.resource = resource;
+ path = path.substr(0, lastSlash);
+ }
+ else
+ {
+ path += "/";
+ }
+ }
+
+ urlObj.path.absolute.string = path;
+ urlObj.path.absolute.array = splitPath(path);
+ }
+ else if (path==="." || path==="..")
+ {
+ // "..?var", "..#anchor", etc ... not "..index.html"
+ path += "/";
+
+ urlObj.path.absolute.string = path;
+ urlObj.path.absolute.array = splitPath(path);
+ }
+ else
+ {
+ // Resource-only
+ urlObj.resource = path;
+ urlObj.path.absolute.string = null;
+ }
+
+ urlObj.extra.resourceIsIndex = isDirectoryIndex(urlObj.resource, options);
+ }
+ // Else: query/hash-only or empty
+}
+
+
+
+function splitPath(path)
+{
+ // TWEAK :: condition only for speed optimization
+ if (path !== "/")
+ {
+ var cleaned = [];
+
+ path.split("/").forEach( function(dir)
+ {
+ // Cleanup -- splitting "/dir/" becomes ["","dir",""]
+ if (dir !== "")
+ {
+ cleaned.push(dir);
+ }
+ });
+
+ return cleaned;
+ }
+ else
+ {
+ // Faster to skip the above block and just create an array
+ return [];
+ }
+}
+
+
+
+module.exports = parsePath;
diff --git a/node_modules/relateurl/lib/parse/port.js b/node_modules/relateurl/lib/parse/port.js
new file mode 100644
index 000000000..8c4ee2e84
--- /dev/null
+++ b/node_modules/relateurl/lib/parse/port.js
@@ -0,0 +1,32 @@
+"use strict";
+
+function parsePort(urlObj, options)
+{
+ var defaultPort = -1;
+
+ for (var i in options.defaultPorts)
+ {
+ if ( i===urlObj.scheme && options.defaultPorts.hasOwnProperty(i) )
+ {
+ defaultPort = options.defaultPorts[i];
+ break;
+ }
+ }
+
+ if (defaultPort > -1)
+ {
+ // Force same type as urlObj.port
+ defaultPort = defaultPort.toString();
+
+ if (urlObj.port === null)
+ {
+ urlObj.port = defaultPort;
+ }
+
+ urlObj.extra.portIsDefault = (urlObj.port === defaultPort);
+ }
+}
+
+
+
+module.exports = parsePort;
diff --git a/node_modules/relateurl/lib/parse/query.js b/node_modules/relateurl/lib/parse/query.js
new file mode 100644
index 000000000..dbb85045c
--- /dev/null
+++ b/node_modules/relateurl/lib/parse/query.js
@@ -0,0 +1,53 @@
+"use strict";
+var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+
+
+function parseQuery(urlObj, options)
+{
+ urlObj.query.string.full = stringify(urlObj.query.object, false);
+
+ // TWEAK :: condition only for speed optimization
+ if (options.removeEmptyQueries)
+ {
+ urlObj.query.string.stripped = stringify(urlObj.query.object, true);
+ }
+}
+
+
+
+function stringify(queryObj, removeEmptyQueries)
+{
+ var count = 0;
+ var str = "";
+
+ for (var i in queryObj)
+ {
+ if ( i!=="" && hasOwnProperty.call(queryObj, i)===true )
+ {
+ var value = queryObj[i];
+
+ if (value !== "" || !removeEmptyQueries)
+ {
+ str += (++count===1) ? "?" : "&";
+
+ i = encodeURIComponent(i);
+
+ if (value !== "")
+ {
+ str += i +"="+ encodeURIComponent(value).replace(/%20/g,"+");
+ }
+ else
+ {
+ str += i;
+ }
+ }
+ }
+ }
+
+ return str;
+}
+
+
+
+module.exports = parseQuery;
diff --git a/node_modules/relateurl/lib/parse/urlstring.js b/node_modules/relateurl/lib/parse/urlstring.js
new file mode 100644
index 000000000..ca4d7d431
--- /dev/null
+++ b/node_modules/relateurl/lib/parse/urlstring.js
@@ -0,0 +1,146 @@
+"use strict";
+
+var _parseUrl = require("url").parse;
+
+
+
+/*
+ Customize the URL object that Node generates
+ because:
+
+ * necessary data for later
+ * urlObj.host is useless
+ * urlObj.hostname is too long
+ * urlObj.path is useless
+ * urlObj.pathname is too long
+ * urlObj.protocol is inaccurate; should be called "scheme"
+ * urlObj.search is mostly useless
+*/
+function clean(urlObj)
+{
+ var scheme = urlObj.protocol;
+
+ if (scheme)
+ {
+ // Remove ":" suffix
+ if (scheme.indexOf(":") === scheme.length-1)
+ {
+ scheme = scheme.substr(0, scheme.length-1);
+ }
+ }
+
+ urlObj.host =
+ {
+ // TODO :: unescape(encodeURIComponent(s)) ? ... http://ecmanaut.blogspot.ca/2006/07/encoding-decoding-utf8-in-javascript.html
+ full: urlObj.hostname,
+ stripped: null
+ };
+
+ urlObj.path =
+ {
+ absolute:
+ {
+ array: null,
+ string: urlObj.pathname
+ },
+ relative:
+ {
+ array: null,
+ string: null
+ }
+ };
+
+ urlObj.query =
+ {
+ object: urlObj.query,
+ string:
+ {
+ full: null,
+ stripped: null
+ }
+ };
+
+ urlObj.extra =
+ {
+ hrefInfo:
+ {
+ minimumPathOnly: null,
+ minimumResourceOnly: null,
+ minimumQueryOnly: null,
+ minimumHashOnly: null,
+ empty: null,
+
+ separatorOnlyQuery: urlObj.search==="?"
+ },
+ portIsDefault: null,
+ relation:
+ {
+ maximumScheme: null,
+ maximumAuth: null,
+ maximumHost: null,
+ maximumPort: null,
+ maximumPath: null,
+ maximumResource: null,
+ maximumQuery: null,
+ maximumHash: null,
+
+ minimumScheme: null,
+ minimumAuth: null,
+ minimumHost: null,
+ minimumPort: null,
+ minimumPath: null,
+ minimumResource: null,
+ minimumQuery: null,
+ minimumHash: null,
+
+ overridesQuery: null
+ },
+ resourceIsIndex: null,
+ slashes: urlObj.slashes
+ };
+
+ urlObj.resource = null;
+ urlObj.scheme = scheme;
+ delete urlObj.hostname;
+ delete urlObj.pathname;
+ delete urlObj.protocol;
+ delete urlObj.search;
+ delete urlObj.slashes;
+
+ return urlObj;
+}
+
+
+
+function validScheme(url, options)
+{
+ var valid = true;
+
+ options.rejectedSchemes.every( function(rejectedScheme)
+ {
+ valid = !(url.indexOf(rejectedScheme+":") === 0);
+
+ // Break loop
+ return valid;
+ });
+
+ return valid;
+}
+
+
+
+function parseUrlString(url, options)
+{
+ if ( validScheme(url,options) )
+ {
+ return clean( _parseUrl(url, true, options.slashesDenoteHost) );
+ }
+ else
+ {
+ return {href:url, valid:false};
+ }
+}
+
+
+
+module.exports = parseUrlString;
diff --git a/node_modules/relateurl/lib/relate/absolutize.js b/node_modules/relateurl/lib/relate/absolutize.js
new file mode 100644
index 000000000..2b535a59b
--- /dev/null
+++ b/node_modules/relateurl/lib/relate/absolutize.js
@@ -0,0 +1,89 @@
+"use strict";
+
+var findRelation = require("./findRelation");
+var objUtils = require("../util/object");
+var pathUtils = require("../util/path");
+
+
+
+function absolutize(urlObj, siteUrlObj, options)
+{
+ findRelation.upToPath(urlObj, siteUrlObj, options);
+
+ // Fill in relative URLs
+ if (urlObj.extra.relation.minimumScheme) urlObj.scheme = siteUrlObj.scheme;
+ if (urlObj.extra.relation.minimumAuth) urlObj.auth = siteUrlObj.auth;
+ if (urlObj.extra.relation.minimumHost) urlObj.host = objUtils.clone(siteUrlObj.host);
+ if (urlObj.extra.relation.minimumPort) copyPort(urlObj, siteUrlObj);
+ if (urlObj.extra.relation.minimumScheme) copyPath(urlObj, siteUrlObj);
+
+ // Check remaining relativeness now that path has been copied and/or resolved
+ findRelation.pathOn(urlObj, siteUrlObj, options);
+
+ // Fill in relative URLs
+ if (urlObj.extra.relation.minimumResource) copyResource(urlObj, siteUrlObj);
+ if (urlObj.extra.relation.minimumQuery) urlObj.query = objUtils.clone(siteUrlObj.query);
+ if (urlObj.extra.relation.minimumHash) urlObj.hash = siteUrlObj.hash;
+}
+
+
+
+/*
+ Get an absolute path that's relative to site url.
+*/
+function copyPath(urlObj, siteUrlObj)
+{
+ if (urlObj.extra.relation.maximumHost || !urlObj.extra.hrefInfo.minimumResourceOnly)
+ {
+ var pathArray = urlObj.path.absolute.array;
+ var pathString = "/";
+
+ // If not erroneous URL
+ if (pathArray)
+ {
+ // If is relative path
+ if (urlObj.extra.hrefInfo.minimumPathOnly && urlObj.path.absolute.string.indexOf("/")!==0)
+ {
+ // Append path to site path
+ pathArray = siteUrlObj.path.absolute.array.concat(pathArray);
+ }
+
+ pathArray = pathUtils.resolveDotSegments(pathArray);
+ pathString += pathUtils.join(pathArray);
+ }
+ else
+ {
+ pathArray = [];
+ }
+
+ urlObj.path.absolute.array = pathArray;
+ urlObj.path.absolute.string = pathString;
+ }
+ else
+ {
+ // Resource-, query- or hash-only or empty
+ urlObj.path = objUtils.clone(siteUrlObj.path);
+ }
+}
+
+
+
+function copyPort(urlObj, siteUrlObj)
+{
+ urlObj.port = siteUrlObj.port;
+
+ urlObj.extra.portIsDefault = siteUrlObj.extra.portIsDefault;
+}
+
+
+
+function copyResource(urlObj, siteUrlObj)
+{
+ urlObj.resource = siteUrlObj.resource;
+
+ urlObj.extra.resourceIsIndex = siteUrlObj.extra.resourceIsIndex;
+}
+
+
+
+module.exports = absolutize;
diff --git a/node_modules/relateurl/lib/relate/findRelation.js b/node_modules/relateurl/lib/relate/findRelation.js
new file mode 100644
index 000000000..c5423c3c4
--- /dev/null
+++ b/node_modules/relateurl/lib/relate/findRelation.js
@@ -0,0 +1,79 @@
+"use strict";
+
+function findRelation_upToPath(urlObj, siteUrlObj, options)
+{
+ // Path- or root-relative URL
+ var pathOnly = urlObj.extra.hrefInfo.minimumPathOnly;
+
+ // Matching scheme, scheme-relative or path-only
+ var minimumScheme = (urlObj.scheme===siteUrlObj.scheme || !urlObj.scheme);
+
+ // Matching auth, ignoring auth or path-only
+ var minimumAuth = minimumScheme && (urlObj.auth===siteUrlObj.auth || options.removeAuth || pathOnly);
+
+ // Matching host or path-only
+ var www = options.ignore_www ? "stripped" : "full";
+ var minimumHost = minimumAuth && (urlObj.host[www]===siteUrlObj.host[www] || pathOnly);
+
+ // Matching port or path-only
+ var minimumPort = minimumHost && (urlObj.port===siteUrlObj.port || pathOnly);
+
+ urlObj.extra.relation.minimumScheme = minimumScheme;
+ urlObj.extra.relation.minimumAuth = minimumAuth;
+ urlObj.extra.relation.minimumHost = minimumHost;
+ urlObj.extra.relation.minimumPort = minimumPort;
+
+ urlObj.extra.relation.maximumScheme = !minimumScheme || minimumScheme && !minimumAuth;
+ urlObj.extra.relation.maximumAuth = !minimumScheme || minimumScheme && !minimumHost;
+ urlObj.extra.relation.maximumHost = !minimumScheme || minimumScheme && !minimumPort;
+}
+
+
+
+function findRelation_pathOn(urlObj, siteUrlObj, options)
+{
+ var queryOnly = urlObj.extra.hrefInfo.minimumQueryOnly;
+ var hashOnly = urlObj.extra.hrefInfo.minimumHashOnly;
+ var empty = urlObj.extra.hrefInfo.empty; // not required, but self-documenting
+
+ // From upToPath()
+ var minimumPort = urlObj.extra.relation.minimumPort;
+ var minimumScheme = urlObj.extra.relation.minimumScheme;
+
+ // Matching port and path
+ var minimumPath = minimumPort && urlObj.path.absolute.string===siteUrlObj.path.absolute.string;
+
+ // Matching resource or query/hash-only or empty
+ var matchingResource = (urlObj.resource===siteUrlObj.resource || !urlObj.resource && siteUrlObj.extra.resourceIsIndex) || (options.removeDirectoryIndexes && urlObj.extra.resourceIsIndex && !siteUrlObj.resource);
+ var minimumResource = minimumPath && (matchingResource || queryOnly || hashOnly || empty);
+
+ // Matching query or hash-only/empty
+ var query = options.removeEmptyQueries ? "stripped" : "full";
+ var urlQuery = urlObj.query.string[query];
+ var siteUrlQuery = siteUrlObj.query.string[query];
+ var minimumQuery = (minimumResource && !!urlQuery && urlQuery===siteUrlQuery) || ((hashOnly || empty) && !urlObj.extra.hrefInfo.separatorOnlyQuery);
+
+ var minimumHash = minimumQuery && urlObj.hash===siteUrlObj.hash;
+
+ urlObj.extra.relation.minimumPath = minimumPath;
+ urlObj.extra.relation.minimumResource = minimumResource;
+ urlObj.extra.relation.minimumQuery = minimumQuery;
+ urlObj.extra.relation.minimumHash = minimumHash;
+
+ urlObj.extra.relation.maximumPort = !minimumScheme || minimumScheme && !minimumPath;
+ urlObj.extra.relation.maximumPath = !minimumScheme || minimumScheme && !minimumResource;
+ urlObj.extra.relation.maximumResource = !minimumScheme || minimumScheme && !minimumQuery;
+ urlObj.extra.relation.maximumQuery = !minimumScheme || minimumScheme && !minimumHash;
+ urlObj.extra.relation.maximumHash = !minimumScheme || minimumScheme && !minimumHash; // there's nothing after hash, so it's the same as maximumQuery
+
+ // Matching path and/or resource with existing but non-matching site query
+ urlObj.extra.relation.overridesQuery = minimumPath && urlObj.extra.relation.maximumResource && !minimumQuery && !!siteUrlQuery;
+}
+
+
+
+module.exports =
+{
+ pathOn: findRelation_pathOn,
+ upToPath: findRelation_upToPath
+};
diff --git a/node_modules/relateurl/lib/relate/index.js b/node_modules/relateurl/lib/relate/index.js
new file mode 100644
index 000000000..f90838181
--- /dev/null
+++ b/node_modules/relateurl/lib/relate/index.js
@@ -0,0 +1,18 @@
+"use strict";
+
+var absolutize = require("./absolutize");
+var relativize = require("./relativize");
+
+
+
+function relateUrl(siteUrlObj, urlObj, options)
+{
+ absolutize(urlObj, siteUrlObj, options);
+ relativize(urlObj, siteUrlObj, options);
+
+ return urlObj;
+}
+
+
+
+module.exports = relateUrl;
diff --git a/node_modules/relateurl/lib/relate/relativize.js b/node_modules/relateurl/lib/relate/relativize.js
new file mode 100644
index 000000000..9af9a1017
--- /dev/null
+++ b/node_modules/relateurl/lib/relate/relativize.js
@@ -0,0 +1,67 @@
+"use strict";
+
+var pathUtils = require("../util/path");
+
+
+
+/*
+ Get a path relative to the site path.
+*/
+function relatePath(absolutePath, siteAbsolutePath)
+{
+ var relativePath = [];
+
+ // At this point, it's related to the host/port
+ var related = true;
+ var parentIndex = -1;
+
+ // Find parents
+ siteAbsolutePath.forEach( function(siteAbsoluteDir, i)
+ {
+ if (related)
+ {
+ if (absolutePath[i] !== siteAbsoluteDir)
+ {
+ related = false;
+ }
+ else
+ {
+ parentIndex = i;
+ }
+ }
+
+ if (!related)
+ {
+ // Up one level
+ relativePath.push("..");
+ }
+ });
+
+ // Form path
+ absolutePath.forEach( function(dir, i)
+ {
+ if (i > parentIndex)
+ {
+ relativePath.push(dir);
+ }
+ });
+
+ return relativePath;
+}
+
+
+
+function relativize(urlObj, siteUrlObj, options)
+{
+ if (urlObj.extra.relation.minimumScheme)
+ {
+ var pathArray = relatePath(urlObj.path.absolute.array, siteUrlObj.path.absolute.array);
+
+ urlObj.path.relative.array = pathArray;
+ urlObj.path.relative.string = pathUtils.join(pathArray);
+ }
+}
+
+
+
+module.exports = relativize;
diff --git a/node_modules/relateurl/lib/util/devlog.js b/node_modules/relateurl/lib/util/devlog.js
new file mode 100644
index 000000000..086bdc946
--- /dev/null
+++ b/node_modules/relateurl/lib/util/devlog.js
@@ -0,0 +1,25 @@
+"use strict";
+
+var inspect = require("util").inspect;
+
+
+
+function log(data)
+{
+ console.log( inspect(data, {depth:null, colors:true}) );
+}
+
+
+
+function logAll(data)
+{
+ console.log( inspect(data, {depth:null, showHidden:true, colors:true}) );
+}
+
+
+
+module.exports =
+{
+ log: log,
+ logAll: logAll
+};
diff --git a/node_modules/relateurl/lib/util/object.js b/node_modules/relateurl/lib/util/object.js
new file mode 100644
index 000000000..8eab7940e
--- /dev/null
+++ b/node_modules/relateurl/lib/util/object.js
@@ -0,0 +1,64 @@
+"use strict";
+
+/*
+ Deep-clone an object.
+*/
+function clone(obj)
+{
+ if (obj instanceof Object)
+ {
+ var clonedObj = (obj instanceof Array) ? [] : {};
+
+ for (var i in obj)
+ {
+ if ( obj.hasOwnProperty(i) )
+ {
+ clonedObj[i] = clone( obj[i] );
+ }
+ }
+
+ return clonedObj;
+ }
+
+ return obj;
+}
+
+
+
+/*
+ https://github.com/jonschlinkert/is-plain-object
+*/
+function isPlainObject(obj)
+{
+ return !!obj && typeof obj==="object" && obj.constructor===Object;
+}
+
+
+
+/*
+ Shallow-merge two objects.
+*/
+function shallowMerge(target, source)
+{
+ if (target instanceof Object && source instanceof Object)
+ {
+ for (var i in source)
+ {
+ if ( source.hasOwnProperty(i) )
+ {
+ target[i] = source[i];
+ }
+ }
+ }
+
+ return target;
+}
+
+
+
+module.exports =
+{
+ clone: clone,
+ isPlainObject: isPlainObject,
+ shallowMerge: shallowMerge
+};
diff --git a/node_modules/relateurl/lib/util/path.js b/node_modules/relateurl/lib/util/path.js
new file mode 100644
index 000000000..f1e9d1193
--- /dev/null
+++ b/node_modules/relateurl/lib/util/path.js
@@ -0,0 +1,49 @@
+"use strict";
+
+function joinPath(pathArray)
+{
+ if (pathArray.length > 0)
+ {
+ return pathArray.join("/") + "/";
+ }
+ else
+ {
+ return "";
+ }
+}
+
+
+
+function resolveDotSegments(pathArray)
+{
+ var pathAbsolute = [];
+
+ pathArray.forEach( function(dir)
+ {
+ if (dir !== "..")
+ {
+ if (dir !== ".")
+ {
+ pathAbsolute.push(dir);
+ }
+ }
+ else
+ {
+ // Remove parent
+ if (pathAbsolute.length > 0)
+ {
+ pathAbsolute.splice(pathAbsolute.length-1, 1);
+ }
+ }
+ });
+
+ return pathAbsolute;
+}
+
+
+
+module.exports =
+{
+ join: joinPath,
+ resolveDotSegments: resolveDotSegments
+};
diff --git a/node_modules/relateurl/license b/node_modules/relateurl/license
new file mode 100644
index 000000000..b760007ae
--- /dev/null
+++ b/node_modules/relateurl/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Steven Vachon <contact@svachon.com> (svachon.com)
+
+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.
diff --git a/node_modules/relateurl/package.json b/node_modules/relateurl/package.json
new file mode 100644
index 000000000..f4b236a7e
--- /dev/null
+++ b/node_modules/relateurl/package.json
@@ -0,0 +1,46 @@
+{
+ "name": "relateurl",
+ "description": "Minify URLs by converting them from absolute to relative.",
+ "version": "0.2.7",
+ "license": "MIT",
+ "homepage": "https://github.com/stevenvachon/relateurl",
+ "author": {
+ "name": "Steven Vachon",
+ "email": "contact@svachon.com",
+ "url": "http://www.svachon.com/"
+ },
+ "main": "lib",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/stevenvachon/relateurl.git"
+ },
+ "bugs": {
+ "url": "https://github.com/stevenvachon/relateurl/issues"
+ },
+ "devDependencies": {
+ "browserify": "^13.0.1",
+ "chai": "^3.5.0",
+ "mocha": "^2.5.3",
+ "uglify-js": "^2.7.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ },
+ "scripts": {
+ "browserify": "browserify lib/ --standalone RelateUrl | uglifyjs --compress --mangle -o relateurl-browser.js",
+ "test": "mocha test/ --bail --reporter spec --check-leaks"
+ },
+ "files": [
+ "lib",
+ "license"
+ ],
+ "keywords": [
+ "uri",
+ "url",
+ "minifier",
+ "minify",
+ "lint",
+ "relative",
+ "absolute"
+ ]
+}