summaryrefslogtreecommitdiff
path: root/school/node_modules/url-parse
diff options
context:
space:
mode:
Diffstat (limited to 'school/node_modules/url-parse')
-rw-r--r--school/node_modules/url-parse/LICENSE22
-rw-r--r--school/node_modules/url-parse/README.md153
-rw-r--r--school/node_modules/url-parse/dist/url-parse.js755
-rw-r--r--school/node_modules/url-parse/dist/url-parse.min.js1
-rw-r--r--school/node_modules/url-parse/dist/url-parse.min.js.map1
-rw-r--r--school/node_modules/url-parse/index.js589
-rw-r--r--school/node_modules/url-parse/package.json49
7 files changed, 1570 insertions, 0 deletions
diff --git a/school/node_modules/url-parse/LICENSE b/school/node_modules/url-parse/LICENSE
new file mode 100644
index 0000000..6dc9316
--- /dev/null
+++ b/school/node_modules/url-parse/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Unshift.io, Arnout Kazemier, the Contributors.
+
+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/school/node_modules/url-parse/README.md b/school/node_modules/url-parse/README.md
new file mode 100644
index 0000000..e5bf8d7
--- /dev/null
+++ b/school/node_modules/url-parse/README.md
@@ -0,0 +1,153 @@
+# url-parse
+
+[![Version npm](https://img.shields.io/npm/v/url-parse.svg?style=flat-square)](https://www.npmjs.com/package/url-parse)[![Build Status](https://img.shields.io/github/workflow/status/unshiftio/url-parse/CI/master?label=CI&style=flat-square)](https://github.com/unshiftio/url-parse/actions?query=workflow%3ACI+branch%3Amaster)[![Coverage Status](https://img.shields.io/coveralls/unshiftio/url-parse/master.svg?style=flat-square)](https://coveralls.io/r/unshiftio/url-parse?branch=master)
+
+[![Sauce Test Status](https://saucelabs.com/browser-matrix/url-parse.svg)](https://saucelabs.com/u/url-parse)
+
+**`url-parse` was created in 2014 when the WHATWG URL API was not available in
+Node.js and the `URL` interface was supported only in some browsers. Today this
+is no longer true. The `URL` interface is available in all supported Node.js
+release lines and basically all browsers. Consider using it for better security
+and accuracy.**
+
+The `url-parse` method exposes two different API interfaces. The
+[`url`](https://nodejs.org/api/url.html) interface that you know from Node.js
+and the new [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL)
+interface that is available in the latest browsers.
+
+In version `0.1` we moved from a DOM based parsing solution, using the `<a>`
+element, to a full Regular Expression solution. The main reason for this was
+to make the URL parser available in different JavaScript environments as you
+don't always have access to the DOM. An example of such environment is the
+[`Worker`](https://developer.mozilla.org/en/docs/Web/API/Worker) interface.
+The RegExp based solution didn't work well as it required a lot of lookups
+causing major problems in FireFox. In version `1.0.0` we ditched the RegExp
+based solution in favor of a pure string parsing solution which chops up the
+URL into smaller pieces. This module still has a really small footprint as it
+has been designed to be used on the client side.
+
+In addition to URL parsing we also expose the bundled `querystringify` module.
+
+## Installation
+
+This module is designed to be used using either browserify or Node.js it's
+released in the public npm registry and can be installed using:
+
+```
+npm install url-parse
+```
+
+## Usage
+
+All examples assume that this library is bootstrapped using:
+
+```js
+'use strict';
+
+var Url = require('url-parse');
+```
+
+To parse an URL simply call the `URL` method with the URL that needs to be
+transformed into an object.
+
+```js
+var url = new Url('https://github.com/foo/bar');
+```
+
+The `new` keyword is optional but it will save you an extra function invocation.
+The constructor takes the following arguments:
+
+- `url` (`String`): A string representing an absolute or relative URL.
+- `baseURL` (`Object` | `String`): An object or string representing
+ the base URL to use in case `url` is a relative URL. This argument is
+ optional and defaults to [`location`](https://developer.mozilla.org/en-US/docs/Web/API/Location)
+ in the browser.
+- `parser` (`Boolean` | `Function`): This argument is optional and specifies
+ how to parse the query string. By default it is `false` so the query string
+ is not parsed. If you pass `true` the query string is parsed using the
+ embedded `querystringify` module. If you pass a function the query string
+ will be parsed using this function.
+
+As said above we also support the Node.js interface so you can also use the
+library in this way:
+
+```js
+'use strict';
+
+var parse = require('url-parse')
+ , url = parse('https://github.com/foo/bar', true);
+```
+
+The returned `url` instance contains the following properties:
+
+- `protocol`: The protocol scheme of the URL (e.g. `http:`).
+- `slashes`: A boolean which indicates whether the `protocol` is followed by two
+ forward slashes (`//`).
+- `auth`: Authentication information portion (e.g. `username:password`).
+- `username`: Username of basic authentication.
+- `password`: Password of basic authentication.
+- `host`: Host name with port number. The hostname might be invalid.
+- `hostname`: Host name without port number. This might be an invalid hostname.
+- `port`: Optional port number.
+- `pathname`: URL path.
+- `query`: Parsed object containing query string, unless parsing is set to false.
+- `hash`: The "fragment" portion of the URL including the pound-sign (`#`).
+- `href`: The full URL.
+- `origin`: The origin of the URL.
+
+Note that when `url-parse` is used in a browser environment, it will default to
+using the browser's current window location as the base URL when parsing all
+inputs. To parse an input independently of the browser's current URL (e.g. for
+functionality parity with the library in a Node environment), pass an empty
+location object as the second parameter:
+
+```js
+var parse = require('url-parse');
+parse('hostname', {});
+```
+
+### Url.set(key, value)
+
+A simple helper function to change parts of the URL and propagating it through
+all properties. When you set a new `host` you want the same value to be applied
+to `port` if has a different port number, `hostname` so it has a correct name
+again and `href` so you have a complete URL.
+
+```js
+var parsed = parse('http://google.com/parse-things');
+
+parsed.set('hostname', 'yahoo.com');
+console.log(parsed.href); // http://yahoo.com/parse-things
+```
+
+It's aware of default ports so you cannot set a port 80 on an URL which has
+`http` as protocol.
+
+### Url.toString()
+
+The returned `url` object comes with a custom `toString` method which will
+generate a full URL again when called. The method accepts an extra function
+which will stringify the query string for you. If you don't supply a function we
+will use our default method.
+
+```js
+var location = url.toString(); // http://example.com/whatever/?qs=32
+```
+
+You would rarely need to use this method as the full URL is also available as
+`href` property. If you are using the `URL.set` method to make changes, this
+will automatically update.
+
+## Testing
+
+The testing of this module is done in 3 different ways:
+
+1. We have unit tests that run under Node.js. You can run these tests with the
+ `npm test` command.
+2. Code coverage can be run manually using `npm run coverage`.
+3. For browser testing we use Sauce Labs and `zuul`. You can run browser tests
+ using the `npm run test-browser` command.
+
+## License
+
+[MIT](LICENSE)
diff --git a/school/node_modules/url-parse/dist/url-parse.js b/school/node_modules/url-parse/dist/url-parse.js
new file mode 100644
index 0000000..e989193
--- /dev/null
+++ b/school/node_modules/url-parse/dist/url-parse.js
@@ -0,0 +1,755 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.URLParse = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
+(function (global){(function (){
+'use strict';
+
+var required = require('requires-port')
+ , qs = require('querystringify')
+ , controlOrWhitespace = /^[\x00-\x20\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+/
+ , CRHTLF = /[\n\r\t]/g
+ , slashes = /^[A-Za-z][A-Za-z0-9+-.]*:\/\//
+ , port = /:\d+$/
+ , protocolre = /^([a-z][a-z0-9.+-]*:)?(\/\/)?([\\/]+)?([\S\s]*)/i
+ , windowsDriveLetter = /^[a-zA-Z]:/;
+
+/**
+ * Remove control characters and whitespace from the beginning of a string.
+ *
+ * @param {Object|String} str String to trim.
+ * @returns {String} A new string representing `str` stripped of control
+ * characters and whitespace from its beginning.
+ * @public
+ */
+function trimLeft(str) {
+ return (str ? str : '').toString().replace(controlOrWhitespace, '');
+}
+
+/**
+ * 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.
+ function sanitize(address, url) { // Sanitize what is left of the address
+ return isSpecial(url.protocol) ? address.replace(/\\/g, '/') : address;
+ },
+ ['/', '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.
+ * @public
+ */
+function lolcation(loc) {
+ var globalVar;
+
+ if (typeof window !== 'undefined') globalVar = window;
+ else if (typeof global !== 'undefined') globalVar = global;
+ else if (typeof self !== 'undefined') globalVar = self;
+ else globalVar = {};
+
+ var location = globalVar.location || {};
+ loc = loc || 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;
+}
+
+/**
+ * Check whether a protocol scheme is special.
+ *
+ * @param {String} The protocol scheme of the URL
+ * @return {Boolean} `true` if the protocol scheme is special, else `false`
+ * @private
+ */
+function isSpecial(scheme) {
+ return (
+ scheme === 'file:' ||
+ scheme === 'ftp:' ||
+ scheme === 'http:' ||
+ scheme === 'https:' ||
+ scheme === 'ws:' ||
+ scheme === 'wss:'
+ );
+}
+
+/**
+ * @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.
+ * @param {Object} location
+ * @return {ProtocolExtract} Extracted information.
+ * @private
+ */
+function extractProtocol(address, location) {
+ address = trimLeft(address);
+ address = address.replace(CRHTLF, '');
+ location = location || {};
+
+ var match = protocolre.exec(address);
+ var protocol = match[1] ? match[1].toLowerCase() : '';
+ var forwardSlashes = !!match[2];
+ var otherSlashes = !!match[3];
+ var slashesCount = 0;
+ var rest;
+
+ if (forwardSlashes) {
+ if (otherSlashes) {
+ rest = match[2] + match[3] + match[4];
+ slashesCount = match[2].length + match[3].length;
+ } else {
+ rest = match[2] + match[4];
+ slashesCount = match[2].length;
+ }
+ } else {
+ if (otherSlashes) {
+ rest = match[3] + match[4];
+ slashesCount = match[3].length;
+ } else {
+ rest = match[4]
+ }
+ }
+
+ if (protocol === 'file:') {
+ if (slashesCount >= 2) {
+ rest = rest.slice(2);
+ }
+ } else if (isSpecial(protocol)) {
+ rest = match[4];
+ } else if (protocol) {
+ if (forwardSlashes) {
+ rest = rest.slice(2);
+ }
+ } else if (slashesCount >= 2 && isSpecial(location.protocol)) {
+ rest = match[4];
+ }
+
+ return {
+ protocol: protocol,
+ slashes: forwardSlashes || isSpecial(protocol),
+ slashesCount: slashesCount,
+ rest: rest
+ };
+}
+
+/**
+ * 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.
+ * @private
+ */
+function resolve(relative, base) {
+ if (relative === '') return 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.
+ *
+ * It is worth noting that we should not use `URL` as class name to prevent
+ * clashes with the global URL instance that got introduced in browsers.
+ *
+ * @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.
+ * @private
+ */
+function Url(address, location, parser) {
+ address = trimLeft(address);
+ address = address.replace(CRHTLF, '');
+
+ 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 || '', location);
+ 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.protocol === 'file:' && (
+ extracted.slashesCount !== 2 || windowsDriveLetter.test(address)) ||
+ (!extracted.slashes &&
+ (extracted.protocol ||
+ extracted.slashesCount < 2 ||
+ !isSpecial(url.protocol)))
+ ) {
+ instructions[3] = [/(.*)/, 'pathname'];
+ }
+
+ for (; i < instructions.length; i++) {
+ instruction = instructions[i];
+
+ if (typeof instruction === 'function') {
+ address = instruction(address, url);
+ continue;
+ }
+
+ parse = instruction[0];
+ key = instruction[1];
+
+ if (parse !== parse) {
+ url[key] = address;
+ } else if ('string' === typeof parse) {
+ index = parse === '@'
+ ? address.lastIndexOf(parse)
+ : address.indexOf(parse);
+
+ if (~index) {
+ 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);
+ }
+
+ //
+ // Default to a / for pathname if none exists. This normalizes the URL
+ // to always have a /
+ //
+ if (url.pathname.charAt(0) !== '/' && isSpecial(url.protocol)) {
+ url.pathname = '/' + url.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) {
+ index = url.auth.indexOf(':');
+
+ if (~index) {
+ url.username = url.auth.slice(0, index);
+ url.username = encodeURIComponent(decodeURIComponent(url.username));
+
+ url.password = url.auth.slice(index + 1);
+ url.password = encodeURIComponent(decodeURIComponent(url.password))
+ } else {
+ url.username = encodeURIComponent(decodeURIComponent(url.auth));
+ }
+
+ url.auth = url.password ? url.username +':'+ url.password : url.username;
+ }
+
+ url.origin = url.protocol !== 'file:' && isSpecial(url.protocol) && url.host
+ ? 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} URL instance for chaining.
+ * @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 (port.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;
+
+ case 'username':
+ case 'password':
+ url[part] = encodeURIComponent(value);
+ break;
+
+ case 'auth':
+ var index = value.indexOf(':');
+
+ if (~index) {
+ url.username = value.slice(0, index);
+ url.username = encodeURIComponent(decodeURIComponent(url.username));
+
+ url.password = value.slice(index + 1);
+ url.password = encodeURIComponent(decodeURIComponent(url.password));
+ } else {
+ url.username = encodeURIComponent(decodeURIComponent(value));
+ }
+ }
+
+ for (var i = 0; i < rules.length; i++) {
+ var ins = rules[i];
+
+ if (ins[4]) url[ins[1]] = url[ins[1]].toLowerCase();
+ }
+
+ url.auth = url.password ? url.username +':'+ url.password : url.username;
+
+ url.origin = url.protocol !== 'file:' && isSpecial(url.protocol) && url.host
+ ? 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} Compiled version of the URL.
+ * @public
+ */
+function toString(stringify) {
+ if (!stringify || 'function' !== typeof stringify) stringify = qs.stringify;
+
+ var query
+ , url = this
+ , host = url.host
+ , protocol = url.protocol;
+
+ if (protocol && protocol.charAt(protocol.length - 1) !== ':') protocol += ':';
+
+ var result =
+ protocol +
+ ((url.protocol && url.slashes) || isSpecial(url.protocol) ? '//' : '');
+
+ if (url.username) {
+ result += url.username;
+ if (url.password) result += ':'+ url.password;
+ result += '@';
+ } else if (url.password) {
+ result += ':'+ url.password;
+ result += '@';
+ } else if (
+ url.protocol !== 'file:' &&
+ isSpecial(url.protocol) &&
+ !host &&
+ url.pathname !== '/'
+ ) {
+ //
+ // Add back the empty userinfo, otherwise the original invalid URL
+ // might be transformed into a valid one with `url.pathname` as host.
+ //
+ result += '@';
+ }
+
+ //
+ // Trailing colon is removed from `url.host` when it is parsed. If it still
+ // ends with a colon, then add back the trailing colon that was removed. This
+ // prevents an invalid URL from being transformed into a valid one.
+ //
+ if (host[host.length - 1] === ':' || (port.test(url.hostname) && !url.port)) {
+ host += ':';
+ }
+
+ result += 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.trimLeft = trimLeft;
+Url.qs = qs;
+
+module.exports = Url;
+
+}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{"querystringify":2,"requires-port":3}],2:[function(require,module,exports){
+'use strict';
+
+var has = Object.prototype.hasOwnProperty
+ , undef;
+
+/**
+ * Decode a URI encoded string.
+ *
+ * @param {String} input The URI encoded string.
+ * @returns {String|Null} The decoded string.
+ * @api private
+ */
+function decode(input) {
+ try {
+ return decodeURIComponent(input.replace(/\+/g, ' '));
+ } catch (e) {
+ return null;
+ }
+}
+
+/**
+ * Attempts to encode a given input.
+ *
+ * @param {String} input The string that needs to be encoded.
+ * @returns {String|Null} The encoded string.
+ * @api private
+ */
+function encode(input) {
+ try {
+ return encodeURIComponent(input);
+ } catch (e) {
+ return null;
+ }
+}
+
+/**
+ * Simple query string parser.
+ *
+ * @param {String} query The query string that needs to be parsed.
+ * @returns {Object}
+ * @api public
+ */
+function querystring(query) {
+ var parser = /([^=?#&]+)=?([^&]*)/g
+ , result = {}
+ , part;
+
+ while (part = parser.exec(query)) {
+ var key = decode(part[1])
+ , value = decode(part[2]);
+
+ //
+ // Prevent overriding of existing properties. This ensures that build-in
+ // methods like `toString` or __proto__ are not overriden by malicious
+ // querystrings.
+ //
+ // In the case if failed decoding, we want to omit the key/value pairs
+ // from the result.
+ //
+ if (key === null || value === null || key in result) continue;
+ result[key] = value;
+ }
+
+ return result;
+}
+
+/**
+ * Transform a query string to an object.
+ *
+ * @param {Object} obj Object that should be transformed.
+ * @param {String} prefix Optional prefix.
+ * @returns {String}
+ * @api public
+ */
+function querystringify(obj, prefix) {
+ prefix = prefix || '';
+
+ var pairs = []
+ , value
+ , key;
+
+ //
+ // Optionally prefix with a '?' if needed
+ //
+ if ('string' !== typeof prefix) prefix = '?';
+
+ for (key in obj) {
+ if (has.call(obj, key)) {
+ value = obj[key];
+
+ //
+ // Edge cases where we actually want to encode the value to an empty
+ // string instead of the stringified value.
+ //
+ if (!value && (value === null || value === undef || isNaN(value))) {
+ value = '';
+ }
+
+ key = encode(key);
+ value = encode(value);
+
+ //
+ // If we failed to encode the strings, we should bail out as we don't
+ // want to add invalid strings to the query.
+ //
+ if (key === null || value === null) continue;
+ pairs.push(key +'='+ value);
+ }
+ }
+
+ return pairs.length ? prefix + pairs.join('&') : '';
+}
+
+//
+// Expose the module.
+//
+exports.stringify = querystringify;
+exports.parse = querystring;
+
+},{}],3:[function(require,module,exports){
+'use strict';
+
+/**
+ * Check if we're required to add a port number.
+ *
+ * @see https://url.spec.whatwg.org/#default-port
+ * @param {Number|String} port Port number we need to check
+ * @param {String} protocol Protocol we need to check against.
+ * @returns {Boolean} Is it a default port for the given protocol
+ * @api private
+ */
+module.exports = function required(port, protocol) {
+ protocol = protocol.split(':')[0];
+ port = +port;
+
+ if (!port) return false;
+
+ switch (protocol) {
+ case 'http':
+ case 'ws':
+ return port !== 80;
+
+ case 'https':
+ case 'wss':
+ return port !== 443;
+
+ case 'ftp':
+ return port !== 21;
+
+ case 'gopher':
+ return port !== 70;
+
+ case 'file':
+ return false;
+ }
+
+ return port !== 0;
+};
+
+},{}]},{},[1])(1)
+});
diff --git a/school/node_modules/url-parse/dist/url-parse.min.js b/school/node_modules/url-parse/dist/url-parse.min.js
new file mode 100644
index 0000000..f0b3b4c
--- /dev/null
+++ b/school/node_modules/url-parse/dist/url-parse.min.js
@@ -0,0 +1 @@
+!function(e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).URLParse=e()}(function(){return function n(r,s,a){function i(o,e){if(!s[o]){if(!r[o]){var t="function"==typeof require&&require;if(!e&&t)return t(o,!0);if(p)return p(o,!0);throw(e=new Error("Cannot find module '"+o+"'")).code="MODULE_NOT_FOUND",e}t=s[o]={exports:{}},r[o][0].call(t.exports,function(e){return i(r[o][1][e]||e)},t,t.exports,n,r,s,a)}return s[o].exports}for(var p="function"==typeof require&&require,e=0;e<a.length;e++)i(a[e]);return i}({1:[function(e,t,o){!function(a){!function(){"use strict";var f=e("requires-port"),h=e("querystringify"),o=/^[\x00-\x20\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+/,d=/[\n\r\t]/g,s=/^[A-Za-z][A-Za-z0-9+-.]*:\/\//,i=/:\d+$/,p=/^([a-z][a-z0-9.+-]*:)?(\/\/)?([\\/]+)?([\S\s]*)/i,v=/^[a-zA-Z]:/;function m(e){return(e||"").toString().replace(o,"")}var w=[["#","hash"],["?","query"],function(e,o){return g(o.protocol)?e.replace(/\\/g,"/"):e},["/","pathname"],["@","auth",1],[NaN,"host",void 0,1,1],[/:(\d*)$/,"port",void 0,1],[NaN,"hostname",void 0,1,1]],r={hash:1,query:1};function y(e){var o,t="undefined"!=typeof window?window:void 0!==a?a:"undefined"!=typeof self?self:{},t=t.location||{},n={},t=typeof(e=e||t);if("blob:"===e.protocol)n=new C(unescape(e.pathname),{});else if("string"==t)for(o in n=new C(e,{}),r)delete n[o];else if("object"==t){for(o in e)o in r||(n[o]=e[o]);void 0===n.slashes&&(n.slashes=s.test(e.href))}return n}function g(e){return"file:"===e||"ftp:"===e||"http:"===e||"https:"===e||"ws:"===e||"wss:"===e}function b(e,o){e=(e=m(e)).replace(d,""),o=o||{};var t,e=p.exec(e),n=e[1]?e[1].toLowerCase():"",r=!!e[2],s=!!e[3],a=0;return r?a=s?(t=e[2]+e[3]+e[4],e[2].length+e[3].length):(t=e[2]+e[4],e[2].length):s?(t=e[3]+e[4],a=e[3].length):t=e[4],"file:"===n?2<=a&&(t=t.slice(2)):g(n)?t=e[4]:n?r&&(t=t.slice(2)):2<=a&&g(o.protocol)&&(t=e[4]),{protocol:n,slashes:r||g(n),slashesCount:a,rest:t}}function C(e,o,t){if(e=(e=m(e)).replace(d,""),!(this instanceof C))return new C(e,o,t);var n,r,s,a,i,u=w.slice(),p=typeof o,c=this,l=0;for("object"!=p&&"string"!=p&&(t=o,o=null),t&&"function"!=typeof t&&(t=h.parse),n=!(p=b(e||"",o=y(o))).protocol&&!p.slashes,c.slashes=p.slashes||n&&o.slashes,c.protocol=p.protocol||o.protocol||"",e=p.rest,("file:"===p.protocol&&(2!==p.slashesCount||v.test(e))||!p.slashes&&(p.protocol||p.slashesCount<2||!g(c.protocol)))&&(u[3]=[/(.*)/,"pathname"]);l<u.length;l++)"function"!=typeof(s=u[l])?(r=s[0],i=s[1],r!=r?c[i]=e:"string"==typeof r?~(a="@"===r?e.lastIndexOf(r):e.indexOf(r))&&(e="number"==typeof s[2]?(c[i]=e.slice(0,a),e.slice(a+s[2])):(c[i]=e.slice(a),e.slice(0,a))):(a=r.exec(e))&&(c[i]=a[1],e=e.slice(0,a.index)),c[i]=c[i]||n&&s[3]&&o[i]||"",s[4]&&(c[i]=c[i].toLowerCase())):e=s(e,c);t&&(c.query=t(c.query)),n&&o.slashes&&"/"!==c.pathname.charAt(0)&&(""!==c.pathname||""!==o.pathname)&&(c.pathname=function(e,o){if(""===e)return o;for(var t=(o||"/").split("/").slice(0,-1).concat(e.split("/")),n=t.length,o=t[n-1],r=!1,s=0;n--;)"."===t[n]?t.splice(n,1):".."===t[n]?(t.splice(n,1),s++):s&&(0===n&&(r=!0),t.splice(n,1),s--);return r&&t.unshift(""),"."!==o&&".."!==o||t.push(""),t.join("/")}(c.pathname,o.pathname)),"/"!==c.pathname.charAt(0)&&g(c.protocol)&&(c.pathname="/"+c.pathname),f(c.port,c.protocol)||(c.host=c.hostname,c.port=""),c.username=c.password="",c.auth&&(~(a=c.auth.indexOf(":"))?(c.username=c.auth.slice(0,a),c.username=encodeURIComponent(decodeURIComponent(c.username)),c.password=c.auth.slice(a+1),c.password=encodeURIComponent(decodeURIComponent(c.password))):c.username=encodeURIComponent(decodeURIComponent(c.auth)),c.auth=c.password?c.username+":"+c.password:c.username),c.origin="file:"!==c.protocol&&g(c.protocol)&&c.host?c.protocol+"//"+c.host:"null",c.href=c.toString()}C.prototype={set:function(e,o,t){var n=this;switch(e){case"query":"string"==typeof o&&o.length&&(o=(t||h.parse)(o)),n[e]=o;break;case"port":n[e]=o,f(o,n.protocol)?o&&(n.host=n.hostname+":"+o):(n.host=n.hostname,n[e]="");break;case"hostname":n[e]=o,n.port&&(o+=":"+n.port),n.host=o;break;case"host":n[e]=o,i.test(o)?(o=o.split(":"),n.port=o.pop(),n.hostname=o.join(":")):(n.hostname=o,n.port="");break;case"protocol":n.protocol=o.toLowerCase(),n.slashes=!t;break;case"pathname":case"hash":o?(r="pathname"===e?"/":"#",n[e]=o.charAt(0)!==r?r+o:o):n[e]=o;break;case"username":case"password":n[e]=encodeURIComponent(o);break;case"auth":var r=o.indexOf(":");~r?(n.username=o.slice(0,r),n.username=encodeURIComponent(decodeURIComponent(n.username)),n.password=o.slice(r+1),n.password=encodeURIComponent(decodeURIComponent(n.password))):n.username=encodeURIComponent(decodeURIComponent(o))}for(var s=0;s<w.length;s++){var a=w[s];a[4]&&(n[a[1]]=n[a[1]].toLowerCase())}return n.auth=n.password?n.username+":"+n.password:n.username,n.origin="file:"!==n.protocol&&g(n.protocol)&&n.host?n.protocol+"//"+n.host:"null",n.href=n.toString(),n},toString:function(e){e&&"function"==typeof e||(e=h.stringify);var o=this,t=o.host,n=((n=o.protocol)&&":"!==n.charAt(n.length-1)&&(n+=":"),n+(o.protocol&&o.slashes||g(o.protocol)?"//":""));return o.username?(n+=o.username,o.password&&(n+=":"+o.password),n+="@"):o.password?n=n+(":"+o.password)+"@":"file:"!==o.protocol&&g(o.protocol)&&!t&&"/"!==o.pathname&&(n+="@"),(":"===t[t.length-1]||i.test(o.hostname)&&!o.port)&&(t+=":"),n+=t+o.pathname,(t="object"==typeof o.query?e(o.query):o.query)&&(n+="?"!==t.charAt(0)?"?"+t:t),o.hash&&(n+=o.hash),n}},C.extractProtocol=b,C.location=y,C.trimLeft=m,C.qs=h,t.exports=C}.call(this)}.call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{querystringify:2,"requires-port":3}],2:[function(e,o,t){"use strict";var s=Object.prototype.hasOwnProperty;function a(e){try{return decodeURIComponent(e.replace(/\+/g," "))}catch(e){return null}}function i(e){try{return encodeURIComponent(e)}catch(e){return null}}t.stringify=function(e,o){var t,n,r=[];for(n in"string"!=typeof(o=o||"")&&(o="?"),e)s.call(e,n)&&((t=e[n])||null!=t&&!isNaN(t)||(t=""),n=i(n),t=i(t),null!==n&&null!==t&&r.push(n+"="+t));return r.length?o+r.join("&"):""},t.parse=function(e){for(var o=/([^=?#&]+)=?([^&]*)/g,t={};r=o.exec(e);){var n=a(r[1]),r=a(r[2]);null===n||null===r||n in t||(t[n]=r)}return t}},{}],3:[function(e,o,t){"use strict";o.exports=function(e,o){if(o=o.split(":")[0],!(e=+e))return!1;switch(o){case"http":case"ws":return 80!==e;case"https":case"wss":return 443!==e;case"ftp":return 21!==e;case"gopher":return 70!==e;case"file":return!1}return 0!==e}},{}]},{},[1])(1)}); \ No newline at end of file
diff --git a/school/node_modules/url-parse/dist/url-parse.min.js.map b/school/node_modules/url-parse/dist/url-parse.min.js.map
new file mode 100644
index 0000000..f76548a
--- /dev/null
+++ b/school/node_modules/url-parse/dist/url-parse.min.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["dist/url-parse.js"],"names":["f","exports","module","define","amd","window","global","self","this","URLParse","r","e","n","t","o","i","c","require","u","a","Error","code","p","call","length","1","required","qs","controlOrWhitespace","CRHTLF","slashes","port","protocolre","windowsDriveLetter","trimLeft","str","toString","replace","rules","address","url","isSpecial","protocol","NaN","undefined","ignore","hash","query","lolcation","loc","key","globalVar","location","finaldestination","type","Url","unescape","pathname","test","href","scheme","extractProtocol","rest","match","exec","toLowerCase","forwardSlashes","otherSlashes","slashesCount","slice","parser","relative","parse","instruction","index","instructions","extracted","lastIndexOf","indexOf","charAt","base","path","split","concat","last","unshift","up","splice","push","join","resolve","host","hostname","username","password","auth","encodeURIComponent","decodeURIComponent","origin","prototype","set","part","value","fn","pop","char","ins","stringify","result","querystringify","requires-port","2","has","Object","hasOwnProperty","decode","input","encode","obj","prefix","pairs","isNaN","3"],"mappings":"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"} \ No newline at end of file
diff --git a/school/node_modules/url-parse/index.js b/school/node_modules/url-parse/index.js
new file mode 100644
index 0000000..b86c29f
--- /dev/null
+++ b/school/node_modules/url-parse/index.js
@@ -0,0 +1,589 @@
+'use strict';
+
+var required = require('requires-port')
+ , qs = require('querystringify')
+ , controlOrWhitespace = /^[\x00-\x20\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+/
+ , CRHTLF = /[\n\r\t]/g
+ , slashes = /^[A-Za-z][A-Za-z0-9+-.]*:\/\//
+ , port = /:\d+$/
+ , protocolre = /^([a-z][a-z0-9.+-]*:)?(\/\/)?([\\/]+)?([\S\s]*)/i
+ , windowsDriveLetter = /^[a-zA-Z]:/;
+
+/**
+ * Remove control characters and whitespace from the beginning of a string.
+ *
+ * @param {Object|String} str String to trim.
+ * @returns {String} A new string representing `str` stripped of control
+ * characters and whitespace from its beginning.
+ * @public
+ */
+function trimLeft(str) {
+ return (str ? str : '').toString().replace(controlOrWhitespace, '');
+}
+
+/**
+ * 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.
+ function sanitize(address, url) { // Sanitize what is left of the address
+ return isSpecial(url.protocol) ? address.replace(/\\/g, '/') : address;
+ },
+ ['/', '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.
+ * @public
+ */
+function lolcation(loc) {
+ var globalVar;
+
+ if (typeof window !== 'undefined') globalVar = window;
+ else if (typeof global !== 'undefined') globalVar = global;
+ else if (typeof self !== 'undefined') globalVar = self;
+ else globalVar = {};
+
+ var location = globalVar.location || {};
+ loc = loc || 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;
+}
+
+/**
+ * Check whether a protocol scheme is special.
+ *
+ * @param {String} The protocol scheme of the URL
+ * @return {Boolean} `true` if the protocol scheme is special, else `false`
+ * @private
+ */
+function isSpecial(scheme) {
+ return (
+ scheme === 'file:' ||
+ scheme === 'ftp:' ||
+ scheme === 'http:' ||
+ scheme === 'https:' ||
+ scheme === 'ws:' ||
+ scheme === 'wss:'
+ );
+}
+
+/**
+ * @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.
+ * @param {Object} location
+ * @return {ProtocolExtract} Extracted information.
+ * @private
+ */
+function extractProtocol(address, location) {
+ address = trimLeft(address);
+ address = address.replace(CRHTLF, '');
+ location = location || {};
+
+ var match = protocolre.exec(address);
+ var protocol = match[1] ? match[1].toLowerCase() : '';
+ var forwardSlashes = !!match[2];
+ var otherSlashes = !!match[3];
+ var slashesCount = 0;
+ var rest;
+
+ if (forwardSlashes) {
+ if (otherSlashes) {
+ rest = match[2] + match[3] + match[4];
+ slashesCount = match[2].length + match[3].length;
+ } else {
+ rest = match[2] + match[4];
+ slashesCount = match[2].length;
+ }
+ } else {
+ if (otherSlashes) {
+ rest = match[3] + match[4];
+ slashesCount = match[3].length;
+ } else {
+ rest = match[4]
+ }
+ }
+
+ if (protocol === 'file:') {
+ if (slashesCount >= 2) {
+ rest = rest.slice(2);
+ }
+ } else if (isSpecial(protocol)) {
+ rest = match[4];
+ } else if (protocol) {
+ if (forwardSlashes) {
+ rest = rest.slice(2);
+ }
+ } else if (slashesCount >= 2 && isSpecial(location.protocol)) {
+ rest = match[4];
+ }
+
+ return {
+ protocol: protocol,
+ slashes: forwardSlashes || isSpecial(protocol),
+ slashesCount: slashesCount,
+ rest: rest
+ };
+}
+
+/**
+ * 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.
+ * @private
+ */
+function resolve(relative, base) {
+ if (relative === '') return 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.
+ *
+ * It is worth noting that we should not use `URL` as class name to prevent
+ * clashes with the global URL instance that got introduced in browsers.
+ *
+ * @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.
+ * @private
+ */
+function Url(address, location, parser) {
+ address = trimLeft(address);
+ address = address.replace(CRHTLF, '');
+
+ 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 || '', location);
+ 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.protocol === 'file:' && (
+ extracted.slashesCount !== 2 || windowsDriveLetter.test(address)) ||
+ (!extracted.slashes &&
+ (extracted.protocol ||
+ extracted.slashesCount < 2 ||
+ !isSpecial(url.protocol)))
+ ) {
+ instructions[3] = [/(.*)/, 'pathname'];
+ }
+
+ for (; i < instructions.length; i++) {
+ instruction = instructions[i];
+
+ if (typeof instruction === 'function') {
+ address = instruction(address, url);
+ continue;
+ }
+
+ parse = instruction[0];
+ key = instruction[1];
+
+ if (parse !== parse) {
+ url[key] = address;
+ } else if ('string' === typeof parse) {
+ index = parse === '@'
+ ? address.lastIndexOf(parse)
+ : address.indexOf(parse);
+
+ if (~index) {
+ 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);
+ }
+
+ //
+ // Default to a / for pathname if none exists. This normalizes the URL
+ // to always have a /
+ //
+ if (url.pathname.charAt(0) !== '/' && isSpecial(url.protocol)) {
+ url.pathname = '/' + url.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) {
+ index = url.auth.indexOf(':');
+
+ if (~index) {
+ url.username = url.auth.slice(0, index);
+ url.username = encodeURIComponent(decodeURIComponent(url.username));
+
+ url.password = url.auth.slice(index + 1);
+ url.password = encodeURIComponent(decodeURIComponent(url.password))
+ } else {
+ url.username = encodeURIComponent(decodeURIComponent(url.auth));
+ }
+
+ url.auth = url.password ? url.username +':'+ url.password : url.username;
+ }
+
+ url.origin = url.protocol !== 'file:' && isSpecial(url.protocol) && url.host
+ ? 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} URL instance for chaining.
+ * @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 (port.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;
+
+ case 'username':
+ case 'password':
+ url[part] = encodeURIComponent(value);
+ break;
+
+ case 'auth':
+ var index = value.indexOf(':');
+
+ if (~index) {
+ url.username = value.slice(0, index);
+ url.username = encodeURIComponent(decodeURIComponent(url.username));
+
+ url.password = value.slice(index + 1);
+ url.password = encodeURIComponent(decodeURIComponent(url.password));
+ } else {
+ url.username = encodeURIComponent(decodeURIComponent(value));
+ }
+ }
+
+ for (var i = 0; i < rules.length; i++) {
+ var ins = rules[i];
+
+ if (ins[4]) url[ins[1]] = url[ins[1]].toLowerCase();
+ }
+
+ url.auth = url.password ? url.username +':'+ url.password : url.username;
+
+ url.origin = url.protocol !== 'file:' && isSpecial(url.protocol) && url.host
+ ? 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} Compiled version of the URL.
+ * @public
+ */
+function toString(stringify) {
+ if (!stringify || 'function' !== typeof stringify) stringify = qs.stringify;
+
+ var query
+ , url = this
+ , host = url.host
+ , protocol = url.protocol;
+
+ if (protocol && protocol.charAt(protocol.length - 1) !== ':') protocol += ':';
+
+ var result =
+ protocol +
+ ((url.protocol && url.slashes) || isSpecial(url.protocol) ? '//' : '');
+
+ if (url.username) {
+ result += url.username;
+ if (url.password) result += ':'+ url.password;
+ result += '@';
+ } else if (url.password) {
+ result += ':'+ url.password;
+ result += '@';
+ } else if (
+ url.protocol !== 'file:' &&
+ isSpecial(url.protocol) &&
+ !host &&
+ url.pathname !== '/'
+ ) {
+ //
+ // Add back the empty userinfo, otherwise the original invalid URL
+ // might be transformed into a valid one with `url.pathname` as host.
+ //
+ result += '@';
+ }
+
+ //
+ // Trailing colon is removed from `url.host` when it is parsed. If it still
+ // ends with a colon, then add back the trailing colon that was removed. This
+ // prevents an invalid URL from being transformed into a valid one.
+ //
+ if (host[host.length - 1] === ':' || (port.test(url.hostname) && !url.port)) {
+ host += ':';
+ }
+
+ result += 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.trimLeft = trimLeft;
+Url.qs = qs;
+
+module.exports = Url;
diff --git a/school/node_modules/url-parse/package.json b/school/node_modules/url-parse/package.json
new file mode 100644
index 0000000..8d1bbbe
--- /dev/null
+++ b/school/node_modules/url-parse/package.json
@@ -0,0 +1,49 @@
+{
+ "name": "url-parse",
+ "version": "1.5.10",
+ "description": "Small footprint URL parser that works seamlessly across Node.js and browser environments",
+ "main": "index.js",
+ "scripts": {
+ "browserify": "rm -rf dist && mkdir -p dist && browserify index.js -s URLParse -o dist/url-parse.js",
+ "minify": "uglifyjs dist/url-parse.js --source-map -cm -o dist/url-parse.min.js",
+ "test": "c8 --reporter=lcov --reporter=text mocha test/test.js",
+ "test-browser": "node test/browser.js",
+ "prepublishOnly": "npm run browserify && npm run minify",
+ "watch": "mocha --watch test/test.js"
+ },
+ "files": [
+ "index.js",
+ "dist"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/unshiftio/url-parse.git"
+ },
+ "keywords": [
+ "URL",
+ "parser",
+ "uri",
+ "url",
+ "parse",
+ "query",
+ "string",
+ "querystring",
+ "stringify"
+ ],
+ "author": "Arnout Kazemier",
+ "license": "MIT",
+ "dependencies": {
+ "querystringify": "^2.1.1",
+ "requires-port": "^1.0.0"
+ },
+ "devDependencies": {
+ "assume": "^2.2.0",
+ "browserify": "^17.0.0",
+ "c8": "^7.3.1",
+ "mocha": "^9.0.3",
+ "pre-commit": "^1.2.2",
+ "sauce-browsers": "^2.0.0",
+ "sauce-test": "^1.3.3",
+ "uglify-js": "^3.5.7"
+ }
+}