CB-13444: fixed merge conflict
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000..a547141
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1 @@
+cordova-lib/cordova.js
\ No newline at end of file
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 701e9c1..c808f18 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -20,6 +20,11 @@
 -->
 ## Release Notes for Cordova Browser ##
 
+### 5.0.1 (Oct 16, 2017)
+* [CB-13444](https://issues.apache.org/jira/browse/CB-13444) Updated checked-in `node_modules`
+* [CB-13435](https://issues.apache.org/jira/browse/CB-13435) fix merges directory support for **Browser**
+* [CB-12895](https://issues.apache.org/jira/browse/CB-12895) ignoring `cordova.js` for `eslint`
+
 ### 5.0.0 (Aug 24, 2017)
 * [CB-13214](https://issues.apache.org/jira/browse/CB-13214) Updated `cordova-serve` dependnecy to 2.0.0. `cordova serve` command now opens system default browser instead of a new instance of `chrome`. A specific target can still be passed in. 
 * [CB-13214](https://issues.apache.org/jira/browse/CB-13214) Updated checked-in `node_modules`
diff --git a/VERSION b/VERSION
index 0062ac9..6b244dc 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-5.0.0
+5.0.1
diff --git a/bin/lib/create.js b/bin/lib/create.js
index 647dc0f..667d9ff 100644
--- a/bin/lib/create.js
+++ b/bin/lib/create.js
@@ -83,8 +83,6 @@
     // copy manifest file to platform_www
     fs.writeFileSync(path.join(platform_www, 'manifest.json'),
         JSON.stringify(manifest, null, 2), 'utf-8');
-    // copy service worker
-    shell.cp(path.join(ROOT, 'bin/template/www', 'cordova-sw.js'), platform_www);
 
     return Promise.resolve();
 };
diff --git a/bin/template/cordova/Api.js b/bin/template/cordova/Api.js
index f9f7b1a..9752d24 100644
--- a/bin/template/cordova/Api.js
+++ b/bin/template/cordova/Api.js
@@ -159,7 +159,7 @@
     this.config.write();
 
     // Update own www dir with project's www assets and plugins' assets and js-files
-    this.parser.update_www(cordovaProject.locations.www);
+    this.parser.update_www(cordovaProject, options);
 
     // Copy or Create manifest.json
     // todo: move this to a manifest helper module
diff --git a/bin/template/cordova/browser_parser.js b/bin/template/cordova/browser_parser.js
index a6270c8..99397c3 100644
--- a/bin/template/cordova/browser_parser.js
+++ b/bin/template/cordova/browser_parser.js
@@ -21,6 +21,8 @@
 var path = require('path');
 var shell = require('shelljs');
 var CordovaError = require('cordova-common').CordovaError;
+var events = require('cordova-common').events;
+var FileUpdater = require('cordova-common').FileUpdater;
 
 function dirExists (dir) {
     return fs.existsSync(dir) && fs.statSync(dir).isDirectory();
@@ -56,22 +58,35 @@
     return path.resolve(jsPath);
 };
 
+/**
+ * Logs all file operations via the verbose event stream, indented.
+ */
+function logFileOp (message) {
+    events.emit('verbose', '  ' + message);
+}
+
 // Replace the www dir with contents of platform_www and app www.
-browser_parser.prototype.update_www = function () {
-    var projectRoot = this.path; /* eslint no-unused-vars : 0 */
-    var app_www = path.join(this.path, '../../www');
+browser_parser.prototype.update_www = function (cordovaProject, opts) {
     var platform_www = path.join(this.path, 'platform_www');
     var my_www = this.www_dir();
+    // add cordova www and platform_www to sourceDirs
+    var sourceDirs = [
+        path.relative(cordovaProject.root, cordovaProject.locations.www),
+        path.relative(cordovaProject.root, platform_www)
+    ];
 
-    // Clear the www dir
-    shell.rm('-rf', my_www);
-    shell.mkdir(my_www);
+    // If project contains 'merges' for our platform, use them as another overrides
+    var merges_path = path.join(cordovaProject.root, 'merges', 'browser');
+    if (fs.existsSync(merges_path)) {
+        events.emit('verbose', 'Found "merges/browser" folder. Copying its contents into the browser project.');
+        // add merges/browser to sourceDirs
+        sourceDirs.push(path.join('merges', 'browser'));
+    }
 
-    // Copy over stock platform www assets (cordova.js)
-    shell.cp('-rf', path.join(platform_www, '*'), my_www);
-
-    // Copy over all app www assets ( overwriting stock )
-    shell.cp('-rf', path.join(app_www, '*'), my_www);
+    // targetDir points to browser/www
+    var targetDir = path.relative(cordovaProject.root, my_www);
+    events.emit('verbose', 'Merging and updating files from [' + sourceDirs.join(', ') + '] to ' + targetDir);
+    FileUpdater.mergeAndUpdateDir(sourceDirs, targetDir, { rootDir: cordovaProject.root }, logFileOp);
 };
 
 browser_parser.prototype.update_overrides = function () {
diff --git a/bin/template/cordova/lib/build.js b/bin/template/cordova/lib/build.js
index 64e5198..01f3fb1 100644
--- a/bin/template/cordova/lib/build.js
+++ b/bin/template/cordova/lib/build.js
@@ -19,9 +19,7 @@
  * under the License.
  */
 
-var fs = require('fs');
 var path = require('path');
-var shell = require('shelljs');
 var check_reqs = require('./check_reqs');
 
 /**
@@ -29,32 +27,7 @@
  *   Creates a zip file int platform/build folder
  */
 module.exports.run = function () {
-
-    var resultP = check_reqs.run();
-
-    resultP.then(function () {
-        var wwwPath = path.join(__dirname, '../../www');
-
-        // generate a generic service worker
-        var lsdir = shell.find(wwwPath);
-        var pathLength = wwwPath.length;
-        var cleanedFileList = lsdir.filter(function (elem) {
-            // skip directory names, and cordova-js-src
-            return !fs.statSync(elem).isDirectory() &&
-                    elem.indexOf('cordova-js-src') < 0;
-        }).map(function (elem) {
-            return elem.substr(pathLength);
-        });
-
-        var swJSPath = path.join(wwwPath, 'cordova-sw.js');
-        var swJS = fs.readFileSync(swJSPath, 'utf8');
-
-        swJS = swJS.replace('%CACHE_VERSION%', Date.now());
-        swJS = swJS.replace("['CACHE_VALUES']", JSON.stringify(cleanedFileList, null, 4));
-
-        fs.writeFileSync(swJSPath, swJS, 'utf8');
-    });
-    return resultP;
+    return check_reqs.run();
 };
 
 module.exports.help = function () {
diff --git a/bin/template/cordova/version b/bin/template/cordova/version
index 28ae86f..7ab09ce 100755
--- a/bin/template/cordova/version
+++ b/bin/template/cordova/version
@@ -20,6 +20,6 @@
 */
 
 // Coho updates this line:
-var VERSION = "5.0.0";
+var VERSION = "5.0.1";
 
 console.log(VERSION);
diff --git a/bin/template/www/cordova-sw.js b/bin/template/www/cordova-sw.js
deleted file mode 100644
index 9740fb1..0000000
--- a/bin/template/www/cordova-sw.js
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-'License'); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
-*/
-
-// Note, these will be updated automatically at build time
-var CACHE_VERSION = '%CACHE_VERSION%';
-var CACHE_LIST = ['CACHE_VALUES'];
-
-this.addEventListener('install', function (event) {
-    // Perform install steps
-    console.log('cordova service worker is installing.');
-    event.waitUntil(caches.open(CACHE_VERSION) /* eslint no-undef : 0 */
-        .then(function (cache) {
-            return cache.addAll(CACHE_LIST);
-        }));
-});
-
-this.addEventListener('activate', function (event) {
-    // Perform activate steps
-    console.log('cordova service worker is activated.');
-});
-
-this.addEventListener('fetch', function (event) {
-    console.log('cordova service worker : fetch : ' + event.request.url);
-
-    event.respondWith(caches.match(event.request).then(function (response) { /* eslint no-undef : 0 */
-        // Cache hit? return response else fetch it
-        return response || fetch(event.request); /* eslint no-undef : 0 */
-    }));
-});
diff --git a/cordova-lib/cordova.js b/cordova-lib/cordova.js
index 872d6ec..4ac61ed 100644
--- a/cordova-lib/cordova.js
+++ b/cordova-lib/cordova.js
@@ -19,7 +19,7 @@
  under the License.
 */
 ;(function() {
-var PLATFORM_VERSION_BUILD_LABEL = '5.0.0';
+var PLATFORM_VERSION_BUILD_LABEL = '5.0.1';
 // file: src/scripts/require.js
 
 /*jshint -W079 */
@@ -1880,4 +1880,4 @@
 
 require('cordova/init');
 
-})();
\ No newline at end of file
+})();
diff --git a/node_modules/abbrev/LICENSE b/node_modules/abbrev/LICENSE
index 19129e3..9bcfa9d 100644
--- a/node_modules/abbrev/LICENSE
+++ b/node_modules/abbrev/LICENSE
@@ -1,3 +1,8 @@
+This software is dual-licensed under the ISC and MIT licenses.
+You may use this software under EITHER of the following licenses.
+
+----------
+
 The ISC License
 
 Copyright (c) Isaac Z. Schlueter and Contributors
@@ -13,3 +18,29 @@
 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
 IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+----------
+
+Copyright Isaac Z. Schlueter and Contributors
+All rights reserved.
+
+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/abbrev/package.json b/node_modules/abbrev/package.json
index 472a71d..a4ea597 100644
--- a/node_modules/abbrev/package.json
+++ b/node_modules/abbrev/package.json
@@ -14,19 +14,19 @@
     ]
   ],
   "_from": "abbrev@>=1.0.0 <2.0.0",
-  "_id": "abbrev@1.1.0",
+  "_id": "abbrev@1.1.1",
   "_inCache": true,
   "_location": "/abbrev",
-  "_nodeVersion": "8.0.0-pre",
+  "_nodeVersion": "8.5.0",
   "_npmOperationalInternal": {
-    "host": "packages-12-west.internal.npmjs.com",
-    "tmp": "tmp/abbrev-1.1.0.tgz_1487054000015_0.9229173036292195"
+    "host": "s3://npm-registry-packages",
+    "tmp": "tmp/abbrev-1.1.1.tgz_1506566833068_0.05750026390887797"
   },
   "_npmUser": {
     "name": "isaacs",
     "email": "i@izs.me"
   },
-  "_npmVersion": "4.3.0",
+  "_npmVersion": "5.4.2",
   "_phantomChildren": {},
   "_requested": {
     "raw": "abbrev@1",
@@ -40,8 +40,8 @@
   "_requiredBy": [
     "/nopt"
   ],
-  "_resolved": "http://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz",
-  "_shasum": "d0554c2256636e2f56e7c2e5ad183f859428d81f",
+  "_resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+  "_shasum": "f8f2c887ad10bf67f634f005b6987fed3179aac8",
   "_shrinkwrap": null,
   "_spec": "abbrev@1",
   "_where": "/Users/steveng/repo/cordova/cordova-browser/node_modules/nopt",
@@ -59,18 +59,23 @@
   },
   "directories": {},
   "dist": {
-    "shasum": "d0554c2256636e2f56e7c2e5ad183f859428d81f",
-    "tarball": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz"
+    "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
+    "shasum": "f8f2c887ad10bf67f634f005b6987fed3179aac8",
+    "tarball": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz"
   },
   "files": [
     "abbrev.js"
   ],
-  "gitHead": "7136d4d95449dc44115d4f78b80ec907724f64e0",
+  "gitHead": "a9ee72ebc8fe3975f1b0c7aeb3a8f2a806a432eb",
   "homepage": "https://github.com/isaacs/abbrev-js#readme",
   "license": "ISC",
   "main": "abbrev.js",
   "maintainers": [
     {
+      "name": "gabra",
+      "email": "jerry+1@npmjs.com"
+    },
+    {
       "name": "isaacs",
       "email": "i@izs.me"
     }
@@ -89,5 +94,5 @@
     "preversion": "npm test",
     "test": "tap test.js --100"
   },
-  "version": "1.1.0"
+  "version": "1.1.1"
 }
diff --git a/node_modules/accepts/package.json b/node_modules/accepts/package.json
index a312aa8..4529a46 100644
--- a/node_modules/accepts/package.json
+++ b/node_modules/accepts/package.json
@@ -2,18 +2,18 @@
   "_args": [
     [
       {
-        "raw": "accepts@~1.3.3",
+        "raw": "accepts@~1.3.4",
         "scope": null,
         "escapedName": "accepts",
         "name": "accepts",
-        "rawSpec": "~1.3.3",
-        "spec": ">=1.3.3 <1.4.0",
+        "rawSpec": "~1.3.4",
+        "spec": ">=1.3.4 <1.4.0",
         "type": "range"
       },
       "/Users/steveng/repo/cordova/cordova-browser/node_modules/compression"
     ]
   ],
-  "_from": "accepts@>=1.3.3 <1.4.0",
+  "_from": "accepts@>=1.3.4 <1.4.0",
   "_id": "accepts@1.3.4",
   "_inCache": true,
   "_location": "/accepts",
@@ -29,12 +29,12 @@
   "_npmVersion": "3.10.10",
   "_phantomChildren": {},
   "_requested": {
-    "raw": "accepts@~1.3.3",
+    "raw": "accepts@~1.3.4",
     "scope": null,
     "escapedName": "accepts",
     "name": "accepts",
-    "rawSpec": "~1.3.3",
-    "spec": ">=1.3.3 <1.4.0",
+    "rawSpec": "~1.3.4",
+    "spec": ">=1.3.4 <1.4.0",
     "type": "range"
   },
   "_requiredBy": [
@@ -44,7 +44,7 @@
   "_resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz",
   "_shasum": "86246758c7dd6d21a6474ff084a4740ec05eb21f",
   "_shrinkwrap": null,
-  "_spec": "accepts@~1.3.3",
+  "_spec": "accepts@~1.3.4",
   "_where": "/Users/steveng/repo/cordova/cordova-browser/node_modules/compression",
   "bugs": {
     "url": "https://github.com/jshttp/accepts/issues"
diff --git a/node_modules/adm-zip/README.md b/node_modules/adm-zip/README.md
deleted file mode 100644
index dd94d47..0000000
--- a/node_modules/adm-zip/README.md
+++ /dev/null
@@ -1,64 +0,0 @@
-# ADM-ZIP for NodeJS
-
-ADM-ZIP is a pure JavaScript implementation for zip data compression for [NodeJS](http://nodejs.org/). 
-
-# Installation
-
-With [npm](http://npmjs.org) do:
-
-    $ npm install adm-zip
-	
-## What is it good for?
-The library allows you to:
-
-* decompress zip files directly to disk or in memory buffers
-* compress files and store them to disk in .zip format or in compressed buffers
-* update content of/add new/delete files from an existing .zip
-
-# Dependencies
-There are no other nodeJS libraries that ADM-ZIP is dependent of
-
-# Examples
-
-## Basic usage
-```javascript
-
-	var AdmZip = require('adm-zip');
-
-	// reading archives
-	var zip = new AdmZip("./my_file.zip");
-	var zipEntries = zip.getEntries(); // an array of ZipEntry records
-
-	zipEntries.forEach(function(zipEntry) {
-	    console.log(zipEntry.toString()); // outputs zip entries information
-		if (zipEntry.entryName == "my_file.txt") {
-		     console.log(zipEntry.data.toString('utf8')); 
-		}
-	});
-	// outputs the content of some_folder/my_file.txt
-	console.log(zip.readAsText("some_folder/my_file.txt")); 
-	// extracts the specified file to the specified location
-	zip.extractEntryTo(/*entry name*/"some_folder/my_file.txt", /*target path*/"/home/me/tempfolder", /*maintainEntryPath*/false, /*overwrite*/true);
-	// extracts everything
-	zip.extractAllTo(/*target path*/"/home/me/zipcontent/", /*overwrite*/true);
-	
-	
-	// creating archives
-	var zip = new AdmZip();
-	
-	// add file directly
-	zip.addFile("test.txt", new Buffer("inner content of the file"), "entry comment goes here");
-	// add local file
-	zip.addLocalFile("/home/me/some_picture.png");
-	// get everything as a buffer
-	var willSendthis = zip.toBuffer();
-	// or write everything to disk
-	zip.writeZip(/*target file name*/"/home/me/files.zip");
-	
-	
-	// ... more examples in the wiki
-```
-
-For more detailed information please check out the [wiki](https://github.com/cthackers/adm-zip/wiki).
-
-[![build status](https://secure.travis-ci.org/cthackers/adm-zip.png)](http://travis-ci.org/cthackers/adm-zip)
diff --git a/node_modules/adm-zip/adm-zip.js b/node_modules/adm-zip/adm-zip.js
deleted file mode 100644
index 9ba4bd0..0000000
--- a/node_modules/adm-zip/adm-zip.js
+++ /dev/null
@@ -1,475 +0,0 @@
-var fs = require("fs"),
-    pth = require("path");
-
-fs.existsSync = fs.existsSync || pth.existsSync;
-
-var ZipEntry = require("./zipEntry"),
-    ZipFile =  require("./zipFile"),
-    Utils = require("./util");
-
-module.exports = function(/*String*/input) {
-    var _zip = undefined,
-        _filename = "";
-
-    if (input && typeof input === "string") { // load zip file
-        if (fs.existsSync(input)) {
-            _filename = input;
-            _zip = new ZipFile(input, Utils.Constants.FILE);
-        } else {
-           throw Utils.Errors.INVALID_FILENAME;
-        }
-    } else if(input && Buffer.isBuffer(input)) { // load buffer
-        _zip = new ZipFile(input, Utils.Constants.BUFFER);
-    } else { // create new zip file
-        _zip = new ZipFile(null, Utils.Constants.NONE);
-    }
-
-    function getEntry(/*Object*/entry) {
-        if (entry && _zip) {
-            var item;
-            // If entry was given as a file name
-            if (typeof entry === "string")
-                item = _zip.getEntry(entry);
-            // if entry was given as a ZipEntry object
-            if (typeof entry === "object" && entry.entryName != undefined && entry.header != undefined)
-                item =  _zip.getEntry(entry.entryName);
-
-            if (item) {
-                return item;
-            }
-        }
-        return null;
-    }
-
-    return {
-        /**
-         * Extracts the given entry from the archive and returns the content as a Buffer object
-         * @param entry ZipEntry object or String with the full path of the entry
-         *
-         * @return Buffer or Null in case of error
-         */
-        readFile : function(/*Object*/entry) {
-            var item = getEntry(entry);
-            return item && item.getData() || null;
-        },
-
-        /**
-         * Asynchronous readFile
-         * @param entry ZipEntry object or String with the full path of the entry
-         * @param callback
-         *
-         * @return Buffer or Null in case of error
-         */
-        readFileAsync : function(/*Object*/entry, /*Function*/callback) {
-            var item = getEntry(entry);
-            if (item) {
-                item.getDataAsync(callback);
-            } else {
-                callback(null,"getEntry failed for:" + entry)
-            }
-        },
-
-        /**
-         * Extracts the given entry from the archive and returns the content as plain text in the given encoding
-         * @param entry ZipEntry object or String with the full path of the entry
-         * @param encoding Optional. If no encoding is specified utf8 is used
-         *
-         * @return String
-         */
-        readAsText : function(/*Object*/entry, /*String - Optional*/encoding) {
-            var item = getEntry(entry);
-            if (item) {
-                var data = item.getData();
-                if (data && data.length) {
-                    return data.toString(encoding || "utf8");
-                }
-            }
-            return "";
-        },
-
-        /**
-         * Asynchronous readAsText
-         * @param entry ZipEntry object or String with the full path of the entry
-         * @param callback
-         * @param encoding Optional. If no encoding is specified utf8 is used
-         *
-         * @return String
-         */
-        readAsTextAsync : function(/*Object*/entry, /*Function*/callback, /*String - Optional*/encoding) {
-            var item = getEntry(entry);
-            if (item) {
-                item.getDataAsync(function(data) {
-                    if (data && data.length) {
-                        callback(data.toString(encoding || "utf8"));
-                    } else {
-                        callback("");
-                    }
-                })
-            } else {
-                callback("");
-            }
-        },
-
-        /**
-         * Remove the entry from the file or the entry and all it's nested directories and files if the given entry is a directory
-         *
-         * @param entry
-         */
-        deleteFile : function(/*Object*/entry) { // @TODO: test deleteFile
-            var item = getEntry(entry);
-            if (item) {
-                _zip.deleteEntry(item.entryName);
-            }
-        },
-
-        /**
-         * Adds a comment to the zip. The zip must be rewritten after adding the comment.
-         *
-         * @param comment
-         */
-        addZipComment : function(/*String*/comment) { // @TODO: test addZipComment
-            _zip.comment = comment;
-        },
-
-        /**
-         * Returns the zip comment
-         *
-         * @return String
-         */
-        getZipComment : function() {
-            return _zip.comment || '';
-        },
-
-        /**
-         * Adds a comment to a specified zipEntry. The zip must be rewritten after adding the comment
-         * The comment cannot exceed 65535 characters in length
-         *
-         * @param entry
-         * @param comment
-         */
-        addZipEntryComment : function(/*Object*/entry,/*String*/comment) {
-            var item = getEntry(entry);
-            if (item) {
-                item.comment = comment;
-            }
-        },
-
-        /**
-         * Returns the comment of the specified entry
-         *
-         * @param entry
-         * @return String
-         */
-        getZipEntryComment : function(/*Object*/entry) {
-            var item = getEntry(entry);
-            if (item) {
-                return item.comment || '';
-            }
-            return ''
-        },
-
-        /**
-         * Updates the content of an existing entry inside the archive. The zip must be rewritten after updating the content
-         *
-         * @param entry
-         * @param content
-         */
-        updateFile : function(/*Object*/entry, /*Buffer*/content) {
-            var item = getEntry(entry);
-            if (item) {
-                item.setData(content);
-            }
-        },
-
-        /**
-         * Adds a file from the disk to the archive
-         *
-         * @param localPath
-         */
-        addLocalFile : function(/*String*/localPath, /*String*/zipPath, /*String*/zipName) {
-             if (fs.existsSync(localPath)) {
-                if(zipPath){
-                    zipPath=zipPath.split("\\").join("/");
-                    if(zipPath.charAt(zipPath.length - 1) != "/"){
-                        zipPath += "/";
-                    }
-                }else{
-                    zipPath="";
-                }
-                 var p = localPath.split("\\").join("/").split("/").pop();
-                
-                 if(zipName){
-                    this.addFile(zipPath+zipName, fs.readFileSync(localPath), "", 0)
-                 }else{
-                    this.addFile(zipPath+p, fs.readFileSync(localPath), "", 0)
-                 }
-             } else {
-                 throw Utils.Errors.FILE_NOT_FOUND.replace("%s", localPath);
-             }
-        },
-
-        /**
-         * Adds a local directory and all its nested files and directories to the archive
-         *
-         * @param localPath
-         * @param zipPath optional path inside zip
-         * @param filter optional RegExp or Function if files match will
-         *               be included.
-         */
-        addLocalFolder : function(/*String*/localPath, /*String*/zipPath, /*RegExp|Function*/filter) {
-            if (filter === undefined) {
-              filter = function() { return true; };
-            } else if (filter instanceof RegExp) {
-              filter = function(filter) {
-                return function(filename) {
-                  return filter.test(filename);
-                }
-              }(filter);
-            }
-
-            if(zipPath){
-                zipPath=zipPath.split("\\").join("/");
-                if(zipPath.charAt(zipPath.length - 1) != "/"){
-                    zipPath += "/";
-                }
-            }else{
-                zipPath="";
-            }
-			localPath = localPath.split("\\").join("/"); //windows fix
-            localPath = pth.normalize(localPath);
-            if (localPath.charAt(localPath.length - 1) != "/")
-                localPath += "/";
-
-            if (fs.existsSync(localPath)) {
-
-                var items = Utils.findFiles(localPath),
-                    self = this;
-
-                if (items.length) {
-                    items.forEach(function(path) {
-						var p = path.split("\\").join("/").replace( new RegExp(localPath, 'i'), ""); //windows fix
-                        if (filter(p)) {
-                            if (p.charAt(p.length - 1) !== "/") {
-                                self.addFile(zipPath+p, fs.readFileSync(path), "", 0)
-                            } else {
-                                self.addFile(zipPath+p, new Buffer(0), "", 0)
-                            }
-                        }
-                    });
-                }
-            } else {
-                throw Utils.Errors.FILE_NOT_FOUND.replace("%s", localPath);
-            }
-        },
-
-        /**
-         * Allows you to create a entry (file or directory) in the zip file.
-         * If you want to create a directory the entryName must end in / and a null buffer should be provided.
-         * Comment and attributes are optional
-         *
-         * @param entryName
-         * @param content
-         * @param comment
-         * @param attr
-         */
-        addFile : function(/*String*/entryName, /*Buffer*/content, /*String*/comment, /*Number*/attr) {
-            var entry = new ZipEntry();
-            entry.entryName = entryName;
-            entry.comment = comment || "";
-            entry.attr = attr || 438; //0666;
-            if (entry.isDirectory && content.length) {
-               // throw Utils.Errors.DIRECTORY_CONTENT_ERROR;
-            }
-            entry.setData(content);
-            _zip.setEntry(entry);
-        },
-
-        /**
-         * Returns an array of ZipEntry objects representing the files and folders inside the archive
-         *
-         * @return Array
-         */
-        getEntries : function() {
-            if (_zip) {
-               return _zip.entries;
-            } else {
-                return [];
-            }
-        },
-
-        /**
-         * Returns a ZipEntry object representing the file or folder specified by ``name``.
-         *
-         * @param name
-         * @return ZipEntry
-         */
-        getEntry : function(/*String*/name) {
-            return getEntry(name);
-        },
-
-        /**
-         * Extracts the given entry to the given targetPath
-         * If the entry is a directory inside the archive, the entire directory and it's subdirectories will be extracted
-         *
-         * @param entry ZipEntry object or String with the full path of the entry
-         * @param targetPath Target folder where to write the file
-         * @param maintainEntryPath If maintainEntryPath is true and the entry is inside a folder, the entry folder
-         *                          will be created in targetPath as well. Default is TRUE
-         * @param overwrite If the file already exists at the target path, the file will be overwriten if this is true.
-         *                  Default is FALSE
-         *
-         * @return Boolean
-         */
-        extractEntryTo : function(/*Object*/entry, /*String*/targetPath, /*Boolean*/maintainEntryPath, /*Boolean*/overwrite) {
-            overwrite = overwrite || false;
-            maintainEntryPath = typeof maintainEntryPath == "undefined" ? true : maintainEntryPath;
-
-            var item = getEntry(entry);
-            if (!item) {
-                throw Utils.Errors.NO_ENTRY;
-            }
-
-            var target = pth.resolve(targetPath, maintainEntryPath ? item.entryName : pth.basename(item.entryName));
-
-            if (item.isDirectory) {
-                target = pth.resolve(target, "..");
-                var children = _zip.getEntryChildren(item);
-                children.forEach(function(child) {
-                    if (child.isDirectory) return;
-                    var content = child.getData();
-                    if (!content) {
-                        throw Utils.Errors.CANT_EXTRACT_FILE;
-                    }
-                    Utils.writeFileTo(pth.resolve(targetPath, maintainEntryPath ? child.entryName : child.entryName.substr(item.entryName.length)), content, overwrite);
-                });
-                return true;
-            }
-
-            var content = item.getData();
-            if (!content) throw Utils.Errors.CANT_EXTRACT_FILE;
-
-            if (fs.existsSync(target) && !overwrite) {
-                throw Utils.Errors.CANT_OVERRIDE;
-            }
-            Utils.writeFileTo(target, content, overwrite);
-
-            return true;
-        },
-
-        /**
-         * Extracts the entire archive to the given location
-         *
-         * @param targetPath Target location
-         * @param overwrite If the file already exists at the target path, the file will be overwriten if this is true.
-         *                  Default is FALSE
-         */
-        extractAllTo : function(/*String*/targetPath, /*Boolean*/overwrite) {
-            overwrite = overwrite || false;
-            if (!_zip) {
-                throw Utils.Errors.NO_ZIP;
-            }
-
-            _zip.entries.forEach(function(entry) {
-                if (entry.isDirectory) {
-                    Utils.makeDir(pth.resolve(targetPath, entry.entryName.toString()));
-                    return;
-                }
-                var content = entry.getData();
-                if (!content) {
-                    throw Utils.Errors.CANT_EXTRACT_FILE + "2";
-                }
-                Utils.writeFileTo(pth.resolve(targetPath, entry.entryName.toString()), content, overwrite);
-            })
-        },
-
-        /**
-         * Asynchronous extractAllTo
-         *
-         * @param targetPath Target location
-         * @param overwrite If the file already exists at the target path, the file will be overwriten if this is true.
-         *                  Default is FALSE
-         * @param callback
-         */
-        extractAllToAsync : function(/*String*/targetPath, /*Boolean*/overwrite, /*Function*/callback) {
-            overwrite = overwrite || false;
-            if (!_zip) {
-                callback(new Error(Utils.Errors.NO_ZIP));
-                return;
-            }
-
-            var entries = _zip.entries;
-            var i = entries.length; 
-            entries.forEach(function(entry) {
-                if(i <= 0) return; // Had an error already
-
-                if (entry.isDirectory) {
-                    Utils.makeDir(pth.resolve(targetPath, entry.entryName.toString()));
-                    if(--i == 0)
-                        callback(undefined);
-                    return;
-                }
-                entry.getDataAsync(function(content) {
-                    if(i <= 0) return;
-                    if (!content) {
-                        i = 0;
-                        callback(new Error(Utils.Errors.CANT_EXTRACT_FILE + "2"));
-                        return;
-                    }
-                    Utils.writeFileToAsync(pth.resolve(targetPath, entry.entryName.toString()), content, overwrite, function(succ) {
-                        if(i <= 0) return;
-
-                        if(!succ) {
-                            i = 0;
-                            callback(new Error('Unable to write'));
-                            return;
-                        }
-
-                        if(--i == 0)
-                            callback(undefined);
-                    });
-                    
-                });
-            })
-        },
-
-        /**
-         * Writes the newly created zip file to disk at the specified location or if a zip was opened and no ``targetFileName`` is provided, it will overwrite the opened zip
-         *
-         * @param targetFileName
-         * @param callback
-         */
-        writeZip : function(/*String*/targetFileName, /*Function*/callback) {
-            if (arguments.length == 1) {
-                if (typeof targetFileName == "function") {
-                    callback = targetFileName;
-                    targetFileName = "";
-                }
-            }
-
-            if (!targetFileName && _filename) {
-                targetFileName = _filename;
-            }
-            if (!targetFileName) return;
-
-            var zipData = _zip.compressToBuffer();
-            if (zipData) {
-                var ok = Utils.writeFileTo(targetFileName, zipData, true);
-                if (typeof callback == 'function') callback(!ok? new Error("failed"): null, "");
-            }
-        },
-
-        /**
-         * Returns the content of the entire zip file as a Buffer object
-         *
-         * @return Buffer
-         */
-        toBuffer : function(/*Function*/onSuccess,/*Function*/onFail,/*Function*/onItemStart,/*Function*/onItemEnd) {
-            this.valueOf = 2;
-            if (typeof onSuccess == "function") {
-                _zip.toAsyncBuffer(onSuccess,onFail,onItemStart,onItemEnd);
-                return null;
-            }
-            return _zip.compressToBuffer()
-        }
-    }
-};
diff --git a/node_modules/adm-zip/headers/entryHeader.js b/node_modules/adm-zip/headers/entryHeader.js
deleted file mode 100644
index 9a0e1bd..0000000
--- a/node_modules/adm-zip/headers/entryHeader.js
+++ /dev/null
@@ -1,261 +0,0 @@
-var Utils = require("../util"),
-    Constants = Utils.Constants;
-
-/* The central directory file header */
-module.exports = function () {
-    var _verMade = 0x0A,
-        _version = 0x0A,
-        _flags = 0,
-        _method = 0,
-        _time = 0,
-        _crc = 0,
-        _compressedSize = 0,
-        _size = 0,
-        _fnameLen = 0,
-        _extraLen = 0,
-
-        _comLen = 0,
-        _diskStart = 0,
-        _inattr = 0,
-        _attr = 0,
-        _offset = 0;
-
-    var _dataHeader = {};
-
-    function setTime(val) {
-        var val = new Date(val);
-        _time = (val.getFullYear() - 1980 & 0x7f) << 25  // b09-16 years from 1980
-            | (val.getMonth() + 1) << 21                 // b05-08 month
-            | val.getDay() << 16                         // b00-04 hour
-
-            // 2 bytes time
-            | val.getHours() << 11    // b11-15 hour
-            | val.getMinutes() << 5   // b05-10 minute
-            | val.getSeconds() >> 1;  // b00-04 seconds divided by 2
-    }
-
-    setTime(+new Date());
-
-    return {
-        get made () { return _verMade; },
-        set made (val) { _verMade = val; },
-
-        get version () { return _version; },
-        set version (val) { _version = val },
-
-        get flags () { return _flags },
-        set flags (val) { _flags = val; },
-
-        get method () { return _method; },
-        set method (val) { _method = val; },
-
-        get time () { return new Date(
-            ((_time >> 25) & 0x7f) + 1980,
-            ((_time >> 21) & 0x0f) - 1,
-            (_time >> 16) & 0x1f,
-            (_time >> 11) & 0x1f,
-            (_time >> 5) & 0x3f,
-            (_time & 0x1f) << 1
-        );
-        },
-        set time (val) {
-            setTime(val);
-        },
-
-        get crc () { return _crc; },
-        set crc (val) { _crc = val; },
-
-        get compressedSize () { return _compressedSize; },
-        set compressedSize (val) { _compressedSize = val; },
-
-        get size () { return _size; },
-        set size (val) { _size = val; },
-
-        get fileNameLength () { return _fnameLen; },
-        set fileNameLength (val) { _fnameLen = val; },
-
-        get extraLength () { return _extraLen },
-        set extraLength (val) { _extraLen = val; },
-
-        get commentLength () { return _comLen },
-        set commentLength (val) { _comLen = val },
-
-        get diskNumStart () { return _diskStart },
-        set diskNumStart (val) { _diskStart = val },
-
-        get inAttr () { return _inattr },
-        set inAttr (val) { _inattr = val },
-
-        get attr () { return _attr },
-        set attr (val) { _attr = val },
-
-        get offset () { return _offset },
-        set offset (val) { _offset = val },
-
-        get encripted () { return (_flags & 1) == 1 },
-
-        get entryHeaderSize () {
-            return Constants.CENHDR + _fnameLen + _extraLen + _comLen;
-        },
-
-        get realDataOffset () {
-            return _offset + Constants.LOCHDR + _dataHeader.fnameLen + _dataHeader.extraLen;
-        },
-
-        get dataHeader () {
-            return _dataHeader;
-        },
-
-        loadDataHeaderFromBinary : function(/*Buffer*/input) {
-            var data = input.slice(_offset, _offset + Constants.LOCHDR);
-            // 30 bytes and should start with "PK\003\004"
-            if (data.readUInt32LE(0) != Constants.LOCSIG) {
-                throw Utils.Errors.INVALID_LOC;
-            }
-            _dataHeader = {
-                // version needed to extract
-                version : data.readUInt16LE(Constants.LOCVER),
-                // general purpose bit flag
-                flags : data.readUInt16LE(Constants.LOCFLG),
-                // compression method
-                method : data.readUInt16LE(Constants.LOCHOW),
-                // modification time (2 bytes time, 2 bytes date)
-                time : data.readUInt32LE(Constants.LOCTIM),
-                // uncompressed file crc-32 value
-                crc : data.readUInt32LE(Constants.LOCCRC),
-                // compressed size
-                compressedSize : data.readUInt32LE(Constants.LOCSIZ),
-                // uncompressed size
-                size : data.readUInt32LE(Constants.LOCLEN),
-                // filename length
-                fnameLen : data.readUInt16LE(Constants.LOCNAM),
-                // extra field length
-                extraLen : data.readUInt16LE(Constants.LOCEXT)
-            }
-        },
-
-        loadFromBinary : function(/*Buffer*/data) {
-            // data should be 46 bytes and start with "PK 01 02"
-            if (data.length != Constants.CENHDR || data.readUInt32LE(0) != Constants.CENSIG) {
-                throw Utils.Errors.INVALID_CEN;
-            }
-            // version made by
-            _verMade = data.readUInt16LE(Constants.CENVEM);
-            // version needed to extract
-            _version = data.readUInt16LE(Constants.CENVER);
-            // encrypt, decrypt flags
-            _flags = data.readUInt16LE(Constants.CENFLG);
-            // compression method
-            _method = data.readUInt16LE(Constants.CENHOW);
-            // modification time (2 bytes time, 2 bytes date)
-            _time = data.readUInt32LE(Constants.CENTIM);
-            // uncompressed file crc-32 value
-            _crc = data.readUInt32LE(Constants.CENCRC);
-            // compressed size
-            _compressedSize = data.readUInt32LE(Constants.CENSIZ);
-            // uncompressed size
-            _size = data.readUInt32LE(Constants.CENLEN);
-            // filename length
-            _fnameLen = data.readUInt16LE(Constants.CENNAM);
-            // extra field length
-            _extraLen = data.readUInt16LE(Constants.CENEXT);
-            // file comment length
-            _comLen = data.readUInt16LE(Constants.CENCOM);
-            // volume number start
-            _diskStart = data.readUInt16LE(Constants.CENDSK);
-            // internal file attributes
-            _inattr = data.readUInt16LE(Constants.CENATT);
-            // external file attributes
-            _attr = data.readUInt32LE(Constants.CENATX);
-            // LOC header offset
-            _offset = data.readUInt32LE(Constants.CENOFF);
-        },
-
-        dataHeaderToBinary : function() {
-            // LOC header size (30 bytes)
-            var data = new Buffer(Constants.LOCHDR);
-            // "PK\003\004"
-            data.writeUInt32LE(Constants.LOCSIG, 0);
-            // version needed to extract
-            data.writeUInt16LE(_version, Constants.LOCVER);
-            // general purpose bit flag
-            data.writeUInt16LE(_flags, Constants.LOCFLG);
-            // compression method
-            data.writeUInt16LE(_method, Constants.LOCHOW);
-            // modification time (2 bytes time, 2 bytes date)
-            data.writeUInt32LE(_time, Constants.LOCTIM);
-            // uncompressed file crc-32 value
-            data.writeUInt32LE(_crc, Constants.LOCCRC);
-            // compressed size
-            data.writeUInt32LE(_compressedSize, Constants.LOCSIZ);
-            // uncompressed size
-            data.writeUInt32LE(_size, Constants.LOCLEN);
-            // filename length
-            data.writeUInt16LE(_fnameLen, Constants.LOCNAM);
-            // extra field length
-            data.writeUInt16LE(_extraLen, Constants.LOCEXT);
-            return data;
-        },
-
-        entryHeaderToBinary : function() {
-            // CEN header size (46 bytes)
-            var data = new Buffer(Constants.CENHDR + _fnameLen + _extraLen + _comLen);
-            // "PK\001\002"
-            data.writeUInt32LE(Constants.CENSIG, 0);
-            // version made by
-            data.writeUInt16LE(_verMade, Constants.CENVEM);
-            // version needed to extract
-            data.writeUInt16LE(_version, Constants.CENVER);
-            // encrypt, decrypt flags
-            data.writeUInt16LE(_flags, Constants.CENFLG);
-            // compression method
-            data.writeUInt16LE(_method, Constants.CENHOW);
-            // modification time (2 bytes time, 2 bytes date)
-            data.writeUInt32LE(_time, Constants.CENTIM);
-            // uncompressed file crc-32 value
-            data.writeInt32LE(_crc, Constants.CENCRC, true);
-            // compressed size
-            data.writeUInt32LE(_compressedSize, Constants.CENSIZ);
-            // uncompressed size
-            data.writeUInt32LE(_size, Constants.CENLEN);
-            // filename length
-            data.writeUInt16LE(_fnameLen, Constants.CENNAM);
-            // extra field length
-            data.writeUInt16LE(_extraLen, Constants.CENEXT);
-            // file comment length
-            data.writeUInt16LE(_comLen, Constants.CENCOM);
-            // volume number start
-            data.writeUInt16LE(_diskStart, Constants.CENDSK);
-            // internal file attributes
-            data.writeUInt16LE(_inattr, Constants.CENATT);
-            // external file attributes
-            data.writeUInt32LE(_attr, Constants.CENATX);
-            // LOC header offset
-            data.writeUInt32LE(_offset, Constants.CENOFF);
-            // fill all with
-            data.fill(0x00, Constants.CENHDR);
-            return data;
-        },
-
-        toString : function() {
-            return '{\n' +
-                '\t"made" : ' + _verMade + ",\n" +
-                '\t"version" : ' + _version + ",\n" +
-                '\t"flags" : ' + _flags + ",\n" +
-                '\t"method" : ' + Utils.methodToString(_method) + ",\n" +
-                '\t"time" : ' + _time + ",\n" +
-                '\t"crc" : 0x' + _crc.toString(16).toUpperCase() + ",\n" +
-                '\t"compressedSize" : ' + _compressedSize + " bytes,\n" +
-                '\t"size" : ' + _size + " bytes,\n" +
-                '\t"fileNameLength" : ' + _fnameLen + ",\n" +
-                '\t"extraLength" : ' + _extraLen + " bytes,\n" +
-                '\t"commentLength" : ' + _comLen + " bytes,\n" +
-                '\t"diskNumStart" : ' + _diskStart + ",\n" +
-                '\t"inAttr" : ' + _inattr + ",\n" +
-                '\t"attr" : ' + _attr + ",\n" +
-                '\t"offset" : ' + _offset + ",\n" +
-                '\t"entryHeaderSize" : ' + (Constants.CENHDR + _fnameLen + _extraLen + _comLen) + " bytes\n" +
-                '}';
-        }
-    }
-};
diff --git a/node_modules/adm-zip/headers/index.js b/node_modules/adm-zip/headers/index.js
deleted file mode 100644
index b54a722..0000000
--- a/node_modules/adm-zip/headers/index.js
+++ /dev/null
@@ -1,2 +0,0 @@
-exports.EntryHeader = require("./entryHeader");
-exports.MainHeader = require("./mainHeader");
diff --git a/node_modules/adm-zip/headers/mainHeader.js b/node_modules/adm-zip/headers/mainHeader.js
deleted file mode 100644
index de8ae1a..0000000
--- a/node_modules/adm-zip/headers/mainHeader.js
+++ /dev/null
@@ -1,80 +0,0 @@
-var Utils = require("../util"),
-    Constants = Utils.Constants;
-
-/* The entries in the end of central directory */
-module.exports = function () {
-    var _volumeEntries = 0,
-        _totalEntries = 0,
-        _size = 0,
-        _offset = 0,
-        _commentLength = 0;
-
-    return {
-        get diskEntries () { return _volumeEntries },
-        set diskEntries (/*Number*/val) { _volumeEntries = _totalEntries = val; },
-
-        get totalEntries () { return _totalEntries },
-        set totalEntries (/*Number*/val) { _totalEntries = _volumeEntries = val; },
-
-        get size () { return _size },
-        set size (/*Number*/val) { _size = val; },
-
-        get offset () { return _offset },
-        set offset (/*Number*/val) { _offset = val; },
-
-        get commentLength () { return _commentLength },
-        set commentLength (/*Number*/val) { _commentLength = val; },
-
-        get mainHeaderSize () {
-            return Constants.ENDHDR + _commentLength;
-        },
-
-        loadFromBinary : function(/*Buffer*/data) {
-            // data should be 22 bytes and start with "PK 05 06"
-            if (data.length != Constants.ENDHDR || data.readUInt32LE(0) != Constants.ENDSIG)
-                throw Utils.Errors.INVALID_END;
-
-            // number of entries on this volume
-            _volumeEntries = data.readUInt16LE(Constants.ENDSUB);
-            // total number of entries
-            _totalEntries = data.readUInt16LE(Constants.ENDTOT);
-            // central directory size in bytes
-            _size = data.readUInt32LE(Constants.ENDSIZ);
-            // offset of first CEN header
-            _offset = data.readUInt32LE(Constants.ENDOFF);
-            // zip file comment length
-            _commentLength = data.readUInt16LE(Constants.ENDCOM);
-        },
-
-        toBinary : function() {
-           var b = new Buffer(Constants.ENDHDR + _commentLength);
-            // "PK 05 06" signature
-            b.writeUInt32LE(Constants.ENDSIG, 0);
-            b.writeUInt32LE(0, 4);
-            // number of entries on this volume
-            b.writeUInt16LE(_volumeEntries, Constants.ENDSUB);
-            // total number of entries
-            b.writeUInt16LE(_totalEntries, Constants.ENDTOT);
-            // central directory size in bytes
-            b.writeUInt32LE(_size, Constants.ENDSIZ);
-            // offset of first CEN header
-            b.writeUInt32LE(_offset, Constants.ENDOFF);
-            // zip file comment length
-            b.writeUInt16LE(_commentLength, Constants.ENDCOM);
-            // fill comment memory with spaces so no garbage is left there
-            b.fill(" ", Constants.ENDHDR);
-
-            return b;
-        },
-
-        toString : function() {
-            return '{\n' +
-                '\t"diskEntries" : ' + _volumeEntries + ",\n" +
-                '\t"totalEntries" : ' + _totalEntries + ",\n" +
-                '\t"size" : ' + _size + " bytes,\n" +
-                '\t"offset" : 0x' + _offset.toString(16).toUpperCase() + ",\n" +
-                '\t"commentLength" : 0x' + _commentLength + "\n" +
-            '}';
-        }
-    }
-};
\ No newline at end of file
diff --git a/node_modules/adm-zip/methods/deflater.js b/node_modules/adm-zip/methods/deflater.js
deleted file mode 100644
index 34ef297..0000000
--- a/node_modules/adm-zip/methods/deflater.js
+++ /dev/null
@@ -1,1578 +0,0 @@
-/*
- * $Id: rawdeflate.js,v 0.5 2013/04/09 14:25:38 dankogai Exp dankogai $
- *
- * GNU General Public License, version 2 (GPL-2.0)
- *   http://opensource.org/licenses/GPL-2.0
- * Original:
- *  http://www.onicos.com/staff/iz/amuse/javascript/expert/deflate.txt
- */
-function JSDeflater(/*inbuff*/inbuf) {
-
-    /* Copyright (C) 1999 Masanao Izumo <iz@onicos.co.jp>
-     * Version: 1.0.1
-     * LastModified: Dec 25 1999
-     */
-
-    var WSIZE = 32768,		// Sliding Window size
-        zip_STORED_BLOCK = 0,
-        zip_STATIC_TREES = 1,
-        zip_DYN_TREES = 2,
-        zip_DEFAULT_LEVEL = 6,
-        zip_FULL_SEARCH = true,
-        zip_INBUFSIZ = 32768,	// Input buffer size
-        zip_INBUF_EXTRA = 64,	// Extra buffer
-        zip_OUTBUFSIZ = 1024 * 8,
-        zip_window_size = 2 * WSIZE,
-        MIN_MATCH = 3,
-        MAX_MATCH = 258,
-        zip_BITS = 16,
-        LIT_BUFSIZE = 0x2000,
-        zip_HASH_BITS = 13,
-        zip_DIST_BUFSIZE = LIT_BUFSIZE,
-        zip_HASH_SIZE = 1 << zip_HASH_BITS,
-        zip_HASH_MASK = zip_HASH_SIZE - 1,
-        zip_WMASK = WSIZE - 1,
-        zip_NIL = 0, // Tail of hash chains
-        zip_TOO_FAR = 4096,
-        zip_MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1,
-        zip_MAX_DIST = WSIZE - zip_MIN_LOOKAHEAD,
-        zip_SMALLEST = 1,
-        zip_MAX_BITS = 15,
-        zip_MAX_BL_BITS = 7,
-        zip_LENGTH_CODES = 29,
-        zip_LITERALS = 256,
-        zip_END_BLOCK = 256,
-        zip_L_CODES = zip_LITERALS + 1 + zip_LENGTH_CODES,
-        zip_D_CODES = 30,
-        zip_BL_CODES = 19,
-        zip_REP_3_6 = 16,
-        zip_REPZ_3_10 = 17,
-        zip_REPZ_11_138 = 18,
-        zip_HEAP_SIZE = 2 * zip_L_CODES + 1,
-        zip_H_SHIFT = parseInt((zip_HASH_BITS + MIN_MATCH - 1) / MIN_MATCH);
-
-    var zip_free_queue, zip_qhead, zip_qtail, zip_initflag, zip_outbuf = null, zip_outcnt, zip_outoff, zip_complete,
-        zip_window, zip_d_buf, zip_l_buf, zip_prev, zip_bi_buf, zip_bi_valid, zip_block_start, zip_ins_h, zip_hash_head,
-        zip_prev_match, zip_match_available, zip_match_length, zip_prev_length, zip_strstart, zip_match_start, zip_eofile,
-        zip_lookahead, zip_max_chain_length, zip_max_lazy_match, zip_compr_level, zip_good_match, zip_nice_match,
-        zip_dyn_ltree, zip_dyn_dtree, zip_static_ltree, zip_static_dtree, zip_bl_tree, zip_l_desc, zip_d_desc, zip_bl_desc,
-        zip_bl_count, zip_heap, zip_heap_len, zip_heap_max, zip_depth, zip_length_code, zip_dist_code, zip_base_length,
-        zip_base_dist, zip_flag_buf, zip_last_lit, zip_last_dist, zip_last_flags, zip_flags, zip_flag_bit, zip_opt_len,
-        zip_static_len, zip_deflate_data, zip_deflate_pos;
-
-    var zip_DeflateCT = function () {
-        this.fc = 0; // frequency count or bit string
-        this.dl = 0; // father node in Huffman tree or length of bit string
-    };
-
-    var zip_DeflateTreeDesc = function () {
-        this.dyn_tree = null;	// the dynamic tree
-        this.static_tree = null;	// corresponding static tree or NULL
-        this.extra_bits = null;	// extra bits for each code or NULL
-        this.extra_base = 0;	// base index for extra_bits
-        this.elems = 0;		// max number of elements in the tree
-        this.max_length = 0;	// max bit length for the codes
-        this.max_code = 0;		// largest code with non zero frequency
-    };
-
-    /* Values for max_lazy_match, good_match and max_chain_length, depending on
-     * the desired pack level (0..9). The values given below have been tuned to
-     * exclude worst case performance for pathological files. Better values may be
-     * found for specific files.
-     */
-    var zip_DeflateConfiguration = function (a, b, c, d) {
-        this.good_length = a; // reduce lazy search above this match length
-        this.max_lazy = b;    // do not perform lazy search above this match length
-        this.nice_length = c; // quit search above this match length
-        this.max_chain = d;
-    };
-
-    var zip_DeflateBuffer = function () {
-        this.next = null;
-        this.len = 0;
-        this.ptr = new Array(zip_OUTBUFSIZ);
-        this.off = 0;
-    };
-
-    /* constant tables */
-    var zip_extra_lbits = new Array(
-        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0);
-    var zip_extra_dbits = new Array(
-        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13);
-    var zip_extra_blbits = new Array(
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7);
-    var zip_bl_order = new Array(
-        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15);
-    var zip_configuration_table = new Array(
-        new zip_DeflateConfiguration(0, 0, 0, 0),
-        new zip_DeflateConfiguration(4, 4, 8, 4),
-        new zip_DeflateConfiguration(4, 5, 16, 8),
-        new zip_DeflateConfiguration(4, 6, 32, 32),
-        new zip_DeflateConfiguration(4, 4, 16, 16),
-        new zip_DeflateConfiguration(8, 16, 32, 32),
-        new zip_DeflateConfiguration(8, 16, 128, 128),
-        new zip_DeflateConfiguration(8, 32, 128, 256),
-        new zip_DeflateConfiguration(32, 128, 258, 1024),
-        new zip_DeflateConfiguration(32, 258, 258, 4096));
-
-
-    /* routines (deflate) */
-
-    var zip_deflate_start = function (level) {
-        var i;
-
-        if (!level)
-            level = zip_DEFAULT_LEVEL;
-        else if (level < 1)
-            level = 1;
-        else if (level > 9)
-            level = 9;
-
-        zip_compr_level = level;
-        zip_initflag = false;
-        zip_eofile = false;
-        if (zip_outbuf != null)
-            return;
-
-        zip_free_queue = zip_qhead = zip_qtail = null;
-        zip_outbuf = new Array(zip_OUTBUFSIZ);
-        zip_window = new Array(zip_window_size);
-        zip_d_buf = new Array(zip_DIST_BUFSIZE);
-        zip_l_buf = new Array(zip_INBUFSIZ + zip_INBUF_EXTRA);
-        zip_prev = new Array(1 << zip_BITS);
-        zip_dyn_ltree = new Array(zip_HEAP_SIZE);
-        for (i = 0; i < zip_HEAP_SIZE; i++) zip_dyn_ltree[i] = new zip_DeflateCT();
-        zip_dyn_dtree = new Array(2 * zip_D_CODES + 1);
-        for (i = 0; i < 2 * zip_D_CODES + 1; i++) zip_dyn_dtree[i] = new zip_DeflateCT();
-        zip_static_ltree = new Array(zip_L_CODES + 2);
-        for (i = 0; i < zip_L_CODES + 2; i++) zip_static_ltree[i] = new zip_DeflateCT();
-        zip_static_dtree = new Array(zip_D_CODES);
-        for (i = 0; i < zip_D_CODES; i++) zip_static_dtree[i] = new zip_DeflateCT();
-        zip_bl_tree = new Array(2 * zip_BL_CODES + 1);
-        for (i = 0; i < 2 * zip_BL_CODES + 1; i++) zip_bl_tree[i] = new zip_DeflateCT();
-        zip_l_desc = new zip_DeflateTreeDesc();
-        zip_d_desc = new zip_DeflateTreeDesc();
-        zip_bl_desc = new zip_DeflateTreeDesc();
-        zip_bl_count = new Array(zip_MAX_BITS + 1);
-        zip_heap = new Array(2 * zip_L_CODES + 1);
-        zip_depth = new Array(2 * zip_L_CODES + 1);
-        zip_length_code = new Array(MAX_MATCH - MIN_MATCH + 1);
-        zip_dist_code = new Array(512);
-        zip_base_length = new Array(zip_LENGTH_CODES);
-        zip_base_dist = new Array(zip_D_CODES);
-        zip_flag_buf = new Array(parseInt(LIT_BUFSIZE / 8));
-    };
-
-    var zip_deflate_end = function () {
-        zip_free_queue = zip_qhead = zip_qtail = null;
-        zip_outbuf = null;
-        zip_window = null;
-        zip_d_buf = null;
-        zip_l_buf = null;
-        zip_prev = null;
-        zip_dyn_ltree = null;
-        zip_dyn_dtree = null;
-        zip_static_ltree = null;
-        zip_static_dtree = null;
-        zip_bl_tree = null;
-        zip_l_desc = null;
-        zip_d_desc = null;
-        zip_bl_desc = null;
-        zip_bl_count = null;
-        zip_heap = null;
-        zip_depth = null;
-        zip_length_code = null;
-        zip_dist_code = null;
-        zip_base_length = null;
-        zip_base_dist = null;
-        zip_flag_buf = null;
-    };
-
-    var zip_reuse_queue = function (p) {
-        p.next = zip_free_queue;
-        zip_free_queue = p;
-    };
-
-    var zip_new_queue = function () {
-        var p;
-
-        if (zip_free_queue != null) {
-            p = zip_free_queue;
-            zip_free_queue = zip_free_queue.next;
-        }
-        else
-            p = new zip_DeflateBuffer();
-        p.next = null;
-        p.len = p.off = 0;
-
-        return p;
-    };
-
-    var zip_head1 = function (i) {
-        return zip_prev[WSIZE + i];
-    };
-
-    var zip_head2 = function (i, val) {
-        return zip_prev[WSIZE + i] = val;
-    };
-
-    /* put_byte is used for the compressed output, put_ubyte for the
-     * uncompressed output. However unlzw() uses window for its
-     * suffix table instead of its output buffer, so it does not use put_ubyte
-     * (to be cleaned up).
-     */
-    var zip_put_byte = function (c) {
-        zip_outbuf[zip_outoff + zip_outcnt++] = c;
-        if (zip_outoff + zip_outcnt == zip_OUTBUFSIZ)
-            zip_qoutbuf();
-    };
-
-    /* Output a 16 bit value, lsb first */
-    var zip_put_short = function (w) {
-        w &= 0xffff;
-        if (zip_outoff + zip_outcnt < zip_OUTBUFSIZ - 2) {
-            zip_outbuf[zip_outoff + zip_outcnt++] = (w & 0xff);
-            zip_outbuf[zip_outoff + zip_outcnt++] = (w >>> 8);
-        } else {
-            zip_put_byte(w & 0xff);
-            zip_put_byte(w >>> 8);
-        }
-    };
-
-    /* ==========================================================================
-     * Insert string s in the dictionary and set match_head to the previous head
-     * of the hash chain (the most recent string with same hash key). Return
-     * the previous length of the hash chain.
-     * IN  assertion: all calls to to INSERT_STRING are made with consecutive
-     *    input characters and the first MIN_MATCH bytes of s are valid
-     *    (except for the last MIN_MATCH-1 bytes of the input file).
-     */
-    var zip_INSERT_STRING = function () {
-        zip_ins_h = ((zip_ins_h << zip_H_SHIFT)
-            ^ (zip_window[zip_strstart + MIN_MATCH - 1] & 0xff))
-            & zip_HASH_MASK;
-        zip_hash_head = zip_head1(zip_ins_h);
-        zip_prev[zip_strstart & zip_WMASK] = zip_hash_head;
-        zip_head2(zip_ins_h, zip_strstart);
-    };
-
-    /* Send a code of the given tree. c and tree must not have side effects */
-    var zip_SEND_CODE = function (c, tree) {
-        zip_send_bits(tree[c].fc, tree[c].dl);
-    };
-
-    /* Mapping from a distance to a distance code. dist is the distance - 1 and
-     * must not have side effects. dist_code[256] and dist_code[257] are never
-     * used.
-     */
-    var zip_D_CODE = function (dist) {
-        return (dist < 256 ? zip_dist_code[dist]
-            : zip_dist_code[256 + (dist >> 7)]) & 0xff;
-    };
-
-    /* ==========================================================================
-     * Compares to subtrees, using the tree depth as tie breaker when
-     * the subtrees have equal frequency. This minimizes the worst case length.
-     */
-    var zip_SMALLER = function (tree, n, m) {
-        return tree[n].fc < tree[m].fc ||
-            (tree[n].fc == tree[m].fc && zip_depth[n] <= zip_depth[m]);
-    };
-
-    /* ==========================================================================
-     * read string data
-     */
-    var zip_read_buff = function (buff, offset, n) {
-        var i;
-        for (i = 0; i < n && zip_deflate_pos < zip_deflate_data.length; i++)
-            buff[offset + i] =
-                zip_deflate_data[zip_deflate_pos++] & 0xff;
-        return i;
-    };
-
-    /* ==========================================================================
-     * Initialize the "longest match" routines for a new file
-     */
-    var zip_lm_init = function () {
-        var j;
-
-        /* Initialize the hash table. */
-        for (j = 0; j < zip_HASH_SIZE; j++)
-            zip_prev[WSIZE + j] = 0;
-        zip_max_lazy_match = zip_configuration_table[zip_compr_level].max_lazy;
-        zip_good_match = zip_configuration_table[zip_compr_level].good_length;
-        if (!zip_FULL_SEARCH)
-            zip_nice_match = zip_configuration_table[zip_compr_level].nice_length;
-        zip_max_chain_length = zip_configuration_table[zip_compr_level].max_chain;
-
-        zip_strstart = 0;
-        zip_block_start = 0;
-
-        zip_lookahead = zip_read_buff(zip_window, 0, 2 * WSIZE);
-        if (zip_lookahead <= 0) {
-            zip_eofile = true;
-            zip_lookahead = 0;
-            return;
-        }
-        zip_eofile = false;
-        /* Make sure that we always have enough lookahead. This is important
-         * if input comes from a device such as a tty.
-         */
-        while (zip_lookahead < zip_MIN_LOOKAHEAD && !zip_eofile)
-            zip_fill_window();
-
-        /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
-         * not important since only literal bytes will be emitted.
-         */
-        zip_ins_h = 0;
-        for (j = 0; j < MIN_MATCH - 1; j++) {
-            zip_ins_h = ((zip_ins_h << zip_H_SHIFT) ^ (zip_window[j] & 0xff)) & zip_HASH_MASK;
-        }
-    };
-
-    /* ==========================================================================
-     * Set match_start to the longest match starting at the given string and
-     * return its length. Matches shorter or equal to prev_length are discarded,
-     * in which case the result is equal to prev_length and match_start is
-     * garbage.
-     * IN assertions: cur_match is the head of the hash chain for the current
-     *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
-     */
-    var zip_longest_match = function (cur_match) {
-        var chain_length = zip_max_chain_length; // max hash chain length
-        var scanp = zip_strstart; // current string
-        var matchp;		// matched string
-        var len;		// length of current match
-        var best_len = zip_prev_length;	// best match length so far
-
-        /* Stop when cur_match becomes <= limit. To simplify the code,
-         * we prevent matches with the string of window index 0.
-         */
-        var limit = (zip_strstart > zip_MAX_DIST ? zip_strstart - zip_MAX_DIST : zip_NIL);
-
-        var strendp = zip_strstart + MAX_MATCH;
-        var scan_end1 = zip_window[scanp + best_len - 1];
-        var scan_end = zip_window[scanp + best_len];
-
-        /* Do not waste too much time if we already have a good match: */
-        if (zip_prev_length >= zip_good_match)
-            chain_length >>= 2;
-
-        do {
-            matchp = cur_match;
-
-            /* Skip to next match if the match length cannot increase
-             * or if the match length is less than 2:
-             */
-            if (zip_window[matchp + best_len] != scan_end ||
-                zip_window[matchp + best_len - 1] != scan_end1 ||
-                zip_window[matchp] != zip_window[scanp] ||
-                zip_window[++matchp] != zip_window[scanp + 1]) {
-                continue;
-            }
-
-            /* The check at best_len-1 can be removed because it will be made
-             * again later. (This heuristic is not always a win.)
-             * It is not necessary to compare scan[2] and match[2] since they
-             * are always equal when the other bytes match, given that
-             * the hash keys are equal and that HASH_BITS >= 8.
-             */
-            scanp += 2;
-            matchp++;
-
-            /* We check for insufficient lookahead only every 8th comparison;
-             * the 256th check will be made at strstart+258.
-             */
-            do {
-            } while (zip_window[++scanp] == zip_window[++matchp] &&
-                zip_window[++scanp] == zip_window[++matchp] &&
-                zip_window[++scanp] == zip_window[++matchp] &&
-                zip_window[++scanp] == zip_window[++matchp] &&
-                zip_window[++scanp] == zip_window[++matchp] &&
-                zip_window[++scanp] == zip_window[++matchp] &&
-                zip_window[++scanp] == zip_window[++matchp] &&
-                zip_window[++scanp] == zip_window[++matchp] &&
-                scanp < strendp);
-
-            len = MAX_MATCH - (strendp - scanp);
-            scanp = strendp - MAX_MATCH;
-
-            if (len > best_len) {
-                zip_match_start = cur_match;
-                best_len = len;
-                if (zip_FULL_SEARCH) {
-                    if (len >= MAX_MATCH) break;
-                } else {
-                    if (len >= zip_nice_match) break;
-                }
-
-                scan_end1 = zip_window[scanp + best_len - 1];
-                scan_end = zip_window[scanp + best_len];
-            }
-        } while ((cur_match = zip_prev[cur_match & zip_WMASK]) > limit
-            && --chain_length != 0);
-
-        return best_len;
-    };
-
-    /* ==========================================================================
-     * Fill the window when the lookahead becomes insufficient.
-     * Updates strstart and lookahead, and sets eofile if end of input file.
-     * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
-     * OUT assertions: at least one byte has been read, or eofile is set;
-     *    file reads are performed for at least two bytes (required for the
-     *    translate_eol option).
-     */
-    var zip_fill_window = function () {
-        var n, m;
-
-        // Amount of free space at the end of the window.
-        var more = zip_window_size - zip_lookahead - zip_strstart;
-
-        /* If the window is almost full and there is insufficient lookahead,
-         * move the upper half to the lower one to make room in the upper half.
-         */
-        if (more == -1) {
-            /* Very unlikely, but possible on 16 bit machine if strstart == 0
-             * and lookahead == 1 (input done one byte at time)
-             */
-            more--;
-        } else if (zip_strstart >= WSIZE + zip_MAX_DIST) {
-            /* By the IN assertion, the window is not empty so we can't confuse
-             * more == 0 with more == 64K on a 16 bit machine.
-             */
-            for (n = 0; n < WSIZE; n++)
-                zip_window[n] = zip_window[n + WSIZE];
-
-            zip_match_start -= WSIZE;
-            zip_strstart -= WSIZE;
-            /* we now have strstart >= MAX_DIST: */
-            zip_block_start -= WSIZE;
-
-            for (n = 0; n < zip_HASH_SIZE; n++) {
-                m = zip_head1(n);
-                zip_head2(n, m >= WSIZE ? m - WSIZE : zip_NIL);
-            }
-            for (n = 0; n < WSIZE; n++) {
-                /* If n is not on any hash chain, prev[n] is garbage but
-                 * its value will never be used.
-                 */
-                m = zip_prev[n];
-                zip_prev[n] = (m >= WSIZE ? m - WSIZE : zip_NIL);
-            }
-            more += WSIZE;
-        }
-        // At this point, more >= 2
-        if (!zip_eofile) {
-            n = zip_read_buff(zip_window, zip_strstart + zip_lookahead, more);
-            if (n <= 0)
-                zip_eofile = true;
-            else
-                zip_lookahead += n;
-        }
-    };
-
-    /* ==========================================================================
-     * Processes a new input file and return its compressed length. This
-     * function does not perform lazy evaluationof matches and inserts
-     * new strings in the dictionary only for unmatched strings or for short
-     * matches. It is used only for the fast compression options.
-     */
-    var zip_deflate_fast = function () {
-        while (zip_lookahead != 0 && zip_qhead == null) {
-            var flush; // set if current block must be flushed
-
-            /* Insert the string window[strstart .. strstart+2] in the
-             * dictionary, and set hash_head to the head of the hash chain:
-             */
-            zip_INSERT_STRING();
-
-            /* Find the longest match, discarding those <= prev_length.
-             * At this point we have always match_length < MIN_MATCH
-             */
-            if (zip_hash_head != zip_NIL &&
-                zip_strstart - zip_hash_head <= zip_MAX_DIST) {
-                /* To simplify the code, we prevent matches with the string
-                 * of window index 0 (in particular we have to avoid a match
-                 * of the string with itself at the start of the input file).
-                 */
-                zip_match_length = zip_longest_match(zip_hash_head);
-                /* longest_match() sets match_start */
-                if (zip_match_length > zip_lookahead)
-                    zip_match_length = zip_lookahead;
-            }
-            if (zip_match_length >= MIN_MATCH) {
-                flush = zip_ct_tally(zip_strstart - zip_match_start,
-                    zip_match_length - MIN_MATCH);
-                zip_lookahead -= zip_match_length;
-
-                /* Insert new strings in the hash table only if the match length
-                 * is not too large. This saves time but degrades compression.
-                 */
-                if (zip_match_length <= zip_max_lazy_match) {
-                    zip_match_length--; // string at strstart already in hash table
-                    do {
-                        zip_strstart++;
-                        zip_INSERT_STRING();
-                        /* strstart never exceeds WSIZE-MAX_MATCH, so there are
-                         * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
-                         * these bytes are garbage, but it does not matter since
-                         * the next lookahead bytes will be emitted as literals.
-                         */
-                    } while (--zip_match_length != 0);
-                    zip_strstart++;
-                } else {
-                    zip_strstart += zip_match_length;
-                    zip_match_length = 0;
-                    zip_ins_h = zip_window[zip_strstart] & 0xff;
-                    zip_ins_h = ((zip_ins_h << zip_H_SHIFT) ^ (zip_window[zip_strstart + 1] & 0xff)) & zip_HASH_MASK;
-                }
-            } else {
-                /* No match, output a literal byte */
-                flush = zip_ct_tally(0, zip_window[zip_strstart] & 0xff);
-                zip_lookahead--;
-                zip_strstart++;
-            }
-            if (flush) {
-                zip_flush_block(0);
-                zip_block_start = zip_strstart;
-            }
-
-            /* Make sure that we always have enough lookahead, except
-             * at the end of the input file. We need MAX_MATCH bytes
-             * for the next match, plus MIN_MATCH bytes to insert the
-             * string following the next match.
-             */
-            while (zip_lookahead < zip_MIN_LOOKAHEAD && !zip_eofile)
-                zip_fill_window();
-        }
-    };
-
-    var zip_deflate_better = function () {
-        /* Process the input block. */
-        while (zip_lookahead != 0 && zip_qhead == null) {
-            /* Insert the string window[strstart .. strstart+2] in the
-             * dictionary, and set hash_head to the head of the hash chain:
-             */
-            zip_INSERT_STRING();
-
-            /* Find the longest match, discarding those <= prev_length.
-             */
-            zip_prev_length = zip_match_length;
-            zip_prev_match = zip_match_start;
-            zip_match_length = MIN_MATCH - 1;
-
-            if (zip_hash_head != zip_NIL &&
-                zip_prev_length < zip_max_lazy_match &&
-                zip_strstart - zip_hash_head <= zip_MAX_DIST) {
-                /* To simplify the code, we prevent matches with the string
-                 * of window index 0 (in particular we have to avoid a match
-                 * of the string with itself at the start of the input file).
-                 */
-                zip_match_length = zip_longest_match(zip_hash_head);
-                /* longest_match() sets match_start */
-                if (zip_match_length > zip_lookahead)
-                    zip_match_length = zip_lookahead;
-
-                /* Ignore a length 3 match if it is too distant: */
-                if (zip_match_length == MIN_MATCH &&
-                    zip_strstart - zip_match_start > zip_TOO_FAR) {
-                    /* If prev_match is also MIN_MATCH, match_start is garbage
-                     * but we will ignore the current match anyway.
-                     */
-                    zip_match_length--;
-                }
-            }
-            /* If there was a match at the previous step and the current
-             * match is not better, output the previous match:
-             */
-            if (zip_prev_length >= MIN_MATCH &&
-                zip_match_length <= zip_prev_length) {
-                var flush; // set if current block must be flushed
-                flush = zip_ct_tally(zip_strstart - 1 - zip_prev_match,
-                    zip_prev_length - MIN_MATCH);
-
-                /* Insert in hash table all strings up to the end of the match.
-                 * strstart-1 and strstart are already inserted.
-                 */
-                zip_lookahead -= zip_prev_length - 1;
-                zip_prev_length -= 2;
-                do {
-                    zip_strstart++;
-                    zip_INSERT_STRING();
-                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
-                     * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
-                     * these bytes are garbage, but it does not matter since the
-                     * next lookahead bytes will always be emitted as literals.
-                     */
-                } while (--zip_prev_length != 0);
-                zip_match_available = 0;
-                zip_match_length = MIN_MATCH - 1;
-                zip_strstart++;
-                if (flush) {
-                    zip_flush_block(0);
-                    zip_block_start = zip_strstart;
-                }
-            } else if (zip_match_available != 0) {
-                /* If there was no match at the previous position, output a
-                 * single literal. If there was a match but the current match
-                 * is longer, truncate the previous match to a single literal.
-                 */
-                if (zip_ct_tally(0, zip_window[zip_strstart - 1] & 0xff)) {
-                    zip_flush_block(0);
-                    zip_block_start = zip_strstart;
-                }
-                zip_strstart++;
-                zip_lookahead--;
-            } else {
-                /* There is no previous match to compare with, wait for
-                 * the next step to decide.
-                 */
-                zip_match_available = 1;
-                zip_strstart++;
-                zip_lookahead--;
-            }
-
-            /* Make sure that we always have enough lookahead, except
-             * at the end of the input file. We need MAX_MATCH bytes
-             * for the next match, plus MIN_MATCH bytes to insert the
-             * string following the next match.
-             */
-            while (zip_lookahead < zip_MIN_LOOKAHEAD && !zip_eofile)
-                zip_fill_window();
-        }
-    };
-
-    var zip_init_deflate = function () {
-        if (zip_eofile)
-            return;
-        zip_bi_buf = 0;
-        zip_bi_valid = 0;
-        zip_ct_init();
-        zip_lm_init();
-
-        zip_qhead = null;
-        zip_outcnt = 0;
-        zip_outoff = 0;
-        zip_match_available = 0;
-
-        if (zip_compr_level <= 3) {
-            zip_prev_length = MIN_MATCH - 1;
-            zip_match_length = 0;
-        }
-        else {
-            zip_match_length = MIN_MATCH - 1;
-            zip_match_available = 0;
-            zip_match_available = 0;
-        }
-
-        zip_complete = false;
-    };
-
-    /* ==========================================================================
-     * Same as above, but achieves better compression. We use a lazy
-     * evaluation for matches: a match is finally adopted only if there is
-     * no better match at the next window position.
-     */
-    var zip_deflate_internal = function (buff, off, buff_size) {
-        var n;
-
-        if (!zip_initflag) {
-            zip_init_deflate();
-            zip_initflag = true;
-            if (zip_lookahead == 0) { // empty
-                zip_complete = true;
-                return 0;
-            }
-        }
-
-        if ((n = zip_qcopy(buff, off, buff_size)) == buff_size)
-            return buff_size;
-
-        if (zip_complete)
-            return n;
-
-        if (zip_compr_level <= 3) // optimized for speed
-            zip_deflate_fast();
-        else
-            zip_deflate_better();
-        if (zip_lookahead == 0) {
-            if (zip_match_available != 0)
-                zip_ct_tally(0, zip_window[zip_strstart - 1] & 0xff);
-            zip_flush_block(1);
-            zip_complete = true;
-        }
-        return n + zip_qcopy(buff, n + off, buff_size - n);
-    };
-
-    var zip_qcopy = function (buff, off, buff_size) {
-        var n, i, j;
-
-        n = 0;
-        while (zip_qhead != null && n < buff_size) {
-            i = buff_size - n;
-            if (i > zip_qhead.len)
-                i = zip_qhead.len;
-            for (j = 0; j < i; j++)
-                buff[off + n + j] = zip_qhead.ptr[zip_qhead.off + j];
-
-            zip_qhead.off += i;
-            zip_qhead.len -= i;
-            n += i;
-            if (zip_qhead.len == 0) {
-                var p;
-                p = zip_qhead;
-                zip_qhead = zip_qhead.next;
-                zip_reuse_queue(p);
-            }
-        }
-
-        if (n == buff_size)
-            return n;
-
-        if (zip_outoff < zip_outcnt) {
-            i = buff_size - n;
-            if (i > zip_outcnt - zip_outoff)
-                i = zip_outcnt - zip_outoff;
-            // System.arraycopy(outbuf, outoff, buff, off + n, i);
-            for (j = 0; j < i; j++)
-                buff[off + n + j] = zip_outbuf[zip_outoff + j];
-            zip_outoff += i;
-            n += i;
-            if (zip_outcnt == zip_outoff)
-                zip_outcnt = zip_outoff = 0;
-        }
-        return n;
-    };
-
-    /* ==========================================================================
-     * Allocate the match buffer, initialize the various tables and save the
-     * location of the internal file attribute (ascii/binary) and method
-     * (DEFLATE/STORE).
-     */
-    var zip_ct_init = function () {
-        var n;	// iterates over tree elements
-        var bits;	// bit counter
-        var length;	// length value
-        var code;	// code value
-        var dist;	// distance index
-
-        if (zip_static_dtree[0].dl != 0) return; // ct_init already called
-
-        zip_l_desc.dyn_tree = zip_dyn_ltree;
-        zip_l_desc.static_tree = zip_static_ltree;
-        zip_l_desc.extra_bits = zip_extra_lbits;
-        zip_l_desc.extra_base = zip_LITERALS + 1;
-        zip_l_desc.elems = zip_L_CODES;
-        zip_l_desc.max_length = zip_MAX_BITS;
-        zip_l_desc.max_code = 0;
-
-        zip_d_desc.dyn_tree = zip_dyn_dtree;
-        zip_d_desc.static_tree = zip_static_dtree;
-        zip_d_desc.extra_bits = zip_extra_dbits;
-        zip_d_desc.extra_base = 0;
-        zip_d_desc.elems = zip_D_CODES;
-        zip_d_desc.max_length = zip_MAX_BITS;
-        zip_d_desc.max_code = 0;
-
-        zip_bl_desc.dyn_tree = zip_bl_tree;
-        zip_bl_desc.static_tree = null;
-        zip_bl_desc.extra_bits = zip_extra_blbits;
-        zip_bl_desc.extra_base = 0;
-        zip_bl_desc.elems = zip_BL_CODES;
-        zip_bl_desc.max_length = zip_MAX_BL_BITS;
-        zip_bl_desc.max_code = 0;
-
-        // Initialize the mapping length (0..255) -> length code (0..28)
-        length = 0;
-        for (code = 0; code < zip_LENGTH_CODES - 1; code++) {
-            zip_base_length[code] = length;
-            for (n = 0; n < (1 << zip_extra_lbits[code]); n++)
-                zip_length_code[length++] = code;
-        }
-        /* Note that the length 255 (match length 258) can be represented
-         * in two different ways: code 284 + 5 bits or code 285, so we
-         * overwrite length_code[255] to use the best encoding:
-         */
-        zip_length_code[length - 1] = code;
-
-        /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
-        dist = 0;
-        for (code = 0; code < 16; code++) {
-            zip_base_dist[code] = dist;
-            for (n = 0; n < (1 << zip_extra_dbits[code]); n++) {
-                zip_dist_code[dist++] = code;
-            }
-        }
-        dist >>= 7; // from now on, all distances are divided by 128
-        for (; code < zip_D_CODES; code++) {
-            zip_base_dist[code] = dist << 7;
-            for (n = 0; n < (1 << (zip_extra_dbits[code] - 7)); n++)
-                zip_dist_code[256 + dist++] = code;
-        }
-        // Construct the codes of the static literal tree
-        for (bits = 0; bits <= zip_MAX_BITS; bits++)
-            zip_bl_count[bits] = 0;
-        n = 0;
-        while (n <= 143) {
-            zip_static_ltree[n++].dl = 8;
-            zip_bl_count[8]++;
-        }
-        while (n <= 255) {
-            zip_static_ltree[n++].dl = 9;
-            zip_bl_count[9]++;
-        }
-        while (n <= 279) {
-            zip_static_ltree[n++].dl = 7;
-            zip_bl_count[7]++;
-        }
-        while (n <= 287) {
-            zip_static_ltree[n++].dl = 8;
-            zip_bl_count[8]++;
-        }
-        /* Codes 286 and 287 do not exist, but we must include them in the
-         * tree construction to get a canonical Huffman tree (longest code
-         * all ones)
-         */
-        zip_gen_codes(zip_static_ltree, zip_L_CODES + 1);
-
-        /* The static distance tree is trivial: */
-        for (n = 0; n < zip_D_CODES; n++) {
-            zip_static_dtree[n].dl = 5;
-            zip_static_dtree[n].fc = zip_bi_reverse(n, 5);
-        }
-
-        // Initialize the first block of the first file:
-        zip_init_block();
-    };
-
-    /* ==========================================================================
-     * Initialize a new block.
-     */
-    var zip_init_block = function () {
-        var n; // iterates over tree elements
-
-        // Initialize the trees.
-        for (n = 0; n < zip_L_CODES; n++) zip_dyn_ltree[n].fc = 0;
-        for (n = 0; n < zip_D_CODES; n++) zip_dyn_dtree[n].fc = 0;
-        for (n = 0; n < zip_BL_CODES; n++) zip_bl_tree[n].fc = 0;
-
-        zip_dyn_ltree[zip_END_BLOCK].fc = 1;
-        zip_opt_len = zip_static_len = 0;
-        zip_last_lit = zip_last_dist = zip_last_flags = 0;
-        zip_flags = 0;
-        zip_flag_bit = 1;
-    };
-
-    /* ==========================================================================
-     * Restore the heap property by moving down the tree starting at node k,
-     * exchanging a node with the smallest of its two sons if necessary, stopping
-     * when the heap property is re-established (each father smaller than its
-     * two sons).
-     */
-    var zip_pqdownheap = function (tree,	// the tree to restore
-                                   k) {	// node to move down
-        var v = zip_heap[k];
-        var j = k << 1;	// left son of k
-
-        while (j <= zip_heap_len) {
-            // Set j to the smallest of the two sons:
-            if (j < zip_heap_len &&
-                zip_SMALLER(tree, zip_heap[j + 1], zip_heap[j]))
-                j++;
-
-            // Exit if v is smaller than both sons
-            if (zip_SMALLER(tree, v, zip_heap[j]))
-                break;
-
-            // Exchange v with the smallest son
-            zip_heap[k] = zip_heap[j];
-            k = j;
-
-            // And continue down the tree, setting j to the left son of k
-            j <<= 1;
-        }
-        zip_heap[k] = v;
-    };
-
-    /* ==========================================================================
-     * Compute the optimal bit lengths for a tree and update the total bit length
-     * for the current block.
-     * IN assertion: the fields freq and dad are set, heap[heap_max] and
-     *    above are the tree nodes sorted by increasing frequency.
-     * OUT assertions: the field len is set to the optimal bit length, the
-     *     array bl_count contains the frequencies for each bit length.
-     *     The length opt_len is updated; static_len is also updated if stree is
-     *     not null.
-     */
-    var zip_gen_bitlen = function (desc) { // the tree descriptor
-        var tree = desc.dyn_tree;
-        var extra = desc.extra_bits;
-        var base = desc.extra_base;
-        var max_code = desc.max_code;
-        var max_length = desc.max_length;
-        var stree = desc.static_tree;
-        var h;		// heap index
-        var n, m;		// iterate over the tree elements
-        var bits;		// bit length
-        var xbits;		// extra bits
-        var f;		// frequency
-        var overflow = 0;	// number of elements with bit length too large
-
-        for (bits = 0; bits <= zip_MAX_BITS; bits++)
-            zip_bl_count[bits] = 0;
-
-        /* In a first pass, compute the optimal bit lengths (which may
-         * overflow in the case of the bit length tree).
-         */
-        tree[zip_heap[zip_heap_max]].dl = 0; // root of the heap
-
-        for (h = zip_heap_max + 1; h < zip_HEAP_SIZE; h++) {
-            n = zip_heap[h];
-            bits = tree[tree[n].dl].dl + 1;
-            if (bits > max_length) {
-                bits = max_length;
-                overflow++;
-            }
-            tree[n].dl = bits;
-            // We overwrite tree[n].dl which is no longer needed
-
-            if (n > max_code)
-                continue; // not a leaf node
-
-            zip_bl_count[bits]++;
-            xbits = 0;
-            if (n >= base)
-                xbits = extra[n - base];
-            f = tree[n].fc;
-            zip_opt_len += f * (bits + xbits);
-            if (stree != null)
-                zip_static_len += f * (stree[n].dl + xbits);
-        }
-        if (overflow == 0)
-            return;
-
-        // This happens for example on obj2 and pic of the Calgary corpus
-
-        // Find the first bit length which could increase:
-        do {
-            bits = max_length - 1;
-            while (zip_bl_count[bits] == 0)
-                bits--;
-            zip_bl_count[bits]--;		// move one leaf down the tree
-            zip_bl_count[bits + 1] += 2;	// move one overflow item as its brother
-            zip_bl_count[max_length]--;
-            /* The brother of the overflow item also moves one step up,
-             * but this does not affect bl_count[max_length]
-             */
-            overflow -= 2;
-        } while (overflow > 0);
-
-        /* Now recompute all bit lengths, scanning in increasing frequency.
-         * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
-         * lengths instead of fixing only the wrong ones. This idea is taken
-         * from 'ar' written by Haruhiko Okumura.)
-         */
-        for (bits = max_length; bits != 0; bits--) {
-            n = zip_bl_count[bits];
-            while (n != 0) {
-                m = zip_heap[--h];
-                if (m > max_code)
-                    continue;
-                if (tree[m].dl != bits) {
-                    zip_opt_len += (bits - tree[m].dl) * tree[m].fc;
-                    tree[m].fc = bits;
-                }
-                n--;
-            }
-        }
-    };
-
-    /* ==========================================================================
-     * Generate the codes for a given tree and bit counts (which need not be
-     * optimal).
-     * IN assertion: the array bl_count contains the bit length statistics for
-     * the given tree and the field len is set for all tree elements.
-     * OUT assertion: the field code is set for all tree elements of non
-     *     zero code length.
-     */
-    var zip_gen_codes = function (tree,	// the tree to decorate
-                                  max_code) {	// largest code with non zero frequency
-        var next_code = new Array(zip_MAX_BITS + 1); // next code value for each bit length
-        var code = 0;		// running code value
-        var bits;			// bit index
-        var n;			// code index
-
-        /* The distribution counts are first used to generate the code values
-         * without bit reversal.
-         */
-        for (bits = 1; bits <= zip_MAX_BITS; bits++) {
-            code = ((code + zip_bl_count[bits - 1]) << 1);
-            next_code[bits] = code;
-        }
-
-        /* Check that the bit counts in bl_count are consistent. The last code
-         * must be all ones.
-         */
-        for (n = 0; n <= max_code; n++) {
-            var len = tree[n].dl;
-            if (len == 0)
-                continue;
-            // Now reverse the bits
-            tree[n].fc = zip_bi_reverse(next_code[len]++, len);
-        }
-    };
-
-    /* ==========================================================================
-     * Construct one Huffman tree and assigns the code bit strings and lengths.
-     * Update the total bit length for the current block.
-     * IN assertion: the field freq is set for all tree elements.
-     * OUT assertions: the fields len and code are set to the optimal bit length
-     *     and corresponding code. The length opt_len is updated; static_len is
-     *     also updated if stree is not null. The field max_code is set.
-     */
-    var zip_build_tree = function (desc) { // the tree descriptor
-        var tree = desc.dyn_tree;
-        var stree = desc.static_tree;
-        var elems = desc.elems;
-        var n, m;		// iterate over heap elements
-        var max_code = -1;	// largest code with non zero frequency
-        var node = elems;	// next internal node of the tree
-
-        /* Construct the initial heap, with least frequent element in
-         * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
-         * heap[0] is not used.
-         */
-        zip_heap_len = 0;
-        zip_heap_max = zip_HEAP_SIZE;
-
-        for (n = 0; n < elems; n++) {
-            if (tree[n].fc != 0) {
-                zip_heap[++zip_heap_len] = max_code = n;
-                zip_depth[n] = 0;
-            } else
-                tree[n].dl = 0;
-        }
-
-        /* The pkzip format requires that at least one distance code exists,
-         * and that at least one bit should be sent even if there is only one
-         * possible code. So to avoid special checks later on we force at least
-         * two codes of non zero frequency.
-         */
-        while (zip_heap_len < 2) {
-            var xnew = zip_heap[++zip_heap_len] = (max_code < 2 ? ++max_code : 0);
-            tree[xnew].fc = 1;
-            zip_depth[xnew] = 0;
-            zip_opt_len--;
-            if (stree != null)
-                zip_static_len -= stree[xnew].dl;
-            // new is 0 or 1 so it does not have extra bits
-        }
-        desc.max_code = max_code;
-
-        /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
-         * establish sub-heaps of increasing lengths:
-         */
-        for (n = zip_heap_len >> 1; n >= 1; n--)
-            zip_pqdownheap(tree, n);
-
-        /* Construct the Huffman tree by repeatedly combining the least two
-         * frequent nodes.
-         */
-        do {
-            n = zip_heap[zip_SMALLEST];
-            zip_heap[zip_SMALLEST] = zip_heap[zip_heap_len--];
-            zip_pqdownheap(tree, zip_SMALLEST);
-
-            m = zip_heap[zip_SMALLEST];  // m = node of next least frequency
-
-            // keep the nodes sorted by frequency
-            zip_heap[--zip_heap_max] = n;
-            zip_heap[--zip_heap_max] = m;
-
-            // Create a new node father of n and m
-            tree[node].fc = tree[n].fc + tree[m].fc;
-            if (zip_depth[n] > zip_depth[m] + 1)
-                zip_depth[node] = zip_depth[n];
-            else
-                zip_depth[node] = zip_depth[m] + 1;
-            tree[n].dl = tree[m].dl = node;
-
-            // and insert the new node in the heap
-            zip_heap[zip_SMALLEST] = node++;
-            zip_pqdownheap(tree, zip_SMALLEST);
-
-        } while (zip_heap_len >= 2);
-
-        zip_heap[--zip_heap_max] = zip_heap[zip_SMALLEST];
-
-        /* At this point, the fields freq and dad are set. We can now
-         * generate the bit lengths.
-         */
-        zip_gen_bitlen(desc);
-
-        // The field len is now set, we can generate the bit codes
-        zip_gen_codes(tree, max_code);
-    };
-
-    /* ==========================================================================
-     * Scan a literal or distance tree to determine the frequencies of the codes
-     * in the bit length tree. Updates opt_len to take into account the repeat
-     * counts. (The contribution of the bit length codes will be added later
-     * during the construction of bl_tree.)
-     */
-    var zip_scan_tree = function (tree,// the tree to be scanned
-                                  max_code) {  // and its largest code of non zero frequency
-        var n;			// iterates over all tree elements
-        var prevlen = -1;		// last emitted length
-        var curlen;			// length of current code
-        var nextlen = tree[0].dl;	// length of next code
-        var count = 0;		// repeat count of the current code
-        var max_count = 7;		// max repeat count
-        var min_count = 4;		// min repeat count
-
-        if (nextlen == 0) {
-            max_count = 138;
-            min_count = 3;
-        }
-        tree[max_code + 1].dl = 0xffff; // guard
-
-        for (n = 0; n <= max_code; n++) {
-            curlen = nextlen;
-            nextlen = tree[n + 1].dl;
-            if (++count < max_count && curlen == nextlen)
-                continue;
-            else if (count < min_count)
-                zip_bl_tree[curlen].fc += count;
-            else if (curlen != 0) {
-                if (curlen != prevlen)
-                    zip_bl_tree[curlen].fc++;
-                zip_bl_tree[zip_REP_3_6].fc++;
-            } else if (count <= 10)
-                zip_bl_tree[zip_REPZ_3_10].fc++;
-            else
-                zip_bl_tree[zip_REPZ_11_138].fc++;
-            count = 0;
-            prevlen = curlen;
-            if (nextlen == 0) {
-                max_count = 138;
-                min_count = 3;
-            } else if (curlen == nextlen) {
-                max_count = 6;
-                min_count = 3;
-            } else {
-                max_count = 7;
-                min_count = 4;
-            }
-        }
-    };
-
-    /* ==========================================================================
-     * Send a literal or distance tree in compressed form, using the codes in
-     * bl_tree.
-     */
-    var zip_send_tree = function (tree, // the tree to be scanned
-                                  max_code) { // and its largest code of non zero frequency
-        var n;			// iterates over all tree elements
-        var prevlen = -1;		// last emitted length
-        var curlen;			// length of current code
-        var nextlen = tree[0].dl;	// length of next code
-        var count = 0;		// repeat count of the current code
-        var max_count = 7;		// max repeat count
-        var min_count = 4;		// min repeat count
-
-        /* tree[max_code+1].dl = -1; */
-        /* guard already set */
-        if (nextlen == 0) {
-            max_count = 138;
-            min_count = 3;
-        }
-
-        for (n = 0; n <= max_code; n++) {
-            curlen = nextlen;
-            nextlen = tree[n + 1].dl;
-            if (++count < max_count && curlen == nextlen) {
-                continue;
-            } else if (count < min_count) {
-                do {
-                    zip_SEND_CODE(curlen, zip_bl_tree);
-                } while (--count != 0);
-            } else if (curlen != 0) {
-                if (curlen != prevlen) {
-                    zip_SEND_CODE(curlen, zip_bl_tree);
-                    count--;
-                }
-                // Assert(count >= 3 && count <= 6, " 3_6?");
-                zip_SEND_CODE(zip_REP_3_6, zip_bl_tree);
-                zip_send_bits(count - 3, 2);
-            } else if (count <= 10) {
-                zip_SEND_CODE(zip_REPZ_3_10, zip_bl_tree);
-                zip_send_bits(count - 3, 3);
-            } else {
-                zip_SEND_CODE(zip_REPZ_11_138, zip_bl_tree);
-                zip_send_bits(count - 11, 7);
-            }
-            count = 0;
-            prevlen = curlen;
-            if (nextlen == 0) {
-                max_count = 138;
-                min_count = 3;
-            } else if (curlen == nextlen) {
-                max_count = 6;
-                min_count = 3;
-            } else {
-                max_count = 7;
-                min_count = 4;
-            }
-        }
-    };
-
-    /* ==========================================================================
-     * Construct the Huffman tree for the bit lengths and return the index in
-     * bl_order of the last bit length code to send.
-     */
-    var zip_build_bl_tree = function () {
-        var max_blindex;  // index of last bit length code of non zero freq
-
-        // Determine the bit length frequencies for literal and distance trees
-        zip_scan_tree(zip_dyn_ltree, zip_l_desc.max_code);
-        zip_scan_tree(zip_dyn_dtree, zip_d_desc.max_code);
-
-        // Build the bit length tree:
-        zip_build_tree(zip_bl_desc);
-        /* opt_len now includes the length of the tree representations, except
-         * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
-         */
-
-        /* Determine the number of bit length codes to send. The pkzip format
-         * requires that at least 4 bit length codes be sent. (appnote.txt says
-         * 3 but the actual value used is 4.)
-         */
-        for (max_blindex = zip_BL_CODES - 1; max_blindex >= 3; max_blindex--) {
-            if (zip_bl_tree[zip_bl_order[max_blindex]].dl != 0) break;
-        }
-        /* Update opt_len to include the bit length tree and counts */
-        zip_opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
-        return max_blindex;
-    };
-
-    /* ==========================================================================
-     * Send the header for a block using dynamic Huffman trees: the counts, the
-     * lengths of the bit length codes, the literal tree and the distance tree.
-     * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
-     */
-    var zip_send_all_trees = function (lcodes, dcodes, blcodes) { // number of codes for each tree
-        var rank; // index in bl_order
-        zip_send_bits(lcodes - 257, 5); // not +255 as stated in appnote.txt
-        zip_send_bits(dcodes - 1, 5);
-        zip_send_bits(blcodes - 4, 4); // not -3 as stated in appnote.txt
-        for (rank = 0; rank < blcodes; rank++) {
-            zip_send_bits(zip_bl_tree[zip_bl_order[rank]].dl, 3);
-        }
-
-        // send the literal tree
-        zip_send_tree(zip_dyn_ltree, lcodes - 1);
-
-        // send the distance tree
-        zip_send_tree(zip_dyn_dtree, dcodes - 1);
-    };
-
-    /* ==========================================================================
-     * Determine the best encoding for the current block: dynamic trees, static
-     * trees or store, and output the encoded block to the zip file.
-     */
-    var zip_flush_block = function (eof) { // true if this is the last block for a file
-        var opt_lenb, static_lenb; // opt_len and static_len in bytes
-        var max_blindex;	// index of last bit length code of non zero freq
-        var stored_len;	// length of input block
-
-        stored_len = zip_strstart - zip_block_start;
-        zip_flag_buf[zip_last_flags] = zip_flags; // Save the flags for the last 8 items
-
-        // Construct the literal and distance trees
-        zip_build_tree(zip_l_desc);
-        zip_build_tree(zip_d_desc);
-        /* At this point, opt_len and static_len are the total bit lengths of
-         * the compressed block data, excluding the tree representations.
-         */
-
-        /* Build the bit length tree for the above two trees, and get the index
-         * in bl_order of the last bit length code to send.
-         */
-        max_blindex = zip_build_bl_tree();
-
-        // Determine the best encoding. Compute first the block length in bytes
-        opt_lenb = (zip_opt_len + 3 + 7) >> 3;
-        static_lenb = (zip_static_len + 3 + 7) >> 3;
-        if (static_lenb <= opt_lenb)
-            opt_lenb = static_lenb;
-        if (stored_len + 4 <= opt_lenb // 4: two words for the lengths
-            && zip_block_start >= 0) {
-            var i;
-
-            /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
-             * Otherwise we can't have processed more than WSIZE input bytes since
-             * the last block flush, because compression would have been
-             * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
-             * transform a block into a stored block.
-             */
-            zip_send_bits((zip_STORED_BLOCK << 1) + eof, 3);
-            /* send block type */
-            zip_bi_windup();
-            /* align on byte boundary */
-            zip_put_short(stored_len);
-            zip_put_short(~stored_len);
-
-            // copy block
-            for (i = 0; i < stored_len; i++)
-                zip_put_byte(zip_window[zip_block_start + i]);
-
-        } else if (static_lenb == opt_lenb) {
-            zip_send_bits((zip_STATIC_TREES << 1) + eof, 3);
-            zip_compress_block(zip_static_ltree, zip_static_dtree);
-        } else {
-            zip_send_bits((zip_DYN_TREES << 1) + eof, 3);
-            zip_send_all_trees(zip_l_desc.max_code + 1,
-                zip_d_desc.max_code + 1,
-                max_blindex + 1);
-            zip_compress_block(zip_dyn_ltree, zip_dyn_dtree);
-        }
-
-        zip_init_block();
-
-        if (eof != 0)
-            zip_bi_windup();
-    };
-
-    /* ==========================================================================
-     * Save the match info and tally the frequency counts. Return true if
-     * the current block must be flushed.
-     */
-    var zip_ct_tally = function (dist, // distance of matched string
-                                 lc) { // match length-MIN_MATCH or unmatched char (if dist==0)
-        zip_l_buf[zip_last_lit++] = lc;
-        if (dist == 0) {
-            // lc is the unmatched char
-            zip_dyn_ltree[lc].fc++;
-        } else {
-            // Here, lc is the match length - MIN_MATCH
-            dist--;		    // dist = match distance - 1
-            zip_dyn_ltree[zip_length_code[lc] + zip_LITERALS + 1].fc++;
-            zip_dyn_dtree[zip_D_CODE(dist)].fc++;
-
-            zip_d_buf[zip_last_dist++] = dist;
-            zip_flags |= zip_flag_bit;
-        }
-        zip_flag_bit <<= 1;
-
-        // Output the flags if they fill a byte
-        if ((zip_last_lit & 7) == 0) {
-            zip_flag_buf[zip_last_flags++] = zip_flags;
-            zip_flags = 0;
-            zip_flag_bit = 1;
-        }
-        // Try to guess if it is profitable to stop the current block here
-        if (zip_compr_level > 2 && (zip_last_lit & 0xfff) == 0) {
-            // Compute an upper bound for the compressed length
-            var out_length = zip_last_lit * 8;
-            var in_length = zip_strstart - zip_block_start;
-            var dcode;
-
-            for (dcode = 0; dcode < zip_D_CODES; dcode++) {
-                out_length += zip_dyn_dtree[dcode].fc * (5 + zip_extra_dbits[dcode]);
-            }
-            out_length >>= 3;
-            if (zip_last_dist < parseInt(zip_last_lit / 2) &&
-                out_length < parseInt(in_length / 2))
-                return true;
-        }
-        return (zip_last_lit == LIT_BUFSIZE - 1 ||
-            zip_last_dist == zip_DIST_BUFSIZE);
-        /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
-         * on 16 bit machines and because stored blocks are restricted to
-         * 64K-1 bytes.
-         */
-    };
-
-    /* ==========================================================================
-     * Send the block data compressed using the given Huffman trees
-     */
-    var zip_compress_block = function (ltree,	// literal tree
-                                       dtree) {	// distance tree
-        var dist;		// distance of matched string
-        var lc;		// match length or unmatched char (if dist == 0)
-        var lx = 0;		// running index in l_buf
-        var dx = 0;		// running index in d_buf
-        var fx = 0;		// running index in flag_buf
-        var flag = 0;	// current flags
-        var code;		// the code to send
-        var extra;		// number of extra bits to send
-
-        if (zip_last_lit != 0) do {
-            if ((lx & 7) == 0)
-                flag = zip_flag_buf[fx++];
-            lc = zip_l_buf[lx++] & 0xff;
-            if ((flag & 1) == 0) {
-                zip_SEND_CODE(lc, ltree);
-                /* send a literal byte */
-            } else {
-                // Here, lc is the match length - MIN_MATCH
-                code = zip_length_code[lc];
-                zip_SEND_CODE(code + zip_LITERALS + 1, ltree); // send the length code
-                extra = zip_extra_lbits[code];
-                if (extra != 0) {
-                    lc -= zip_base_length[code];
-                    zip_send_bits(lc, extra); // send the extra length bits
-                }
-                dist = zip_d_buf[dx++];
-                // Here, dist is the match distance - 1
-                code = zip_D_CODE(dist);
-                zip_SEND_CODE(code, dtree);	  // send the distance code
-                extra = zip_extra_dbits[code];
-                if (extra != 0) {
-                    dist -= zip_base_dist[code];
-                    zip_send_bits(dist, extra);   // send the extra distance bits
-                }
-            } // literal or match pair ?
-            flag >>= 1;
-        } while (lx < zip_last_lit);
-
-        zip_SEND_CODE(zip_END_BLOCK, ltree);
-    };
-
-    /* ==========================================================================
-     * Send a value on a given number of bits.
-     * IN assertion: length <= 16 and value fits in length bits.
-     */
-    var zip_Buf_size = 16; // bit size of bi_buf
-    var zip_send_bits = function (value,	// value to send
-                                  length) {	// number of bits
-        /* If not enough room in bi_buf, use (valid) bits from bi_buf and
-         * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
-         * unused bits in value.
-         */
-        if (zip_bi_valid > zip_Buf_size - length) {
-            zip_bi_buf |= (value << zip_bi_valid);
-            zip_put_short(zip_bi_buf);
-            zip_bi_buf = (value >> (zip_Buf_size - zip_bi_valid));
-            zip_bi_valid += length - zip_Buf_size;
-        } else {
-            zip_bi_buf |= value << zip_bi_valid;
-            zip_bi_valid += length;
-        }
-    };
-
-    /* ==========================================================================
-     * Reverse the first len bits of a code, using straightforward code (a faster
-     * method would use a table)
-     * IN assertion: 1 <= len <= 15
-     */
-    var zip_bi_reverse = function (code,	// the value to invert
-                                   len) {	// its bit length
-        var res = 0;
-        do {
-            res |= code & 1;
-            code >>= 1;
-            res <<= 1;
-        } while (--len > 0);
-        return res >> 1;
-    };
-
-    /* ==========================================================================
-     * Write out any remaining bits in an incomplete byte.
-     */
-    var zip_bi_windup = function () {
-        if (zip_bi_valid > 8) {
-            zip_put_short(zip_bi_buf);
-        } else if (zip_bi_valid > 0) {
-            zip_put_byte(zip_bi_buf);
-        }
-        zip_bi_buf = 0;
-        zip_bi_valid = 0;
-    };
-
-    var zip_qoutbuf = function () {
-        if (zip_outcnt != 0) {
-            var q, i;
-            q = zip_new_queue();
-            if (zip_qhead == null)
-                zip_qhead = zip_qtail = q;
-            else
-                zip_qtail = zip_qtail.next = q;
-            q.len = zip_outcnt - zip_outoff;
-            for (i = 0; i < q.len; i++)
-                q.ptr[i] = zip_outbuf[zip_outoff + i];
-            zip_outcnt = zip_outoff = 0;
-        }
-    };
-
-    function deflate(buffData, level) {
-        zip_deflate_data = buffData;
-        zip_deflate_pos = 0;
-        zip_deflate_start(level);
-
-        var buff = new Array(1024),
-            pages = [],
-            totalSize = 0,
-            i;
-
-        for (i = 0; i < 1024; i++) buff[i] = 0;
-        while ((i = zip_deflate_internal(buff, 0, buff.length)) > 0) {
-            var buf = new Buffer(buff.slice(0, i));
-            pages.push(buf);
-            totalSize += buf.length;
-        }
-
-        if (pages.length == 1) {
-            return pages[0];
-        }
-
-        var result = new Buffer(totalSize),
-            index = 0;
-
-        for (i = 0; i < pages.length; i++) {
-            pages[i].copy(result, index);
-            index = index + pages[i].length
-        }
-
-        return result;
-    }
-
-    return {
-        deflate: function () {
-            return deflate(inbuf, 8);
-        }
-    }
-}
-
-module.exports = function (/*Buffer*/inbuf) {
-
-    var zlib = require("zlib");
-
-    return {
-        deflate: function () {
-            return new JSDeflater(inbuf).deflate();
-        },
-
-        deflateAsync: function (/*Function*/callback) {
-            var tmp = zlib.createDeflateRaw({chunkSize:(parseInt(inbuf.length / 1024) + 1)*1024}),
-                parts = [], total = 0;
-            tmp.on('data', function(data) {
-                parts.push(data);
-                total += data.length;
-            });
-            tmp.on('end', function() {
-                var buf = new Buffer(total), written = 0;
-                buf.fill(0);
-
-                for (var i = 0; i < parts.length; i++) {
-                    var part = parts[i];
-                    part.copy(buf, written);
-                    written += part.length;
-                }
-                callback && callback(buf);
-            });
-            tmp.end(inbuf);
-        }
-    }
-};
diff --git a/node_modules/adm-zip/methods/index.js b/node_modules/adm-zip/methods/index.js
deleted file mode 100644
index 58c718d..0000000
--- a/node_modules/adm-zip/methods/index.js
+++ /dev/null
@@ -1,2 +0,0 @@
-exports.Deflater = require("./deflater");
-exports.Inflater = require("./inflater");
\ No newline at end of file
diff --git a/node_modules/adm-zip/methods/inflater.js b/node_modules/adm-zip/methods/inflater.js
deleted file mode 100644
index 3739d98..0000000
--- a/node_modules/adm-zip/methods/inflater.js
+++ /dev/null
@@ -1,448 +0,0 @@
-var Buffer = require("buffer").Buffer;
-
-function JSInflater(/*Buffer*/input) {
-
-    var WSIZE = 0x8000,
-        slide = new Buffer(0x10000),
-        windowPos = 0,
-        fixedTableList = null,
-        fixedTableDist,
-        fixedLookup,
-        bitBuf = 0,
-        bitLen = 0,
-        method = -1,
-        eof = false,
-        copyLen = 0,
-        copyDist = 0,
-        tblList, tblDist, bitList, bitdist,
-
-        inputPosition = 0,
-
-        MASK_BITS = [0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff],
-        LENS = [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0],
-        LEXT = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99],
-        DISTS = [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577],
-        DEXT = [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13],
-        BITORDER = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
-
-    function HuffTable(clen, cnum, cval, blist, elist, lookupm) {
-
-        this.status = 0;
-        this.root = null;
-        this.maxbit = 0;
-
-        var el, f, tail,
-            offsets = [],
-            countTbl = [],
-            sTbl = [],
-            values = [],
-            tentry = {extra: 0, bitcnt: 0, lbase: 0, next: null};
-
-        tail = this.root = null;
-        for(var i = 0; i < 0x11; i++)  { countTbl[i] = 0; sTbl[i] = 0; offsets[i] = 0; }
-        for(i = 0; i < 0x120; i++) values[i] = 0;
-
-        el = cnum > 256 ? clen[256] : 16;
-
-        var pidx = -1;
-        while (++pidx < cnum) countTbl[clen[pidx]]++;
-
-        if(countTbl[0] == cnum) return;
-
-        for(var j = 1; j <= 16; j++) if(countTbl[j] != 0) break;
-        var bitLen = j;
-        for(i = 16; i != 0; i--) if(countTbl[i] != 0) break;
-        var maxLen = i;
-
-        lookupm < j && (lookupm = j);
-
-        var dCodes = 1 << j;
-        for(; j < i; j++, dCodes <<= 1)
-            if((dCodes -= countTbl[j]) < 0) {
-                this.status = 2;
-                this.maxbit = lookupm;
-                return;
-            }
-
-        if((dCodes -= countTbl[i]) < 0) {
-            this.status = 2;
-            this.maxbit = lookupm;
-            return;
-        }
-
-        countTbl[i] += dCodes;
-        offsets[1] = j = 0;
-        pidx = 1;
-        var xp = 2;
-        while(--i > 0) offsets[xp++] = (j += countTbl[pidx++]);
-        pidx = 0;
-        i = 0;
-        do {
-            (j = clen[pidx++]) && (values[offsets[j]++] = i);
-        } while(++i < cnum);
-        cnum = offsets[maxLen];
-        offsets[0] = i = 0;
-        pidx = 0;
-
-        var level = -1,
-            w = sTbl[0] = 0,
-            cnode = null,
-            tblCnt = 0,
-            tblStack = [];
-
-        for(; bitLen <= maxLen; bitLen++) {
-            var kccnt = countTbl[bitLen];
-            while(kccnt-- > 0) {
-                while(bitLen > w + sTbl[1 + level]) {
-                    w += sTbl[1 + level];
-                    level++;
-                    tblCnt = (tblCnt = maxLen - w) > lookupm ? lookupm : tblCnt;
-                    if((f = 1 << (j = bitLen - w)) > kccnt + 1) {
-                        f -= kccnt + 1;
-                        xp = bitLen;
-                        while(++j < tblCnt) {
-                            if((f <<= 1) <= countTbl[++xp]) break;
-                            f -= countTbl[xp];
-                        }
-                    }
-                    if(w + j > el && w < el) j = el - w;
-                    tblCnt = 1 << j;
-                    sTbl[1 + level] = j;
-                    cnode = [];
-                    while (cnode.length < tblCnt) cnode.push({extra: 0, bitcnt: 0, lbase: 0, next: null});
-                    if (tail == null) {
-                        tail = this.root = {next:null, list:null};
-                    } else {
-                        tail = tail.next = {next:null, list:null}
-                    }
-                    tail.next = null;
-                    tail.list = cnode;
-
-                    tblStack[level] = cnode;
-
-                    if(level > 0) {
-                        offsets[level] = i;
-                        tentry.bitcnt = sTbl[level];
-                        tentry.extra = 16 + j;
-                        tentry.next = cnode;
-                        j = (i & ((1 << w) - 1)) >> (w - sTbl[level]);
-
-                        tblStack[level-1][j].extra = tentry.extra;
-                        tblStack[level-1][j].bitcnt = tentry.bitcnt;
-                        tblStack[level-1][j].lbase = tentry.lbase;
-                        tblStack[level-1][j].next = tentry.next;
-                    }
-                }
-                tentry.bitcnt = bitLen - w;
-                if(pidx >= cnum)
-                    tentry.extra = 99;
-                else if(values[pidx] < cval) {
-                    tentry.extra = (values[pidx] < 256 ? 16 : 15);
-                    tentry.lbase = values[pidx++];
-                } else {
-                    tentry.extra = elist[values[pidx] - cval];
-                    tentry.lbase = blist[values[pidx++] - cval];
-                }
-
-                f = 1 << (bitLen - w);
-                for(j = i >> w; j < tblCnt; j += f) {
-                    cnode[j].extra = tentry.extra;
-                    cnode[j].bitcnt = tentry.bitcnt;
-                    cnode[j].lbase = tentry.lbase;
-                    cnode[j].next = tentry.next;
-                }
-                for(j = 1 << (bitLen - 1); (i & j) != 0; j >>= 1)
-                    i ^= j;
-                i ^= j;
-                while((i & ((1 << w) - 1)) != offsets[level]) {
-                    w -= sTbl[level];
-                    level--;
-                }
-            }
-        }
-
-        this.maxbit = sTbl[1];
-        this.status = ((dCodes != 0 && maxLen != 1) ? 1 : 0);
-    }
-
-    function addBits(n) {
-        while(bitLen < n) {
-            bitBuf |= input[inputPosition++] << bitLen;
-            bitLen += 8;
-        }
-        return bitBuf;
-    }
-
-    function cutBits(n) {
-        bitLen -= n;
-        return bitBuf >>= n;
-    }
-
-    function maskBits(n) {
-        while(bitLen < n) {
-            bitBuf |= input[inputPosition++] << bitLen;
-            bitLen += 8;
-        }
-        var res = bitBuf & MASK_BITS[n];
-        bitBuf >>= n;
-        bitLen -= n;
-        return res;
-    }
-
-    function codes(buff, off, size) {
-        var e, t;
-        if(size == 0) return 0;
-
-        var n = 0;
-        for(;;) {
-            t = tblList.list[addBits(bitList) & MASK_BITS[bitList]];
-            e = t.extra;
-            while(e > 16) {
-                if(e == 99) return -1;
-                cutBits(t.bitcnt);
-                e -= 16;
-                t = t.next[addBits(e) & MASK_BITS[e]];
-                e = t.extra;
-            }
-            cutBits(t.bitcnt);
-            if(e == 16) {
-                windowPos &= WSIZE - 1;
-                buff[off + n++] = slide[windowPos++] = t.lbase;
-                if(n == size) return size;
-                continue;
-            }
-            if(e == 15) break;
-
-            copyLen = t.lbase + maskBits(e);
-            t = tblDist.list[addBits(bitdist) & MASK_BITS[bitdist]];
-            e = t.extra;
-
-            while(e > 16) {
-                if(e == 99) return -1;
-                cutBits(t.bitcnt);
-                e -= 16;
-                t = t.next[addBits(e) & MASK_BITS[e]];
-                e = t.extra
-            }
-            cutBits(t.bitcnt);
-            copyDist = windowPos - t.lbase - maskBits(e);
-
-            while(copyLen > 0 && n < size) {
-                copyLen--;
-                copyDist &= WSIZE - 1;
-                windowPos &= WSIZE - 1;
-                buff[off + n++] = slide[windowPos++] = slide[copyDist++];
-            }
-
-            if(n == size) return size;
-        }
-
-        method = -1; // done
-        return n;
-    }
-
-    function stored(buff, off, size) {
-        cutBits(bitLen & 7);
-        var n = maskBits(0x10);
-        if(n != ((~maskBits(0x10)) & 0xffff)) return -1;
-        copyLen = n;
-
-        n = 0;
-        while(copyLen > 0 && n < size) {
-            copyLen--;
-            windowPos &= WSIZE - 1;
-            buff[off + n++] = slide[windowPos++] = maskBits(8);
-        }
-
-        if(copyLen == 0) method = -1;
-        return n;
-    }
-
-    function fixed(buff, off, size) {
-        var fixed_bd = 0;
-        if(fixedTableList == null) {
-            var lengths = [];
-
-            for(var symbol = 0; symbol < 144; symbol++) lengths[symbol] = 8;
-            for(; symbol < 256; symbol++) lengths[symbol] = 9;
-            for(; symbol < 280; symbol++) lengths[symbol] = 7;
-            for(; symbol < 288; symbol++) lengths[symbol] = 8;
-
-            fixedLookup = 7;
-
-            var htbl = new HuffTable(lengths, 288, 257, LENS, LEXT, fixedLookup);
-
-            if(htbl.status != 0) return -1;
-
-            fixedTableList = htbl.root;
-            fixedLookup = htbl.maxbit;
-
-            for(symbol = 0; symbol < 30; symbol++) lengths[symbol] = 5;
-            fixed_bd = 5;
-
-            htbl = new HuffTable(lengths, 30, 0, DISTS, DEXT, fixed_bd);
-            if(htbl.status > 1) {
-                fixedTableList = null;
-                return -1;
-            }
-            fixedTableDist = htbl.root;
-            fixed_bd = htbl.maxbit;
-        }
-
-        tblList = fixedTableList;
-        tblDist = fixedTableDist;
-        bitList = fixedLookup;
-        bitdist = fixed_bd;
-        return codes(buff, off, size);
-    }
-
-    function dynamic(buff, off, size) {
-        var ll = new Array(0x023C);
-
-        for (var m = 0; m < 0x023C; m++) ll[m] = 0;
-
-        var llencnt = 257 + maskBits(5),
-            dcodescnt = 1 + maskBits(5),
-            bitlencnt = 4 + maskBits(4);
-
-        if(llencnt > 286 || dcodescnt > 30) return -1;
-
-        for(var j = 0; j < bitlencnt; j++) ll[BITORDER[j]] = maskBits(3);
-        for(; j < 19; j++) ll[BITORDER[j]] = 0;
-
-        // build decoding table for trees--single level, 7 bit lookup
-        bitList = 7;
-        var hufTable = new HuffTable(ll, 19, 19, null, null, bitList);
-        if(hufTable.status != 0)
-            return -1;	// incomplete code set
-
-        tblList = hufTable.root;
-        bitList = hufTable.maxbit;
-        var lencnt = llencnt + dcodescnt,
-            i = 0,
-            lastLen = 0;
-        while(i < lencnt) {
-            var hufLcode = tblList.list[addBits(bitList) & MASK_BITS[bitList]];
-            j = hufLcode.bitcnt;
-            cutBits(j);
-            j = hufLcode.lbase;
-            if(j < 16)
-                ll[i++] = lastLen = j;
-            else if(j == 16) {
-                j = 3 + maskBits(2);
-                if(i + j > lencnt) return -1;
-                while(j-- > 0) ll[i++] = lastLen;
-            } else if(j == 17) {
-                j = 3 + maskBits(3);
-                if(i + j > lencnt) return -1;
-                while(j-- > 0) ll[i++] = 0;
-                lastLen = 0;
-            } else {
-                j = 11 + maskBits(7);
-                if(i + j > lencnt) return -1;
-                while(j-- > 0) ll[i++] = 0;
-                lastLen = 0;
-            }
-        }
-        bitList = 9;
-        hufTable = new HuffTable(ll, llencnt, 257, LENS, LEXT, bitList);
-        bitList == 0 && (hufTable.status = 1);
-
-        if (hufTable.status != 0) return -1;
-
-        tblList = hufTable.root;
-        bitList = hufTable.maxbit;
-
-        for(i = 0; i < dcodescnt; i++) ll[i] = ll[i + llencnt];
-        bitdist = 6;
-        hufTable = new HuffTable(ll, dcodescnt, 0, DISTS, DEXT, bitdist);
-        tblDist = hufTable.root;
-        bitdist = hufTable.maxbit;
-
-        if((bitdist == 0 && llencnt > 257) || hufTable.status != 0) return -1;
-
-        return codes(buff, off, size);
-    }
-
-    return {
-        inflate : function(/*Buffer*/outputBuffer) {
-            tblList = null;
-
-            var size = outputBuffer.length,
-                offset = 0, i;
-
-            while(offset < size) {
-                if(eof && method == -1) return;
-                if(copyLen > 0) {
-                    if(method != 0) {
-                        while(copyLen > 0 && offset < size) {
-                            copyLen--;
-                            copyDist &= WSIZE - 1;
-                            windowPos &= WSIZE - 1;
-                            outputBuffer[offset++] = (slide[windowPos++] = slide[copyDist++]);
-                        }
-                    } else {
-                        while(copyLen > 0 && offset < size) {
-                            copyLen--;
-                            windowPos &= WSIZE - 1;
-                            outputBuffer[offset++] = (slide[windowPos++] = maskBits(8));
-                        }
-                        copyLen == 0 && (method = -1); // done
-                    }
-                    if (offset == size) return;
-                }
-
-                if(method == -1) {
-                    if(eof) break;
-                    eof = maskBits(1) != 0;
-                    method = maskBits(2);
-                    tblList = null;
-                    copyLen = 0;
-                }
-                switch(method) {
-                    case 0: i = stored(outputBuffer, offset, size - offset); break;
-                    case 1: i = tblList != null ? codes(outputBuffer, offset, size - offset) : fixed(outputBuffer, offset, size - offset); break;
-                    case 2: i = tblList != null ? codes(outputBuffer, offset, size - offset) : dynamic(outputBuffer, offset, size - offset); break;
-                    default: i = -1; break;
-                }
-
-                if(i == -1) return;
-                offset += i;
-            }
-        }
-    };
-}
-
-module.exports = function(/*Buffer*/inbuf) {
-    var zlib = require("zlib");
-    return {
-        inflateAsync : function(/*Function*/callback) {
-            var tmp = zlib.createInflateRaw(),
-                parts = [], total = 0;
-            tmp.on('data', function(data) {
-                parts.push(data);
-                total += data.length;
-            });
-            tmp.on('end', function() {
-                var buf = new Buffer(total), written = 0;
-                buf.fill(0);
-
-                for (var i = 0; i < parts.length; i++) {
-                    var part = parts[i];
-                    part.copy(buf, written);
-                    written += part.length;
-                }
-                callback && callback(buf);
-            });
-            tmp.end(inbuf)
-        },
-
-        inflate : function(/*Buffer*/outputBuffer) {
-            var x = {
-                x: new JSInflater(inbuf)
-            };
-            x.x.inflate(outputBuffer);
-            delete(x.x);
-        }
-    }
-};
diff --git a/node_modules/adm-zip/package.json b/node_modules/adm-zip/package.json
deleted file mode 100644
index 436e8f2..0000000
--- a/node_modules/adm-zip/package.json
+++ /dev/null
@@ -1,103 +0,0 @@
-{
-  "_args": [
-    [
-      {
-        "raw": "adm-zip@*",
-        "scope": null,
-        "escapedName": "adm-zip",
-        "name": "adm-zip",
-        "rawSpec": "*",
-        "spec": "*",
-        "type": "range"
-      },
-      "/Users/steveng/repo/cordova/cordova-browser"
-    ]
-  ],
-  "_from": "adm-zip@*",
-  "_id": "adm-zip@0.4.7",
-  "_inCache": true,
-  "_location": "/adm-zip",
-  "_nodeVersion": "0.12.0",
-  "_npmUser": {
-    "name": "cthackers",
-    "email": "iacob.campia@gmail.com"
-  },
-  "_npmVersion": "2.5.1",
-  "_phantomChildren": {},
-  "_requested": {
-    "raw": "adm-zip@*",
-    "scope": null,
-    "escapedName": "adm-zip",
-    "name": "adm-zip",
-    "rawSpec": "*",
-    "spec": "*",
-    "type": "range"
-  },
-  "_requiredBy": [
-    "/"
-  ],
-  "_resolved": "http://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz",
-  "_shasum": "8606c2cbf1c426ce8c8ec00174447fd49b6eafc1",
-  "_shrinkwrap": null,
-  "_spec": "adm-zip@*",
-  "_where": "/Users/steveng/repo/cordova/cordova-browser",
-  "author": {
-    "name": "Nasca Iacob",
-    "email": "sy@another-d-mention.ro",
-    "url": "https://github.com/cthackers"
-  },
-  "bugs": {
-    "url": "https://github.com/cthackers/adm-zip/issues",
-    "email": "sy@another-d-mention.ro"
-  },
-  "dependencies": {},
-  "description": "A Javascript implementation of zip for nodejs. Allows user to create or extract zip files both in memory or to/from disk",
-  "devDependencies": {},
-  "directories": {},
-  "dist": {
-    "shasum": "8606c2cbf1c426ce8c8ec00174447fd49b6eafc1",
-    "tarball": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz"
-  },
-  "engines": {
-    "node": ">=0.3.0"
-  },
-  "files": [
-    "adm-zip.js",
-    "headers",
-    "methods",
-    "util",
-    "zipEntry.js",
-    "zipFile.js"
-  ],
-  "gitHead": "6708a3e5788ff9e67ddba288397f7788a5c02855",
-  "homepage": "http://github.com/cthackers/adm-zip",
-  "keywords": [
-    "zip",
-    "methods",
-    "archive",
-    "unzip"
-  ],
-  "licenses": [
-    {
-      "type": "MIT",
-      "url": "https://raw.github.com/cthackers/adm-zip/master/MIT-LICENSE.txt"
-    }
-  ],
-  "main": "adm-zip.js",
-  "maintainers": [
-    {
-      "name": "cthackers",
-      "email": "sy@another-d-mention.ro"
-    }
-  ],
-  "name": "adm-zip",
-  "optionalDependencies": {},
-  "readme": "# ADM-ZIP for NodeJS\r\n\r\nADM-ZIP is a pure JavaScript implementation for zip data compression for [NodeJS](http://nodejs.org/). \r\n\r\n# Installation\r\n\r\nWith [npm](http://npmjs.org) do:\r\n\r\n    $ npm install adm-zip\r\n\t\r\n## What is it good for?\r\nThe library allows you to:\r\n\r\n* decompress zip files directly to disk or in memory buffers\r\n* compress files and store them to disk in .zip format or in compressed buffers\r\n* update content of/add new/delete files from an existing .zip\r\n\r\n# Dependencies\r\nThere are no other nodeJS libraries that ADM-ZIP is dependent of\r\n\r\n# Examples\r\n\r\n## Basic usage\r\n```javascript\r\n\r\n\tvar AdmZip = require('adm-zip');\r\n\r\n\t// reading archives\r\n\tvar zip = new AdmZip(\"./my_file.zip\");\r\n\tvar zipEntries = zip.getEntries(); // an array of ZipEntry records\r\n\r\n\tzipEntries.forEach(function(zipEntry) {\r\n\t    console.log(zipEntry.toString()); // outputs zip entries information\r\n\t\tif (zipEntry.entryName == \"my_file.txt\") {\r\n\t\t     console.log(zipEntry.data.toString('utf8')); \r\n\t\t}\r\n\t});\r\n\t// outputs the content of some_folder/my_file.txt\r\n\tconsole.log(zip.readAsText(\"some_folder/my_file.txt\")); \r\n\t// extracts the specified file to the specified location\r\n\tzip.extractEntryTo(/*entry name*/\"some_folder/my_file.txt\", /*target path*/\"/home/me/tempfolder\", /*maintainEntryPath*/false, /*overwrite*/true);\r\n\t// extracts everything\r\n\tzip.extractAllTo(/*target path*/\"/home/me/zipcontent/\", /*overwrite*/true);\r\n\t\r\n\t\r\n\t// creating archives\r\n\tvar zip = new AdmZip();\r\n\t\r\n\t// add file directly\r\n\tzip.addFile(\"test.txt\", new Buffer(\"inner content of the file\"), \"entry comment goes here\");\r\n\t// add local file\r\n\tzip.addLocalFile(\"/home/me/some_picture.png\");\r\n\t// get everything as a buffer\r\n\tvar willSendthis = zip.toBuffer();\r\n\t// or write everything to disk\r\n\tzip.writeZip(/*target file name*/\"/home/me/files.zip\");\r\n\t\r\n\t\r\n\t// ... more examples in the wiki\r\n```\r\n\r\nFor more detailed information please check out the [wiki](https://github.com/cthackers/adm-zip/wiki).\r\n\r\n[![build status](https://secure.travis-ci.org/cthackers/adm-zip.png)](http://travis-ci.org/cthackers/adm-zip)\r\n",
-  "readmeFilename": "README.md",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/cthackers/adm-zip.git"
-  },
-  "scripts": {},
-  "version": "0.4.7"
-}
diff --git a/node_modules/adm-zip/util/constants.js b/node_modules/adm-zip/util/constants.js
deleted file mode 100644
index 02de1e9..0000000
--- a/node_modules/adm-zip/util/constants.js
+++ /dev/null
@@ -1,115 +0,0 @@
-module.exports = {
-    /* The local file header */
-    LOCHDR           : 30, // LOC header size
-    LOCSIG           : 0x04034b50, // "PK\003\004"
-    LOCVER           : 4,	// version needed to extract
-    LOCFLG           : 6, // general purpose bit flag
-    LOCHOW           : 8, // compression method
-    LOCTIM           : 10, // modification time (2 bytes time, 2 bytes date)
-    LOCCRC           : 14, // uncompressed file crc-32 value
-    LOCSIZ           : 18, // compressed size
-    LOCLEN           : 22, // uncompressed size
-    LOCNAM           : 26, // filename length
-    LOCEXT           : 28, // extra field length
-
-    /* The Data descriptor */
-    EXTSIG           : 0x08074b50, // "PK\007\008"
-    EXTHDR           : 16, // EXT header size
-    EXTCRC           : 4, // uncompressed file crc-32 value
-    EXTSIZ           : 8, // compressed size
-    EXTLEN           : 12, // uncompressed size
-
-    /* The central directory file header */
-    CENHDR           : 46, // CEN header size
-    CENSIG           : 0x02014b50, // "PK\001\002"
-    CENVEM           : 4, // version made by
-    CENVER           : 6, // version needed to extract
-    CENFLG           : 8, // encrypt, decrypt flags
-    CENHOW           : 10, // compression method
-    CENTIM           : 12, // modification time (2 bytes time, 2 bytes date)
-    CENCRC           : 16, // uncompressed file crc-32 value
-    CENSIZ           : 20, // compressed size
-    CENLEN           : 24, // uncompressed size
-    CENNAM           : 28, // filename length
-    CENEXT           : 30, // extra field length
-    CENCOM           : 32, // file comment length
-    CENDSK           : 34, // volume number start
-    CENATT           : 36, // internal file attributes
-    CENATX           : 38, // external file attributes (host system dependent)
-    CENOFF           : 42, // LOC header offset
-
-    /* The entries in the end of central directory */
-    ENDHDR           : 22, // END header size
-    ENDSIG           : 0x06054b50, // "PK\005\006"
-    ENDSUB           : 8, // number of entries on this disk
-    ENDTOT           : 10, // total number of entries
-    ENDSIZ           : 12, // central directory size in bytes
-    ENDOFF           : 16, // offset of first CEN header
-    ENDCOM           : 20, // zip file comment length
-
-    /* Compression methods */
-    STORED           : 0, // no compression
-    SHRUNK           : 1, // shrunk
-    REDUCED1         : 2, // reduced with compression factor 1
-    REDUCED2         : 3, // reduced with compression factor 2
-    REDUCED3         : 4, // reduced with compression factor 3
-    REDUCED4         : 5, // reduced with compression factor 4
-    IMPLODED         : 6, // imploded
-    // 7 reserved
-    DEFLATED         : 8, // deflated
-    ENHANCED_DEFLATED: 9, // enhanced deflated
-    PKWARE           : 10,// PKWare DCL imploded
-    // 11 reserved
-    BZIP2            : 12, //  compressed using BZIP2
-    // 13 reserved
-    LZMA             : 14, // LZMA
-    // 15-17 reserved
-    IBM_TERSE        : 18, // compressed using IBM TERSE
-    IBM_LZ77         : 19, //IBM LZ77 z
-
-    /* General purpose bit flag */
-    FLG_ENC          : 0,  // encripted file
-    FLG_COMP1        : 1,  // compression option
-    FLG_COMP2        : 2,  // compression option
-    FLG_DESC         : 4,  // data descriptor
-    FLG_ENH          : 8,  // enhanced deflation
-    FLG_STR          : 16, // strong encryption
-    FLG_LNG          : 1024, // language encoding
-    FLG_MSK          : 4096, // mask header values
-
-    /* Load type */
-    FILE             : 0,
-    BUFFER           : 1,
-    NONE             : 2,
-
-    /* 4.5 Extensible data fields */
-    EF_ID            : 0,
-    EF_SIZE          : 2,
-
-    /* Header IDs */
-    ID_ZIP64         : 0x0001,
-    ID_AVINFO        : 0x0007,
-    ID_PFS           : 0x0008,
-    ID_OS2           : 0x0009,
-    ID_NTFS          : 0x000a,
-    ID_OPENVMS       : 0x000c,
-    ID_UNIX          : 0x000d,
-    ID_FORK          : 0x000e,
-    ID_PATCH         : 0x000f,
-    ID_X509_PKCS7    : 0x0014,
-    ID_X509_CERTID_F : 0x0015,
-    ID_X509_CERTID_C : 0x0016,
-    ID_STRONGENC     : 0x0017,
-    ID_RECORD_MGT    : 0x0018,
-    ID_X509_PKCS7_RL : 0x0019,
-    ID_IBM1          : 0x0065,
-    ID_IBM2          : 0x0066,
-    ID_POSZIP        : 0x4690,
-
-    EF_ZIP64_OR_32   : 0xffffffff,
-    EF_ZIP64_OR_16   : 0xffff,
-    EF_ZIP64_SUNCOMP : 0,
-    EF_ZIP64_SCOMP   : 8,
-    EF_ZIP64_RHO     : 16,
-    EF_ZIP64_DSN     : 24
-};
diff --git a/node_modules/adm-zip/util/errors.js b/node_modules/adm-zip/util/errors.js
deleted file mode 100644
index 50931c3..0000000
--- a/node_modules/adm-zip/util/errors.js
+++ /dev/null
@@ -1,35 +0,0 @@
-module.exports = {
-    /* Header error messages */
-    "INVALID_LOC" : "Invalid LOC header (bad signature)",
-    "INVALID_CEN" : "Invalid CEN header (bad signature)",
-    "INVALID_END" : "Invalid END header (bad signature)",
-
-    /* ZipEntry error messages*/
-    "NO_DATA" : "Nothing to decompress",
-    "BAD_CRC" : "CRC32 checksum failed",
-    "FILE_IN_THE_WAY" : "There is a file in the way: %s",
-    "UNKNOWN_METHOD" : "Invalid/unsupported compression method",
-
-    /* Inflater error messages */
-    "AVAIL_DATA" : "inflate::Available inflate data did not terminate",
-    "INVALID_DISTANCE" : "inflate::Invalid literal/length or distance code in fixed or dynamic block",
-    "TO_MANY_CODES" : "inflate::Dynamic block code description: too many length or distance codes",
-    "INVALID_REPEAT_LEN" : "inflate::Dynamic block code description: repeat more than specified lengths",
-    "INVALID_REPEAT_FIRST" : "inflate::Dynamic block code description: repeat lengths with no first length",
-    "INCOMPLETE_CODES" : "inflate::Dynamic block code description: code lengths codes incomplete",
-    "INVALID_DYN_DISTANCE": "inflate::Dynamic block code description: invalid distance code lengths",
-    "INVALID_CODES_LEN": "inflate::Dynamic block code description: invalid literal/length code lengths",
-    "INVALID_STORE_BLOCK" : "inflate::Stored block length did not match one's complement",
-    "INVALID_BLOCK_TYPE" : "inflate::Invalid block type (type == 3)",
-
-    /* ADM-ZIP error messages */
-    "CANT_EXTRACT_FILE" : "Could not extract the file",
-    "CANT_OVERRIDE" : "Target file already exists",
-    "NO_ZIP" : "No zip file was loaded",
-    "NO_ENTRY" : "Entry doesn't exist",
-    "DIRECTORY_CONTENT_ERROR" : "A directory cannot have content",
-    "FILE_NOT_FOUND" : "File not found: %s",
-    "NOT_IMPLEMENTED" : "Not implemented",
-    "INVALID_FILENAME" : "Invalid filename",
-    "INVALID_FORMAT" : "Invalid or unsupported zip format. No END header found"
-};
\ No newline at end of file
diff --git a/node_modules/adm-zip/util/fattr.js b/node_modules/adm-zip/util/fattr.js
deleted file mode 100644
index 4f247ea..0000000
--- a/node_modules/adm-zip/util/fattr.js
+++ /dev/null
@@ -1,84 +0,0 @@
-var fs = require("fs"),
-    pth = require("path");
-	
-fs.existsSync = fs.existsSync || pth.existsSync;
-
-module.exports = function(/*String*/path) {
-
-    var _path = path || "",
-        _permissions = 0,
-        _obj = newAttr(),
-        _stat = null;
-
-    function newAttr() {
-        return {
-            directory : false,
-            readonly : false,
-            hidden : false,
-            executable : false,
-            mtime : 0,
-            atime : 0
-        }
-    }
-
-    if (_path && fs.existsSync(_path)) {
-        _stat = fs.statSync(_path);
-        _obj.directory = _stat.isDirectory();
-        _obj.mtime = _stat.mtime;
-        _obj.atime = _stat.atime;
-        _obj.executable = !!(1 & parseInt ((_stat.mode & parseInt ("777", 8)).toString (8)[0]));
-        _obj.readonly = !!(2 & parseInt ((_stat.mode & parseInt ("777", 8)).toString (8)[0]));
-        _obj.hidden = pth.basename(_path)[0] === ".";
-    } else {
-        console.warn("Invalid path: " + _path)
-    }
-
-    return {
-
-        get directory () {
-            return _obj.directory;
-        },
-
-        get readOnly () {
-            return _obj.readonly;
-        },
-
-        get hidden () {
-            return _obj.hidden;
-        },
-
-        get mtime () {
-            return _obj.mtime;
-        },
-
-        get atime () {
-           return _obj.atime;
-        },
-
-
-        get executable () {
-            return _obj.executable;
-        },
-
-        decodeAttributes : function(val) {
-
-        },
-
-        encodeAttributes : function (val) {
-
-        },
-
-        toString : function() {
-           return '{\n' +
-               '\t"path" : "' + _path + ",\n" +
-               '\t"isDirectory" : ' + _obj.directory + ",\n" +
-               '\t"isReadOnly" : ' + _obj.readonly + ",\n" +
-               '\t"isHidden" : ' + _obj.hidden + ",\n" +
-               '\t"isExecutable" : ' + _obj.executable + ",\n" +
-               '\t"mTime" : ' + _obj.mtime + "\n" +
-               '\t"aTime" : ' + _obj.atime + "\n" +
-           '}';
-        }
-    }
-
-};
diff --git a/node_modules/adm-zip/util/index.js b/node_modules/adm-zip/util/index.js
deleted file mode 100644
index d77b980..0000000
--- a/node_modules/adm-zip/util/index.js
+++ /dev/null
@@ -1,4 +0,0 @@
-module.exports = require("./utils");
-module.exports.Constants = require("./constants");
-module.exports.Errors = require("./errors");
-module.exports.FileAttr = require("./fattr");
\ No newline at end of file
diff --git a/node_modules/adm-zip/util/utils.js b/node_modules/adm-zip/util/utils.js
deleted file mode 100644
index 52a8ed9..0000000
--- a/node_modules/adm-zip/util/utils.js
+++ /dev/null
@@ -1,199 +0,0 @@
-var fs = require("fs"),
-    pth = require('path');
-
-fs.existsSync = fs.existsSync || pth.existsSync;
-
-module.exports = (function() {
-
-    var crcTable = [],
-        Constants = require('./constants'),
-        Errors = require('./errors'),
-
-        PATH_SEPARATOR = pth.normalize("/");
-
-
-    function mkdirSync(/*String*/path) {
-        var resolvedPath = path.split(PATH_SEPARATOR)[0];
-        path.split(PATH_SEPARATOR).forEach(function(name) {
-            if (!name || name.substr(-1,1) == ":") return;
-            resolvedPath += PATH_SEPARATOR + name;
-            var stat;
-            try {
-                stat = fs.statSync(resolvedPath);
-            } catch (e) {
-                fs.mkdirSync(resolvedPath);
-            }
-            if (stat && stat.isFile())
-                throw Errors.FILE_IN_THE_WAY.replace("%s", resolvedPath);
-        });
-    }
-
-    function findSync(/*String*/root, /*RegExp*/pattern, /*Boolean*/recoursive) {
-        if (typeof pattern === 'boolean') {
-            recoursive = pattern;
-            pattern = undefined;
-        }
-        var files = [];
-        fs.readdirSync(root).forEach(function(file) {
-            var path = pth.join(root, file);
-
-            if (fs.statSync(path).isDirectory() && recoursive)
-                files = files.concat(findSync(path, pattern, recoursive));
-
-            if (!pattern || pattern.test(path)) {
-                files.push(pth.normalize(path) + (fs.statSync(path).isDirectory() ? PATH_SEPARATOR : ""));
-            }
-
-        });
-        return files;
-    }
-
-    return {
-        makeDir : function(/*String*/path) {
-            mkdirSync(path);
-        },
-
-        crc32 : function(buf) {
-            var b = new Buffer(4);
-            if (!crcTable.length) {
-                for (var n = 0; n < 256; n++) {
-                    var c = n;
-                    for (var k = 8; --k >= 0;)  //
-                        if ((c & 1) != 0)  { c = 0xedb88320 ^ (c >>> 1); } else { c = c >>> 1; }
-                    if (c < 0) {
-                        b.writeInt32LE(c, 0);
-                        c = b.readUInt32LE(0);
-                    }
-                    crcTable[n] = c;
-                }
-            }
-            var crc = 0, off = 0, len = buf.length, c1 = ~crc;
-            while(--len >= 0) c1 = crcTable[(c1 ^ buf[off++]) & 0xff] ^ (c1 >>> 8);
-            crc = ~c1;
-            b.writeInt32LE(crc & 0xffffffff, 0);
-            return b.readUInt32LE(0);
-        },
-
-        methodToString : function(/*Number*/method) {
-            switch (method) {
-                case Constants.STORED:
-                    return 'STORED (' + method + ')';
-                case Constants.DEFLATED:
-                    return 'DEFLATED (' + method + ')';
-                default:
-                    return 'UNSUPPORTED (' + method + ')';
-            }
-
-        },
-
-        writeFileTo : function(/*String*/path, /*Buffer*/content, /*Boolean*/overwrite, /*Number*/attr) {
-            if (fs.existsSync(path)) {
-                if (!overwrite)
-                    return false; // cannot overwite
-
-                var stat = fs.statSync(path);
-                if (stat.isDirectory()) {
-                    return false;
-                }
-            }
-            var folder = pth.dirname(path);
-            if (!fs.existsSync(folder)) {
-                mkdirSync(folder);
-            }
-
-            var fd;
-            try {
-                fd = fs.openSync(path, 'w', 438); // 0666
-            } catch(e) {
-                fs.chmodSync(path, 438);
-                fd = fs.openSync(path, 'w', 438);
-            }
-            if (fd) {
-                fs.writeSync(fd, content, 0, content.length, 0);
-                fs.closeSync(fd);
-            }
-            fs.chmodSync(path, attr || 438);
-            return true;
-        },
-
-        writeFileToAsync : function(/*String*/path, /*Buffer*/content, /*Boolean*/overwrite, /*Number*/attr, /*Function*/callback) {
-            if(typeof attr === 'function') {
-                callback = attr;
-                attr = undefined;
-            }
-
-            fs.exists(path, function(exists) {
-                if(exists && !overwrite)
-                    return callback(false);
-
-                fs.stat(path, function(err, stat) {
-                    if(exists &&stat.isDirectory()) {
-                        return callback(false);
-                    }
-
-                    var folder = pth.dirname(path);
-                    fs.exists(folder, function(exists) {
-                        if(!exists)
-                            mkdirSync(folder);
-                        
-                        fs.open(path, 'w', 438, function(err, fd) {
-                            if(err) {
-                                fs.chmod(path, 438, function(err) {
-                                    fs.open(path, 'w', 438, function(err, fd) {
-                                        fs.write(fd, content, 0, content.length, 0, function(err, written, buffer) {
-                                            fs.close(fd, function(err) {
-                                                fs.chmod(path, attr || 438, function() {
-                                                    callback(true);
-                                                })
-                                            });
-                                        });
-                                    });
-                                })
-                            } else {
-                                if(fd) {
-                                    fs.write(fd, content, 0, content.length, 0, function(err, written, buffer) {
-                                        fs.close(fd, function(err) {
-                                            fs.chmod(path, attr || 438, function() {
-                                                callback(true);
-                                            })
-                                        });
-                                    });
-                                } else {
-                                    fs.chmod(path, attr || 438, function() {
-                                        callback(true);
-                                    })
-                                }
-                            }
-                        });
-                    })
-                })
-            })
-        },
-
-        findFiles : function(/*String*/path) {
-            return findSync(path, true);
-        },
-
-        getAttributes : function(/*String*/path) {
-
-        },
-
-        setAttributes : function(/*String*/path) {
-
-        },
-
-        toBuffer : function(input) {
-            if (Buffer.isBuffer(input)) {
-                return input;
-            } else {
-                if (input.length == 0) {
-                    return new Buffer(0)
-                }
-                return new Buffer(input, 'utf8');
-            }
-        },
-
-        Constants : Constants,
-        Errors : Errors
-    }
-})();
diff --git a/node_modules/adm-zip/zipEntry.js b/node_modules/adm-zip/zipEntry.js
deleted file mode 100644
index 6b1309b..0000000
--- a/node_modules/adm-zip/zipEntry.js
+++ /dev/null
@@ -1,284 +0,0 @@
-var Utils = require("./util"),
-    Headers = require("./headers"),
-    Constants = Utils.Constants,
-    Methods = require("./methods");
-
-module.exports = function (/*Buffer*/input) {
-
-    var _entryHeader = new Headers.EntryHeader(),
-        _entryName = new Buffer(0),
-        _comment = new Buffer(0),
-        _isDirectory = false,
-        uncompressedData = null,
-        _extra = new Buffer(0);
-
-    function getCompressedDataFromZip() {
-        if (!input || !Buffer.isBuffer(input)) {
-            return new Buffer(0);
-        }
-        _entryHeader.loadDataHeaderFromBinary(input);
-        return input.slice(_entryHeader.realDataOffset, _entryHeader.realDataOffset + _entryHeader.compressedSize)
-    }
-
-    function crc32OK(data) {
-        // if bit 3 (0x08) of the general-purpose flags field is set, then the CRC-32 and file sizes are not known when the header is written
-        if (_entryHeader.flags & 0x8 != 0x8) {
-           if (Utils.crc32(data) != _entryHeader.crc) {
-               return false;
-           }
-        } else {
-            // @TODO: load and check data descriptor header
-            // The fields in the local header are filled with zero, and the CRC-32 and size are appended in a 12-byte structure
-            // (optionally preceded by a 4-byte signature) immediately after the compressed data:
-        }
-        return true;
-    }
-
-    function decompress(/*Boolean*/async, /*Function*/callback, /*String*/pass) {
-        if(typeof callback === 'undefined' && typeof async === 'string') {
-            pass=async;
-            async=void 0;
-        }
-        if (_isDirectory) {
-            if (async && callback) {
-                callback(new Buffer(0), Utils.Errors.DIRECTORY_CONTENT_ERROR); //si added error.
-            }
-            return new Buffer(0);
-        }
-
-        var compressedData = getCompressedDataFromZip();
-       
-        if (compressedData.length == 0) {
-            if (async && callback) callback(compressedData, Utils.Errors.NO_DATA);//si added error.
-            return compressedData;
-        }
-
-        var data = new Buffer(_entryHeader.size);
-        data.fill(0);
-
-        switch (_entryHeader.method) {
-            case Utils.Constants.STORED:
-                compressedData.copy(data);
-                if (!crc32OK(data)) {
-                    if (async && callback) callback(data, Utils.Errors.BAD_CRC);//si added error
-                    return Utils.Errors.BAD_CRC;
-                } else {//si added otherwise did not seem to return data.
-                    if (async && callback) callback(data);
-                    return data;
-                }
-                break;
-            case Utils.Constants.DEFLATED:
-                var inflater = new Methods.Inflater(compressedData);
-                if (!async) {
-                    inflater.inflate(data);
-                    if (!crc32OK(data)) {
-                        console.warn(Utils.Errors.BAD_CRC + " " + _entryName.toString())
-                    }
-                    return data;
-                } else {
-                    inflater.inflateAsync(function(result) {
-                        result.copy(data, 0);
-                        if (!crc32OK(data)) {
-                            if (callback) callback(data, Utils.Errors.BAD_CRC); //si added error
-                        } else { //si added otherwise did not seem to return data.
-                            if (callback) callback(data);
-                        }
-                    })
-                }
-                break;
-            default:
-                if (async && callback) callback(new Buffer(0), Utils.Errors.UNKNOWN_METHOD);
-                return Utils.Errors.UNKNOWN_METHOD;
-        }
-    }
-
-    function compress(/*Boolean*/async, /*Function*/callback) {
-        if ((!uncompressedData || !uncompressedData.length) && Buffer.isBuffer(input)) {
-            // no data set or the data wasn't changed to require recompression
-            if (async && callback) callback(getCompressedDataFromZip());
-            return getCompressedDataFromZip();
-        }
-
-        if (uncompressedData.length && !_isDirectory) {
-            var compressedData;
-            // Local file header
-            switch (_entryHeader.method) {
-                case Utils.Constants.STORED:
-                    _entryHeader.compressedSize = _entryHeader.size;
-
-                    compressedData = new Buffer(uncompressedData.length);
-                    uncompressedData.copy(compressedData);
-
-                    if (async && callback) callback(compressedData);
-                    return compressedData;
-
-                    break;
-                default:
-                case Utils.Constants.DEFLATED:
-
-                    var deflater = new Methods.Deflater(uncompressedData);
-                    if (!async) {
-                        var deflated = deflater.deflate();
-                        _entryHeader.compressedSize = deflated.length;
-                        return deflated;
-                    } else {
-                        deflater.deflateAsync(function(data) {
-                            compressedData = new Buffer(data.length);
-                            _entryHeader.compressedSize = data.length;
-                            data.copy(compressedData);
-                            callback && callback(compressedData);
-                        })
-                    }
-                    deflater = null;
-                    break;
-            }
-        } else {
-            if (async && callback) {
-                callback(new Buffer(0));
-            } else {
-                return new Buffer(0);
-            }
-        }
-    }
-
-    function readUInt64LE(buffer, offset) {
-        return (buffer.readUInt32LE(offset + 4) << 4) + buffer.readUInt32LE(offset);
-    }
-
-    function parseExtra(data) {
-        var offset = 0;
-        var signature, size, part;
-        while(offset<data.length) {
-            signature = data.readUInt16LE(offset);
-            offset += 2;
-            size = data.readUInt16LE(offset);
-            offset += 2;
-            part = data.slice(offset, offset+size);
-            offset += size;
-            if(Constants.ID_ZIP64 === signature) {
-                parseZip64ExtendedInformation(part);
-            }
-        }
-    }
-
-    //Override header field values with values from the ZIP64 extra field
-    function parseZip64ExtendedInformation(data) {
-        var size, compressedSize, offset, diskNumStart;
-
-        if(data.length >= Constants.EF_ZIP64_SCOMP) {
-            size = readUInt64LE(data, Constants.EF_ZIP64_SUNCOMP);
-            if(_entryHeader.size === Constants.EF_ZIP64_OR_32) {
-                _entryHeader.size = size;
-            }
-        }
-        if(data.length >= Constants.EF_ZIP64_RHO) {
-            compressedSize = readUInt64LE(data, Constants.EF_ZIP64_SCOMP);
-            if(_entryHeader.compressedSize === Constants.EF_ZIP64_OR_32) {
-                _entryHeader.compressedSize = compressedSize;
-            }
-        }
-        if(data.length >= Constants.EF_ZIP64_DSN) {
-            offset = readUInt64LE(data, Constants.EF_ZIP64_RHO);
-            if(_entryHeader.offset === Constants.EF_ZIP64_OR_32) {
-                _entryHeader.offset = offset;
-            }
-        }
-        if(data.length >= Constants.EF_ZIP64_DSN+4) {
-            diskNumStart = data.readUInt32LE(Constants.EF_ZIP64_DSN);
-            if(_entryHeader.diskNumStart === Constants.EF_ZIP64_OR_16) {
-                _entryHeader.diskNumStart = diskNumStart;
-            }
-        }
-    }
-
-
-    return {
-        get entryName () { return _entryName.toString(); },
-        get rawEntryName() { return _entryName; },
-        set entryName (val) {
-            _entryName = Utils.toBuffer(val);
-            var lastChar = _entryName[_entryName.length - 1];
-            _isDirectory = (lastChar == 47) || (lastChar == 92);
-            _entryHeader.fileNameLength = _entryName.length;
-        },
-
-        get extra () { return _extra; },
-        set extra (val) {
-            _extra = val;
-            _entryHeader.extraLength = val.length;
-            parseExtra(val);
-        },
-
-        get comment () { return _comment.toString(); },
-        set comment (val) {
-            _comment = Utils.toBuffer(val);
-            _entryHeader.commentLength = _comment.length;
-        },
-
-        get name () { var n = _entryName.toString(); return _isDirectory ? n.substr(n.length - 1).split("/").pop() : n.split("/").pop(); },
-        get isDirectory () { return _isDirectory },
-
-        getCompressedData : function() {
-            return compress(false, null)
-        },
-
-        getCompressedDataAsync : function(/*Function*/callback) {
-            compress(true, callback)
-        },
-
-        setData : function(value) {
-            uncompressedData = Utils.toBuffer(value);
-            if (!_isDirectory && uncompressedData.length) {
-                _entryHeader.size = uncompressedData.length;
-                _entryHeader.method = Utils.Constants.DEFLATED;
-                _entryHeader.crc = Utils.crc32(value);
-            } else { // folders and blank files should be stored
-                _entryHeader.method = Utils.Constants.STORED;
-            }
-        },
-
-        getData : function(pass) {
-            return decompress(false, null, pass);
-        },
-
-        getDataAsync : function(/*Function*/callback, pass) {
-            decompress(true, callback, pass)
-        },
-
-        set attr(attr) { _entryHeader.attr = attr; },
-        get attr() { return _entryHeader.attr; },
-
-        set header(/*Buffer*/data) {
-            _entryHeader.loadFromBinary(data);
-        },
-
-        get header() {
-            return _entryHeader;
-        },
-
-        packHeader : function() {
-            var header = _entryHeader.entryHeaderToBinary();
-            // add
-            _entryName.copy(header, Utils.Constants.CENHDR);
-            if (_entryHeader.extraLength) {
-                _extra.copy(header, Utils.Constants.CENHDR + _entryName.length)
-            }
-            if (_entryHeader.commentLength) {
-                _comment.copy(header, Utils.Constants.CENHDR + _entryName.length + _entryHeader.extraLength, _comment.length);
-            }
-            return header;
-        },
-
-        toString : function() {
-            return '{\n' +
-                '\t"entryName" : "' + _entryName.toString() + "\",\n" +
-                '\t"name" : "' + _entryName.toString().split("/").pop() + "\",\n" +
-                '\t"comment" : "' + _comment.toString() + "\",\n" +
-                '\t"isDirectory" : ' + _isDirectory + ",\n" +
-                '\t"header" : ' + _entryHeader.toString().replace(/\t/mg, "\t\t") + ",\n" +
-                '\t"compressedData" : <' + (input && input.length  + " bytes buffer" || "null") + ">\n" +
-                '\t"data" : <' + (uncompressedData && uncompressedData.length  + " bytes buffer" || "null") + ">\n" +
-                '}';
-        }
-    }
-};
diff --git a/node_modules/adm-zip/zipFile.js b/node_modules/adm-zip/zipFile.js
deleted file mode 100644
index 794afdb..0000000
--- a/node_modules/adm-zip/zipFile.js
+++ /dev/null
@@ -1,311 +0,0 @@
-var ZipEntry = require("./zipEntry"),
-    Headers = require("./headers"),
-    Utils = require("./util");
-
-module.exports = function(/*String|Buffer*/input, /*Number*/inputType) {
-    var entryList = [],
-        entryTable = {},
-        _comment = new Buffer(0),
-        filename = "",
-        fs = require("fs"),
-        inBuffer = null,
-        mainHeader = new Headers.MainHeader();
-
-    if (inputType == Utils.Constants.FILE) {
-        // is a filename
-        filename = input;
-        inBuffer = fs.readFileSync(filename);
-        readMainHeader();
-    } else if (inputType == Utils.Constants.BUFFER) {
-        // is a memory buffer
-        inBuffer = input;
-        readMainHeader();
-    } else {
-        // none. is a new file
-    }
-
-    function readEntries() {
-        entryTable = {};
-        entryList = new Array(mainHeader.diskEntries);  // total number of entries
-        var index = mainHeader.offset;  // offset of first CEN header
-        for(var i = 0; i < entryList.length; i++) {
-
-            var tmp = index,
-                entry = new ZipEntry(inBuffer);
-            entry.header = inBuffer.slice(tmp, tmp += Utils.Constants.CENHDR);
-
-            entry.entryName = inBuffer.slice(tmp, tmp += entry.header.fileNameLength);
-
-            if (entry.header.extraLength) {
-                entry.extra = inBuffer.slice(tmp, tmp += entry.header.extraLength);
-            }
-
-            if (entry.header.commentLength)
-                entry.comment = inBuffer.slice(tmp, tmp + entry.header.commentLength);
-
-            index += entry.header.entryHeaderSize;
-
-            entryList[i] = entry;
-            entryTable[entry.entryName] = entry;
-        }
-    }
-
-    function readMainHeader() {
-        var i = inBuffer.length - Utils.Constants.ENDHDR, // END header size
-            n = Math.max(0, i - 0xFFFF), // 0xFFFF is the max zip file comment length
-            endOffset = -1; // Start offset of the END header
-
-        for (i; i >= n; i--) {
-            if (inBuffer[i] != 0x50) continue; // quick check that the byte is 'P'
-            if (inBuffer.readUInt32LE(i) == Utils.Constants.ENDSIG) { // "PK\005\006"
-                endOffset = i;
-                break;
-            }
-        }
-        if (!~endOffset)
-            throw Utils.Errors.INVALID_FORMAT;
-
-        mainHeader.loadFromBinary(inBuffer.slice(endOffset, endOffset + Utils.Constants.ENDHDR));
-        if (mainHeader.commentLength) {
-            _comment = inBuffer.slice(endOffset + Utils.Constants.ENDHDR);
-        }
-        readEntries();
-    }
-
-    return {
-        /**
-         * Returns an array of ZipEntry objects existent in the current opened archive
-         * @return Array
-         */
-        get entries () {
-            return entryList;
-        },
-
-        /**
-         * Archive comment
-         * @return {String}
-         */
-        get comment () { return _comment.toString(); },
-        set comment(val) {
-            mainHeader.commentLength = val.length;
-            _comment = val;
-        },
-
-        /**
-         * Returns a reference to the entry with the given name or null if entry is inexistent
-         *
-         * @param entryName
-         * @return ZipEntry
-         */
-        getEntry : function(/*String*/entryName) {
-            return entryTable[entryName] || null;
-        },
-
-        /**
-         * Adds the given entry to the entry list
-         *
-         * @param entry
-         */
-        setEntry : function(/*ZipEntry*/entry) {
-            entryList.push(entry);
-            entryTable[entry.entryName] = entry;
-            mainHeader.totalEntries = entryList.length;
-        },
-
-        /**
-         * Removes the entry with the given name from the entry list.
-         *
-         * If the entry is a directory, then all nested files and directories will be removed
-         * @param entryName
-         */
-        deleteEntry : function(/*String*/entryName) {
-            var entry = entryTable[entryName];
-            if (entry && entry.isDirectory) {
-                var _self = this;
-                this.getEntryChildren(entry).forEach(function(child) {
-                    if (child.entryName != entryName) {
-                        _self.deleteEntry(child.entryName)
-                    }
-                })
-            }
-            entryList.splice(entryList.indexOf(entry), 1);
-            delete(entryTable[entryName]);
-            mainHeader.totalEntries = entryList.length;
-        },
-
-        /**
-         *  Iterates and returns all nested files and directories of the given entry
-         *
-         * @param entry
-         * @return Array
-         */
-        getEntryChildren : function(/*ZipEntry*/entry) {
-            if (entry.isDirectory) {
-                var list = [],
-                    name = entry.entryName,
-                    len = name.length;
-
-                entryList.forEach(function(zipEntry) {
-                    if (zipEntry.entryName.substr(0, len) == name) {
-                        list.push(zipEntry);
-                    }
-                });
-                return list;
-            }
-            return []
-        },
-
-        /**
-         * Returns the zip file
-         *
-         * @return Buffer
-         */
-        compressToBuffer : function() {
-            if (entryList.length > 1) {
-                entryList.sort(function(a, b) {
-                    var nameA = a.entryName.toLowerCase();
-                    var nameB = b.entryName.toLowerCase();
-                    if (nameA < nameB) {return -1}
-                    if (nameA > nameB) {return 1}
-                    return 0;
-                });
-            }
-
-            var totalSize = 0,
-                dataBlock = [],
-                entryHeaders = [],
-                dindex = 0;
-
-            mainHeader.size = 0;
-            mainHeader.offset = 0;
-
-            entryList.forEach(function(entry) {
-                entry.header.offset = dindex;
-
-                // compress data and set local and entry header accordingly. Reason why is called first
-                var compressedData = entry.getCompressedData();
-                // data header
-                var dataHeader = entry.header.dataHeaderToBinary();
-                var postHeader = new Buffer(entry.entryName + entry.extra.toString());
-                var dataLength = dataHeader.length + postHeader.length + compressedData.length;
-
-                dindex += dataLength;
-
-                dataBlock.push(dataHeader);
-                dataBlock.push(postHeader);
-                dataBlock.push(compressedData);
-
-                var entryHeader = entry.packHeader();
-                entryHeaders.push(entryHeader);
-                mainHeader.size += entryHeader.length;
-                totalSize += (dataLength + entryHeader.length);
-            });
-
-            totalSize += mainHeader.mainHeaderSize; // also includes zip file comment length
-            // point to end of data and begining of central directory first record
-            mainHeader.offset = dindex;
-
-            dindex = 0;
-            var outBuffer = new Buffer(totalSize);
-            dataBlock.forEach(function(content) {
-                content.copy(outBuffer, dindex); // write data blocks
-                dindex += content.length;
-            });
-            entryHeaders.forEach(function(content) {
-                content.copy(outBuffer, dindex); // write central directory entries
-                dindex += content.length;
-            });
-
-            var mh = mainHeader.toBinary();
-            if (_comment) {
-                _comment.copy(mh, Utils.Constants.ENDHDR); // add zip file comment
-            }
-
-            mh.copy(outBuffer, dindex); // write main header
-
-            return outBuffer
-        },
-
-        toAsyncBuffer : function(/*Function*/onSuccess,/*Function*/onFail,/*Function*/onItemStart,/*Function*/onItemEnd) {
-            if (entryList.length > 1) {
-                entryList.sort(function(a, b) {
-                    var nameA = a.entryName.toLowerCase();
-                    var nameB = b.entryName.toLowerCase();
-                    if (nameA > nameB) {return -1}
-                    if (nameA < nameB) {return 1}
-                    return 0;
-                });
-            }
-
-            var totalSize = 0,
-                dataBlock = [],
-                entryHeaders = [],
-                dindex = 0;
-
-            mainHeader.size = 0;
-            mainHeader.offset = 0;
-
-            var compress=function(entryList){
-                var self=arguments.callee;
-                var entry;
-                if(entryList.length){
-                    var entry=entryList.pop();
-                    var name=entry.entryName + entry.extra.toString();
-                    if(onItemStart)onItemStart(name);
-                    entry.getCompressedDataAsync(function(compressedData){
-                        if(onItemEnd)onItemEnd(name);
-
-                        entry.header.offset = dindex;
-                        // data header
-                        var dataHeader = entry.header.dataHeaderToBinary();
-                        var postHeader = new Buffer(name);
-                        var dataLength = dataHeader.length + postHeader.length + compressedData.length;
-
-                        dindex += dataLength;
-
-                        dataBlock.push(dataHeader);
-                        dataBlock.push(postHeader);
-                        dataBlock.push(compressedData);
-
-                        var entryHeader = entry.packHeader();
-                        entryHeaders.push(entryHeader);
-                        mainHeader.size += entryHeader.length;
-                        totalSize += (dataLength + entryHeader.length);
-
-                        if(entryList.length){
-                            self(entryList);
-                        }else{
-
-
-                            totalSize += mainHeader.mainHeaderSize; // also includes zip file comment length
-                            // point to end of data and begining of central directory first record
-                            mainHeader.offset = dindex;
-
-                            dindex = 0;
-                            var outBuffer = new Buffer(totalSize);
-                            dataBlock.forEach(function(content) {
-                                content.copy(outBuffer, dindex); // write data blocks
-                                dindex += content.length;
-                            });
-                            entryHeaders.forEach(function(content) {
-                                content.copy(outBuffer, dindex); // write central directory entries
-                                dindex += content.length;
-                            });
-
-                            var mh = mainHeader.toBinary();
-                            if (_comment) {
-                                _comment.copy(mh, Utils.Constants.ENDHDR); // add zip file comment
-                            }
-
-                            mh.copy(outBuffer, dindex); // write main header
-
-                            onSuccess(outBuffer);
-                        }
-                    });
-                }
-            };
-
-            compress(entryList);
-        }
-    }
-};
diff --git a/node_modules/big-integer/BigInteger.js b/node_modules/big-integer/BigInteger.js
index 56e3792..8ba8843 100644
--- a/node_modules/big-integer/BigInteger.js
+++ b/node_modules/big-integer/BigInteger.js
@@ -1143,11 +1143,13 @@
         var sign = this.sign ? "-" : "";
         return sign + str;
     };
+
     SmallInteger.prototype.toString = function (radix) {
         if (radix === undefined) radix = 10;
         if (radix != 10) return toBase(this, radix);
         return String(this.value);
     };
+    BigInteger.prototype.toJSON = SmallInteger.prototype.toJSON = function() { return this.toString(); }
 
     BigInteger.prototype.valueOf = function () {
         return +this.toString();
diff --git a/node_modules/big-integer/BigInteger.min.js b/node_modules/big-integer/BigInteger.min.js
index 8ee9a89..99ea9fb 100644
--- a/node_modules/big-integer/BigInteger.min.js
+++ b/node_modules/big-integer/BigInteger.min.js
@@ -1 +1 @@
-var bigInt=function(undefined){"use strict";var BASE=1e7,LOG_BASE=7,MAX_INT=9007199254740992,MAX_INT_ARR=smallToArray(MAX_INT),LOG_MAX_INT=Math.log(MAX_INT);function Integer(v,radix){if(typeof v==="undefined")return Integer[0];if(typeof radix!=="undefined")return+radix===10?parseValue(v):parseBase(v,radix);return parseValue(v)}function BigInteger(value,sign){this.value=value;this.sign=sign;this.isSmall=false}BigInteger.prototype=Object.create(Integer.prototype);function SmallInteger(value){this.value=value;this.sign=value<0;this.isSmall=true}SmallInteger.prototype=Object.create(Integer.prototype);function isPrecise(n){return-MAX_INT<n&&n<MAX_INT}function smallToArray(n){if(n<1e7)return[n];if(n<1e14)return[n%1e7,Math.floor(n/1e7)];return[n%1e7,Math.floor(n/1e7)%1e7,Math.floor(n/1e14)]}function arrayToSmall(arr){trim(arr);var length=arr.length;if(length<4&&compareAbs(arr,MAX_INT_ARR)<0){switch(length){case 0:return 0;case 1:return arr[0];case 2:return arr[0]+arr[1]*BASE;default:return arr[0]+(arr[1]+arr[2]*BASE)*BASE}}return arr}function trim(v){var i=v.length;while(v[--i]===0);v.length=i+1}function createArray(length){var x=new Array(length);var i=-1;while(++i<length){x[i]=0}return x}function truncate(n){if(n>0)return Math.floor(n);return Math.ceil(n)}function add(a,b){var l_a=a.length,l_b=b.length,r=new Array(l_a),carry=0,base=BASE,sum,i;for(i=0;i<l_b;i++){sum=a[i]+b[i]+carry;carry=sum>=base?1:0;r[i]=sum-carry*base}while(i<l_a){sum=a[i]+carry;carry=sum===base?1:0;r[i++]=sum-carry*base}if(carry>0)r.push(carry);return r}function addAny(a,b){if(a.length>=b.length)return add(a,b);return add(b,a)}function addSmall(a,carry){var l=a.length,r=new Array(l),base=BASE,sum,i;for(i=0;i<l;i++){sum=a[i]-base+carry;carry=Math.floor(sum/base);r[i]=sum-carry*base;carry+=1}while(carry>0){r[i++]=carry%base;carry=Math.floor(carry/base)}return r}BigInteger.prototype.add=function(v){var n=parseValue(v);if(this.sign!==n.sign){return this.subtract(n.negate())}var a=this.value,b=n.value;if(n.isSmall){return new BigInteger(addSmall(a,Math.abs(b)),this.sign)}return new BigInteger(addAny(a,b),this.sign)};BigInteger.prototype.plus=BigInteger.prototype.add;SmallInteger.prototype.add=function(v){var n=parseValue(v);var a=this.value;if(a<0!==n.sign){return this.subtract(n.negate())}var b=n.value;if(n.isSmall){if(isPrecise(a+b))return new SmallInteger(a+b);b=smallToArray(Math.abs(b))}return new BigInteger(addSmall(b,Math.abs(a)),a<0)};SmallInteger.prototype.plus=SmallInteger.prototype.add;function subtract(a,b){var a_l=a.length,b_l=b.length,r=new Array(a_l),borrow=0,base=BASE,i,difference;for(i=0;i<b_l;i++){difference=a[i]-borrow-b[i];if(difference<0){difference+=base;borrow=1}else borrow=0;r[i]=difference}for(i=b_l;i<a_l;i++){difference=a[i]-borrow;if(difference<0)difference+=base;else{r[i++]=difference;break}r[i]=difference}for(;i<a_l;i++){r[i]=a[i]}trim(r);return r}function subtractAny(a,b,sign){var value;if(compareAbs(a,b)>=0){value=subtract(a,b)}else{value=subtract(b,a);sign=!sign}value=arrayToSmall(value);if(typeof value==="number"){if(sign)value=-value;return new SmallInteger(value)}return new BigInteger(value,sign)}function subtractSmall(a,b,sign){var l=a.length,r=new Array(l),carry=-b,base=BASE,i,difference;for(i=0;i<l;i++){difference=a[i]+carry;carry=Math.floor(difference/base);difference%=base;r[i]=difference<0?difference+base:difference}r=arrayToSmall(r);if(typeof r==="number"){if(sign)r=-r;return new SmallInteger(r)}return new BigInteger(r,sign)}BigInteger.prototype.subtract=function(v){var n=parseValue(v);if(this.sign!==n.sign){return this.add(n.negate())}var a=this.value,b=n.value;if(n.isSmall)return subtractSmall(a,Math.abs(b),this.sign);return subtractAny(a,b,this.sign)};BigInteger.prototype.minus=BigInteger.prototype.subtract;SmallInteger.prototype.subtract=function(v){var n=parseValue(v);var a=this.value;if(a<0!==n.sign){return this.add(n.negate())}var b=n.value;if(n.isSmall){return new SmallInteger(a-b)}return subtractSmall(b,Math.abs(a),a>=0)};SmallInteger.prototype.minus=SmallInteger.prototype.subtract;BigInteger.prototype.negate=function(){return new BigInteger(this.value,!this.sign)};SmallInteger.prototype.negate=function(){var sign=this.sign;var small=new SmallInteger(-this.value);small.sign=!sign;return small};BigInteger.prototype.abs=function(){return new BigInteger(this.value,false)};SmallInteger.prototype.abs=function(){return new SmallInteger(Math.abs(this.value))};function multiplyLong(a,b){var a_l=a.length,b_l=b.length,l=a_l+b_l,r=createArray(l),base=BASE,product,carry,i,a_i,b_j;for(i=0;i<a_l;++i){a_i=a[i];for(var j=0;j<b_l;++j){b_j=b[j];product=a_i*b_j+r[i+j];carry=Math.floor(product/base);r[i+j]=product-carry*base;r[i+j+1]+=carry}}trim(r);return r}function multiplySmall(a,b){var l=a.length,r=new Array(l),base=BASE,carry=0,product,i;for(i=0;i<l;i++){product=a[i]*b+carry;carry=Math.floor(product/base);r[i]=product-carry*base}while(carry>0){r[i++]=carry%base;carry=Math.floor(carry/base)}return r}function shiftLeft(x,n){var r=[];while(n-- >0)r.push(0);return r.concat(x)}function multiplyKaratsuba(x,y){var n=Math.max(x.length,y.length);if(n<=30)return multiplyLong(x,y);n=Math.ceil(n/2);var b=x.slice(n),a=x.slice(0,n),d=y.slice(n),c=y.slice(0,n);var ac=multiplyKaratsuba(a,c),bd=multiplyKaratsuba(b,d),abcd=multiplyKaratsuba(addAny(a,b),addAny(c,d));var product=addAny(addAny(ac,shiftLeft(subtract(subtract(abcd,ac),bd),n)),shiftLeft(bd,2*n));trim(product);return product}function useKaratsuba(l1,l2){return-.012*l1-.012*l2+15e-6*l1*l2>0}BigInteger.prototype.multiply=function(v){var n=parseValue(v),a=this.value,b=n.value,sign=this.sign!==n.sign,abs;if(n.isSmall){if(b===0)return Integer[0];if(b===1)return this;if(b===-1)return this.negate();abs=Math.abs(b);if(abs<BASE){return new BigInteger(multiplySmall(a,abs),sign)}b=smallToArray(abs)}if(useKaratsuba(a.length,b.length))return new BigInteger(multiplyKaratsuba(a,b),sign);return new BigInteger(multiplyLong(a,b),sign)};BigInteger.prototype.times=BigInteger.prototype.multiply;function multiplySmallAndArray(a,b,sign){if(a<BASE){return new BigInteger(multiplySmall(b,a),sign)}return new BigInteger(multiplyLong(b,smallToArray(a)),sign)}SmallInteger.prototype._multiplyBySmall=function(a){if(isPrecise(a.value*this.value)){return new SmallInteger(a.value*this.value)}return multiplySmallAndArray(Math.abs(a.value),smallToArray(Math.abs(this.value)),this.sign!==a.sign)};BigInteger.prototype._multiplyBySmall=function(a){if(a.value===0)return Integer[0];if(a.value===1)return this;if(a.value===-1)return this.negate();return multiplySmallAndArray(Math.abs(a.value),this.value,this.sign!==a.sign)};SmallInteger.prototype.multiply=function(v){return parseValue(v)._multiplyBySmall(this)};SmallInteger.prototype.times=SmallInteger.prototype.multiply;function square(a){var l=a.length,r=createArray(l+l),base=BASE,product,carry,i,a_i,a_j;for(i=0;i<l;i++){a_i=a[i];for(var j=0;j<l;j++){a_j=a[j];product=a_i*a_j+r[i+j];carry=Math.floor(product/base);r[i+j]=product-carry*base;r[i+j+1]+=carry}}trim(r);return r}BigInteger.prototype.square=function(){return new BigInteger(square(this.value),false)};SmallInteger.prototype.square=function(){var value=this.value*this.value;if(isPrecise(value))return new SmallInteger(value);return new BigInteger(square(smallToArray(Math.abs(this.value))),false)};function divMod1(a,b){var a_l=a.length,b_l=b.length,base=BASE,result=createArray(b.length),divisorMostSignificantDigit=b[b_l-1],lambda=Math.ceil(base/(2*divisorMostSignificantDigit)),remainder=multiplySmall(a,lambda),divisor=multiplySmall(b,lambda),quotientDigit,shift,carry,borrow,i,l,q;if(remainder.length<=a_l)remainder.push(0);divisor.push(0);divisorMostSignificantDigit=divisor[b_l-1];for(shift=a_l-b_l;shift>=0;shift--){quotientDigit=base-1;if(remainder[shift+b_l]!==divisorMostSignificantDigit){quotientDigit=Math.floor((remainder[shift+b_l]*base+remainder[shift+b_l-1])/divisorMostSignificantDigit)}carry=0;borrow=0;l=divisor.length;for(i=0;i<l;i++){carry+=quotientDigit*divisor[i];q=Math.floor(carry/base);borrow+=remainder[shift+i]-(carry-q*base);carry=q;if(borrow<0){remainder[shift+i]=borrow+base;borrow=-1}else{remainder[shift+i]=borrow;borrow=0}}while(borrow!==0){quotientDigit-=1;carry=0;for(i=0;i<l;i++){carry+=remainder[shift+i]-base+divisor[i];if(carry<0){remainder[shift+i]=carry+base;carry=0}else{remainder[shift+i]=carry;carry=1}}borrow+=carry}result[shift]=quotientDigit}remainder=divModSmall(remainder,lambda)[0];return[arrayToSmall(result),arrayToSmall(remainder)]}function divMod2(a,b){var a_l=a.length,b_l=b.length,result=[],part=[],base=BASE,guess,xlen,highx,highy,check;while(a_l){part.unshift(a[--a_l]);trim(part);if(compareAbs(part,b)<0){result.push(0);continue}xlen=part.length;highx=part[xlen-1]*base+part[xlen-2];highy=b[b_l-1]*base+b[b_l-2];if(xlen>b_l){highx=(highx+1)*base}guess=Math.ceil(highx/highy);do{check=multiplySmall(b,guess);if(compareAbs(check,part)<=0)break;guess--}while(guess);result.push(guess);part=subtract(part,check)}result.reverse();return[arrayToSmall(result),arrayToSmall(part)]}function divModSmall(value,lambda){var length=value.length,quotient=createArray(length),base=BASE,i,q,remainder,divisor;remainder=0;for(i=length-1;i>=0;--i){divisor=remainder*base+value[i];q=truncate(divisor/lambda);remainder=divisor-q*lambda;quotient[i]=q|0}return[quotient,remainder|0]}function divModAny(self,v){var value,n=parseValue(v);var a=self.value,b=n.value;var quotient;if(b===0)throw new Error("Cannot divide by zero");if(self.isSmall){if(n.isSmall){return[new SmallInteger(truncate(a/b)),new SmallInteger(a%b)]}return[Integer[0],self]}if(n.isSmall){if(b===1)return[self,Integer[0]];if(b==-1)return[self.negate(),Integer[0]];var abs=Math.abs(b);if(abs<BASE){value=divModSmall(a,abs);quotient=arrayToSmall(value[0]);var remainder=value[1];if(self.sign)remainder=-remainder;if(typeof quotient==="number"){if(self.sign!==n.sign)quotient=-quotient;return[new SmallInteger(quotient),new SmallInteger(remainder)]}return[new BigInteger(quotient,self.sign!==n.sign),new SmallInteger(remainder)]}b=smallToArray(abs)}var comparison=compareAbs(a,b);if(comparison===-1)return[Integer[0],self];if(comparison===0)return[Integer[self.sign===n.sign?1:-1],Integer[0]];if(a.length+b.length<=200)value=divMod1(a,b);else value=divMod2(a,b);quotient=value[0];var qSign=self.sign!==n.sign,mod=value[1],mSign=self.sign;if(typeof quotient==="number"){if(qSign)quotient=-quotient;quotient=new SmallInteger(quotient)}else quotient=new BigInteger(quotient,qSign);if(typeof mod==="number"){if(mSign)mod=-mod;mod=new SmallInteger(mod)}else mod=new BigInteger(mod,mSign);return[quotient,mod]}BigInteger.prototype.divmod=function(v){var result=divModAny(this,v);return{quotient:result[0],remainder:result[1]}};SmallInteger.prototype.divmod=BigInteger.prototype.divmod;BigInteger.prototype.divide=function(v){return divModAny(this,v)[0]};SmallInteger.prototype.over=SmallInteger.prototype.divide=BigInteger.prototype.over=BigInteger.prototype.divide;BigInteger.prototype.mod=function(v){return divModAny(this,v)[1]};SmallInteger.prototype.remainder=SmallInteger.prototype.mod=BigInteger.prototype.remainder=BigInteger.prototype.mod;BigInteger.prototype.pow=function(v){var n=parseValue(v),a=this.value,b=n.value,value,x,y;if(b===0)return Integer[1];if(a===0)return Integer[0];if(a===1)return Integer[1];if(a===-1)return n.isEven()?Integer[1]:Integer[-1];if(n.sign){return Integer[0]}if(!n.isSmall)throw new Error("The exponent "+n.toString()+" is too large.");if(this.isSmall){if(isPrecise(value=Math.pow(a,b)))return new SmallInteger(truncate(value))}x=this;y=Integer[1];while(true){if(b&1===1){y=y.times(x);--b}if(b===0)break;b/=2;x=x.square()}return y};SmallInteger.prototype.pow=BigInteger.prototype.pow;BigInteger.prototype.modPow=function(exp,mod){exp=parseValue(exp);mod=parseValue(mod);if(mod.isZero())throw new Error("Cannot take modPow with modulus 0");var r=Integer[1],base=this.mod(mod);while(exp.isPositive()){if(base.isZero())return Integer[0];if(exp.isOdd())r=r.multiply(base).mod(mod);exp=exp.divide(2);base=base.square().mod(mod)}return r};SmallInteger.prototype.modPow=BigInteger.prototype.modPow;function compareAbs(a,b){if(a.length!==b.length){return a.length>b.length?1:-1}for(var i=a.length-1;i>=0;i--){if(a[i]!==b[i])return a[i]>b[i]?1:-1}return 0}BigInteger.prototype.compareAbs=function(v){var n=parseValue(v),a=this.value,b=n.value;if(n.isSmall)return 1;return compareAbs(a,b)};SmallInteger.prototype.compareAbs=function(v){var n=parseValue(v),a=Math.abs(this.value),b=n.value;if(n.isSmall){b=Math.abs(b);return a===b?0:a>b?1:-1}return-1};BigInteger.prototype.compare=function(v){if(v===Infinity){return-1}if(v===-Infinity){return 1}var n=parseValue(v),a=this.value,b=n.value;if(this.sign!==n.sign){return n.sign?1:-1}if(n.isSmall){return this.sign?-1:1}return compareAbs(a,b)*(this.sign?-1:1)};BigInteger.prototype.compareTo=BigInteger.prototype.compare;SmallInteger.prototype.compare=function(v){if(v===Infinity){return-1}if(v===-Infinity){return 1}var n=parseValue(v),a=this.value,b=n.value;if(n.isSmall){return a==b?0:a>b?1:-1}if(a<0!==n.sign){return a<0?-1:1}return a<0?1:-1};SmallInteger.prototype.compareTo=SmallInteger.prototype.compare;BigInteger.prototype.equals=function(v){return this.compare(v)===0};SmallInteger.prototype.eq=SmallInteger.prototype.equals=BigInteger.prototype.eq=BigInteger.prototype.equals;BigInteger.prototype.notEquals=function(v){return this.compare(v)!==0};SmallInteger.prototype.neq=SmallInteger.prototype.notEquals=BigInteger.prototype.neq=BigInteger.prototype.notEquals;BigInteger.prototype.greater=function(v){return this.compare(v)>0};SmallInteger.prototype.gt=SmallInteger.prototype.greater=BigInteger.prototype.gt=BigInteger.prototype.greater;BigInteger.prototype.lesser=function(v){return this.compare(v)<0};SmallInteger.prototype.lt=SmallInteger.prototype.lesser=BigInteger.prototype.lt=BigInteger.prototype.lesser;BigInteger.prototype.greaterOrEquals=function(v){return this.compare(v)>=0};SmallInteger.prototype.geq=SmallInteger.prototype.greaterOrEquals=BigInteger.prototype.geq=BigInteger.prototype.greaterOrEquals;BigInteger.prototype.lesserOrEquals=function(v){return this.compare(v)<=0};SmallInteger.prototype.leq=SmallInteger.prototype.lesserOrEquals=BigInteger.prototype.leq=BigInteger.prototype.lesserOrEquals;BigInteger.prototype.isEven=function(){return(this.value[0]&1)===0};SmallInteger.prototype.isEven=function(){return(this.value&1)===0};BigInteger.prototype.isOdd=function(){return(this.value[0]&1)===1};SmallInteger.prototype.isOdd=function(){return(this.value&1)===1};BigInteger.prototype.isPositive=function(){return!this.sign};SmallInteger.prototype.isPositive=function(){return this.value>0};BigInteger.prototype.isNegative=function(){return this.sign};SmallInteger.prototype.isNegative=function(){return this.value<0};BigInteger.prototype.isUnit=function(){return false};SmallInteger.prototype.isUnit=function(){return Math.abs(this.value)===1};BigInteger.prototype.isZero=function(){return false};SmallInteger.prototype.isZero=function(){return this.value===0};BigInteger.prototype.isDivisibleBy=function(v){var n=parseValue(v);var value=n.value;if(value===0)return false;if(value===1)return true;if(value===2)return this.isEven();return this.mod(n).equals(Integer[0])};SmallInteger.prototype.isDivisibleBy=BigInteger.prototype.isDivisibleBy;function isBasicPrime(v){var n=v.abs();if(n.isUnit())return false;if(n.equals(2)||n.equals(3)||n.equals(5))return true;if(n.isEven()||n.isDivisibleBy(3)||n.isDivisibleBy(5))return false;if(n.lesser(25))return true}BigInteger.prototype.isPrime=function(){var isPrime=isBasicPrime(this);if(isPrime!==undefined)return isPrime;var n=this.abs(),nPrev=n.prev();var a=[2,3,5,7,11,13,17,19],b=nPrev,d,t,i,x;while(b.isEven())b=b.divide(2);for(i=0;i<a.length;i++){x=bigInt(a[i]).modPow(b,n);if(x.equals(Integer[1])||x.equals(nPrev))continue;for(t=true,d=b;t&&d.lesser(nPrev);d=d.multiply(2)){x=x.square().mod(n);if(x.equals(nPrev))t=false}if(t)return false}return true};SmallInteger.prototype.isPrime=BigInteger.prototype.isPrime;BigInteger.prototype.isProbablePrime=function(iterations){var isPrime=isBasicPrime(this);if(isPrime!==undefined)return isPrime;var n=this.abs();var t=iterations===undefined?5:iterations;for(var i=0;i<t;i++){var a=bigInt.randBetween(2,n.minus(2));if(!a.modPow(n.prev(),n).isUnit())return false}return true};SmallInteger.prototype.isProbablePrime=BigInteger.prototype.isProbablePrime;BigInteger.prototype.modInv=function(n){var t=bigInt.zero,newT=bigInt.one,r=parseValue(n),newR=this.abs(),q,lastT,lastR;while(!newR.equals(bigInt.zero)){q=r.divide(newR);lastT=t;lastR=r;t=newT;r=newR;newT=lastT.subtract(q.multiply(newT));newR=lastR.subtract(q.multiply(newR))}if(!r.equals(1))throw new Error(this.toString()+" and "+n.toString()+" are not co-prime");if(t.compare(0)===-1){t=t.add(n)}if(this.isNegative()){return t.negate()}return t};SmallInteger.prototype.modInv=BigInteger.prototype.modInv;BigInteger.prototype.next=function(){var value=this.value;if(this.sign){return subtractSmall(value,1,this.sign)}return new BigInteger(addSmall(value,1),this.sign)};SmallInteger.prototype.next=function(){var value=this.value;if(value+1<MAX_INT)return new SmallInteger(value+1);return new BigInteger(MAX_INT_ARR,false)};BigInteger.prototype.prev=function(){var value=this.value;if(this.sign){return new BigInteger(addSmall(value,1),true)}return subtractSmall(value,1,this.sign)};SmallInteger.prototype.prev=function(){var value=this.value;if(value-1>-MAX_INT)return new SmallInteger(value-1);return new BigInteger(MAX_INT_ARR,true)};var powersOfTwo=[1];while(powersOfTwo[powersOfTwo.length-1]<=BASE)powersOfTwo.push(2*powersOfTwo[powersOfTwo.length-1]);var powers2Length=powersOfTwo.length,highestPower2=powersOfTwo[powers2Length-1];function shift_isSmall(n){return(typeof n==="number"||typeof n==="string")&&+Math.abs(n)<=BASE||n instanceof BigInteger&&n.value.length<=1}BigInteger.prototype.shiftLeft=function(n){if(!shift_isSmall(n)){throw new Error(String(n)+" is too large for shifting.")}n=+n;if(n<0)return this.shiftRight(-n);var result=this;while(n>=powers2Length){result=result.multiply(highestPower2);n-=powers2Length-1}return result.multiply(powersOfTwo[n])};SmallInteger.prototype.shiftLeft=BigInteger.prototype.shiftLeft;BigInteger.prototype.shiftRight=function(n){var remQuo;if(!shift_isSmall(n)){throw new Error(String(n)+" is too large for shifting.")}n=+n;if(n<0)return this.shiftLeft(-n);var result=this;while(n>=powers2Length){if(result.isZero())return result;remQuo=divModAny(result,highestPower2);result=remQuo[1].isNegative()?remQuo[0].prev():remQuo[0];n-=powers2Length-1}remQuo=divModAny(result,powersOfTwo[n]);return remQuo[1].isNegative()?remQuo[0].prev():remQuo[0]};SmallInteger.prototype.shiftRight=BigInteger.prototype.shiftRight;function bitwise(x,y,fn){y=parseValue(y);var xSign=x.isNegative(),ySign=y.isNegative();var xRem=xSign?x.not():x,yRem=ySign?y.not():y;var xBits=[],yBits=[];var xStop=false,yStop=false;while(!xStop||!yStop){if(xRem.isZero()){xStop=true;xBits.push(xSign?1:0)}else if(xSign)xBits.push(xRem.isEven()?1:0);else xBits.push(xRem.isEven()?0:1);if(yRem.isZero()){yStop=true;yBits.push(ySign?1:0)}else if(ySign)yBits.push(yRem.isEven()?1:0);else yBits.push(yRem.isEven()?0:1);xRem=xRem.over(2);yRem=yRem.over(2)}var result=[];for(var i=0;i<xBits.length;i++)result.push(fn(xBits[i],yBits[i]));var sum=bigInt(result.pop()).negate().times(bigInt(2).pow(result.length));while(result.length){sum=sum.add(bigInt(result.pop()).times(bigInt(2).pow(result.length)))}return sum}BigInteger.prototype.not=function(){return this.negate().prev()};SmallInteger.prototype.not=BigInteger.prototype.not;BigInteger.prototype.and=function(n){return bitwise(this,n,function(a,b){return a&b})};SmallInteger.prototype.and=BigInteger.prototype.and;BigInteger.prototype.or=function(n){return bitwise(this,n,function(a,b){return a|b})};SmallInteger.prototype.or=BigInteger.prototype.or;BigInteger.prototype.xor=function(n){return bitwise(this,n,function(a,b){return a^b})};SmallInteger.prototype.xor=BigInteger.prototype.xor;var LOBMASK_I=1<<30,LOBMASK_BI=(BASE&-BASE)*(BASE&-BASE)|LOBMASK_I;function roughLOB(n){var v=n.value,x=typeof v==="number"?v|LOBMASK_I:v[0]+v[1]*BASE|LOBMASK_BI;return x&-x}function max(a,b){a=parseValue(a);b=parseValue(b);return a.greater(b)?a:b}function min(a,b){a=parseValue(a);b=parseValue(b);return a.lesser(b)?a:b}function gcd(a,b){a=parseValue(a).abs();b=parseValue(b).abs();if(a.equals(b))return a;if(a.isZero())return b;if(b.isZero())return a;var c=Integer[1],d,t;while(a.isEven()&&b.isEven()){d=Math.min(roughLOB(a),roughLOB(b));a=a.divide(d);b=b.divide(d);c=c.multiply(d)}while(a.isEven()){a=a.divide(roughLOB(a))}do{while(b.isEven()){b=b.divide(roughLOB(b))}if(a.greater(b)){t=b;b=a;a=t}b=b.subtract(a)}while(!b.isZero());return c.isUnit()?a:a.multiply(c)}function lcm(a,b){a=parseValue(a).abs();b=parseValue(b).abs();return a.divide(gcd(a,b)).multiply(b)}function randBetween(a,b){a=parseValue(a);b=parseValue(b);var low=min(a,b),high=max(a,b);var range=high.subtract(low);if(range.isSmall)return low.add(Math.round(Math.random()*range));var length=range.value.length-1;var result=[],restricted=true;for(var i=length;i>=0;i--){var top=restricted?range.value[i]:BASE;var digit=truncate(Math.random()*top);result.unshift(digit);if(digit<top)restricted=false}result=arrayToSmall(result);return low.add(typeof result==="number"?new SmallInteger(result):new BigInteger(result,false))}var parseBase=function(text,base){var length=text.length;var i;var absBase=Math.abs(base);for(var i=0;i<length;i++){var c=text[i].toLowerCase();if(c==="-")continue;if(/[a-z0-9]/.test(c)){if(/[0-9]/.test(c)&&+c>=absBase){if(c==="1"&&absBase===1)continue;throw new Error(c+" is not a valid digit in base "+base+".")}else if(c.charCodeAt(0)-87>=absBase){throw new Error(c+" is not a valid digit in base "+base+".")}}}if(2<=base&&base<=36){if(length<=LOG_MAX_INT/Math.log(base)){var result=parseInt(text,base);if(isNaN(result)){throw new Error(c+" is not a valid digit in base "+base+".")}return new SmallInteger(parseInt(text,base))}}base=parseValue(base);var digits=[];var isNegative=text[0]==="-";for(i=isNegative?1:0;i<text.length;i++){var c=text[i].toLowerCase(),charCode=c.charCodeAt(0);if(48<=charCode&&charCode<=57)digits.push(parseValue(c));else if(97<=charCode&&charCode<=122)digits.push(parseValue(c.charCodeAt(0)-87));else if(c==="<"){var start=i;do{i++}while(text[i]!==">");digits.push(parseValue(text.slice(start+1,i)))}else throw new Error(c+" is not a valid character")}return parseBaseFromArray(digits,base,isNegative)};function parseBaseFromArray(digits,base,isNegative){var val=Integer[0],pow=Integer[1],i;for(i=digits.length-1;i>=0;i--){val=val.add(digits[i].times(pow));pow=pow.times(base)}return isNegative?val.negate():val}function stringify(digit){var v=digit.value;if(typeof v==="number")v=[v];if(v.length===1&&v[0]<=35){return"0123456789abcdefghijklmnopqrstuvwxyz".charAt(v[0])}return"<"+v+">"}function toBase(n,base){base=bigInt(base);if(base.isZero()){if(n.isZero())return"0";throw new Error("Cannot convert nonzero numbers to base 0.")}if(base.equals(-1)){if(n.isZero())return"0";if(n.isNegative())return new Array(1-n).join("10");return"1"+new Array(+n).join("01")}var minusSign="";if(n.isNegative()&&base.isPositive()){minusSign="-";n=n.abs()}if(base.equals(1)){if(n.isZero())return"0";return minusSign+new Array(+n+1).join(1)}var out=[];var left=n,divmod;while(left.isNegative()||left.compareAbs(base)>=0){divmod=left.divmod(base);left=divmod.quotient;var digit=divmod.remainder;if(digit.isNegative()){digit=base.minus(digit).abs();left=left.next()}out.push(stringify(digit))}out.push(stringify(left));return minusSign+out.reverse().join("")}BigInteger.prototype.toString=function(radix){if(radix===undefined)radix=10;if(radix!==10)return toBase(this,radix);var v=this.value,l=v.length,str=String(v[--l]),zeros="0000000",digit;while(--l>=0){digit=String(v[l]);str+=zeros.slice(digit.length)+digit}var sign=this.sign?"-":"";return sign+str};SmallInteger.prototype.toString=function(radix){if(radix===undefined)radix=10;if(radix!=10)return toBase(this,radix);return String(this.value)};BigInteger.prototype.valueOf=function(){return+this.toString()};BigInteger.prototype.toJSNumber=BigInteger.prototype.valueOf;SmallInteger.prototype.valueOf=function(){return this.value};SmallInteger.prototype.toJSNumber=SmallInteger.prototype.valueOf;function parseStringValue(v){if(isPrecise(+v)){var x=+v;if(x===truncate(x))return new SmallInteger(x);throw"Invalid integer: "+v}var sign=v[0]==="-";if(sign)v=v.slice(1);var split=v.split(/e/i);if(split.length>2)throw new Error("Invalid integer: "+split.join("e"));if(split.length===2){var exp=split[1];if(exp[0]==="+")exp=exp.slice(1);exp=+exp;if(exp!==truncate(exp)||!isPrecise(exp))throw new Error("Invalid integer: "+exp+" is not a valid exponent.");var text=split[0];var decimalPlace=text.indexOf(".");if(decimalPlace>=0){exp-=text.length-decimalPlace-1;text=text.slice(0,decimalPlace)+text.slice(decimalPlace+1)}if(exp<0)throw new Error("Cannot include negative exponent part for integers");text+=new Array(exp+1).join("0");v=text}var isValid=/^([0-9][0-9]*)$/.test(v);if(!isValid)throw new Error("Invalid integer: "+v);var r=[],max=v.length,l=LOG_BASE,min=max-l;while(max>0){r.push(+v.slice(min,max));min-=l;if(min<0)min=0;max-=l}trim(r);return new BigInteger(r,sign)}function parseNumberValue(v){if(isPrecise(v)){if(v!==truncate(v))throw new Error(v+" is not an integer.");return new SmallInteger(v)}return parseStringValue(v.toString())}function parseValue(v){if(typeof v==="number"){return parseNumberValue(v)}if(typeof v==="string"){return parseStringValue(v)}return v}for(var i=0;i<1e3;i++){Integer[i]=new SmallInteger(i);if(i>0)Integer[-i]=new SmallInteger(-i)}Integer.one=Integer[1];Integer.zero=Integer[0];Integer.minusOne=Integer[-1];Integer.max=max;Integer.min=min;Integer.gcd=gcd;Integer.lcm=lcm;Integer.isInstance=function(x){return x instanceof BigInteger||x instanceof SmallInteger};Integer.randBetween=randBetween;Integer.fromArray=function(digits,base,isNegative){return parseBaseFromArray(digits.map(parseValue),parseValue(base||10),isNegative)};return Integer}();if(typeof module!=="undefined"&&module.hasOwnProperty("exports")){module.exports=bigInt}if(typeof define==="function"&&define.amd){define("big-integer",[],function(){return bigInt})}
\ No newline at end of file
+var bigInt=function(undefined){"use strict";var BASE=1e7,LOG_BASE=7,MAX_INT=9007199254740992,MAX_INT_ARR=smallToArray(MAX_INT),LOG_MAX_INT=Math.log(MAX_INT);function Integer(v,radix){if(typeof v==="undefined")return Integer[0];if(typeof radix!=="undefined")return+radix===10?parseValue(v):parseBase(v,radix);return parseValue(v)}function BigInteger(value,sign){this.value=value;this.sign=sign;this.isSmall=false}BigInteger.prototype=Object.create(Integer.prototype);function SmallInteger(value){this.value=value;this.sign=value<0;this.isSmall=true}SmallInteger.prototype=Object.create(Integer.prototype);function isPrecise(n){return-MAX_INT<n&&n<MAX_INT}function smallToArray(n){if(n<1e7)return[n];if(n<1e14)return[n%1e7,Math.floor(n/1e7)];return[n%1e7,Math.floor(n/1e7)%1e7,Math.floor(n/1e14)]}function arrayToSmall(arr){trim(arr);var length=arr.length;if(length<4&&compareAbs(arr,MAX_INT_ARR)<0){switch(length){case 0:return 0;case 1:return arr[0];case 2:return arr[0]+arr[1]*BASE;default:return arr[0]+(arr[1]+arr[2]*BASE)*BASE}}return arr}function trim(v){var i=v.length;while(v[--i]===0);v.length=i+1}function createArray(length){var x=new Array(length);var i=-1;while(++i<length){x[i]=0}return x}function truncate(n){if(n>0)return Math.floor(n);return Math.ceil(n)}function add(a,b){var l_a=a.length,l_b=b.length,r=new Array(l_a),carry=0,base=BASE,sum,i;for(i=0;i<l_b;i++){sum=a[i]+b[i]+carry;carry=sum>=base?1:0;r[i]=sum-carry*base}while(i<l_a){sum=a[i]+carry;carry=sum===base?1:0;r[i++]=sum-carry*base}if(carry>0)r.push(carry);return r}function addAny(a,b){if(a.length>=b.length)return add(a,b);return add(b,a)}function addSmall(a,carry){var l=a.length,r=new Array(l),base=BASE,sum,i;for(i=0;i<l;i++){sum=a[i]-base+carry;carry=Math.floor(sum/base);r[i]=sum-carry*base;carry+=1}while(carry>0){r[i++]=carry%base;carry=Math.floor(carry/base)}return r}BigInteger.prototype.add=function(v){var n=parseValue(v);if(this.sign!==n.sign){return this.subtract(n.negate())}var a=this.value,b=n.value;if(n.isSmall){return new BigInteger(addSmall(a,Math.abs(b)),this.sign)}return new BigInteger(addAny(a,b),this.sign)};BigInteger.prototype.plus=BigInteger.prototype.add;SmallInteger.prototype.add=function(v){var n=parseValue(v);var a=this.value;if(a<0!==n.sign){return this.subtract(n.negate())}var b=n.value;if(n.isSmall){if(isPrecise(a+b))return new SmallInteger(a+b);b=smallToArray(Math.abs(b))}return new BigInteger(addSmall(b,Math.abs(a)),a<0)};SmallInteger.prototype.plus=SmallInteger.prototype.add;function subtract(a,b){var a_l=a.length,b_l=b.length,r=new Array(a_l),borrow=0,base=BASE,i,difference;for(i=0;i<b_l;i++){difference=a[i]-borrow-b[i];if(difference<0){difference+=base;borrow=1}else borrow=0;r[i]=difference}for(i=b_l;i<a_l;i++){difference=a[i]-borrow;if(difference<0)difference+=base;else{r[i++]=difference;break}r[i]=difference}for(;i<a_l;i++){r[i]=a[i]}trim(r);return r}function subtractAny(a,b,sign){var value;if(compareAbs(a,b)>=0){value=subtract(a,b)}else{value=subtract(b,a);sign=!sign}value=arrayToSmall(value);if(typeof value==="number"){if(sign)value=-value;return new SmallInteger(value)}return new BigInteger(value,sign)}function subtractSmall(a,b,sign){var l=a.length,r=new Array(l),carry=-b,base=BASE,i,difference;for(i=0;i<l;i++){difference=a[i]+carry;carry=Math.floor(difference/base);difference%=base;r[i]=difference<0?difference+base:difference}r=arrayToSmall(r);if(typeof r==="number"){if(sign)r=-r;return new SmallInteger(r)}return new BigInteger(r,sign)}BigInteger.prototype.subtract=function(v){var n=parseValue(v);if(this.sign!==n.sign){return this.add(n.negate())}var a=this.value,b=n.value;if(n.isSmall)return subtractSmall(a,Math.abs(b),this.sign);return subtractAny(a,b,this.sign)};BigInteger.prototype.minus=BigInteger.prototype.subtract;SmallInteger.prototype.subtract=function(v){var n=parseValue(v);var a=this.value;if(a<0!==n.sign){return this.add(n.negate())}var b=n.value;if(n.isSmall){return new SmallInteger(a-b)}return subtractSmall(b,Math.abs(a),a>=0)};SmallInteger.prototype.minus=SmallInteger.prototype.subtract;BigInteger.prototype.negate=function(){return new BigInteger(this.value,!this.sign)};SmallInteger.prototype.negate=function(){var sign=this.sign;var small=new SmallInteger(-this.value);small.sign=!sign;return small};BigInteger.prototype.abs=function(){return new BigInteger(this.value,false)};SmallInteger.prototype.abs=function(){return new SmallInteger(Math.abs(this.value))};function multiplyLong(a,b){var a_l=a.length,b_l=b.length,l=a_l+b_l,r=createArray(l),base=BASE,product,carry,i,a_i,b_j;for(i=0;i<a_l;++i){a_i=a[i];for(var j=0;j<b_l;++j){b_j=b[j];product=a_i*b_j+r[i+j];carry=Math.floor(product/base);r[i+j]=product-carry*base;r[i+j+1]+=carry}}trim(r);return r}function multiplySmall(a,b){var l=a.length,r=new Array(l),base=BASE,carry=0,product,i;for(i=0;i<l;i++){product=a[i]*b+carry;carry=Math.floor(product/base);r[i]=product-carry*base}while(carry>0){r[i++]=carry%base;carry=Math.floor(carry/base)}return r}function shiftLeft(x,n){var r=[];while(n-- >0)r.push(0);return r.concat(x)}function multiplyKaratsuba(x,y){var n=Math.max(x.length,y.length);if(n<=30)return multiplyLong(x,y);n=Math.ceil(n/2);var b=x.slice(n),a=x.slice(0,n),d=y.slice(n),c=y.slice(0,n);var ac=multiplyKaratsuba(a,c),bd=multiplyKaratsuba(b,d),abcd=multiplyKaratsuba(addAny(a,b),addAny(c,d));var product=addAny(addAny(ac,shiftLeft(subtract(subtract(abcd,ac),bd),n)),shiftLeft(bd,2*n));trim(product);return product}function useKaratsuba(l1,l2){return-.012*l1-.012*l2+15e-6*l1*l2>0}BigInteger.prototype.multiply=function(v){var n=parseValue(v),a=this.value,b=n.value,sign=this.sign!==n.sign,abs;if(n.isSmall){if(b===0)return Integer[0];if(b===1)return this;if(b===-1)return this.negate();abs=Math.abs(b);if(abs<BASE){return new BigInteger(multiplySmall(a,abs),sign)}b=smallToArray(abs)}if(useKaratsuba(a.length,b.length))return new BigInteger(multiplyKaratsuba(a,b),sign);return new BigInteger(multiplyLong(a,b),sign)};BigInteger.prototype.times=BigInteger.prototype.multiply;function multiplySmallAndArray(a,b,sign){if(a<BASE){return new BigInteger(multiplySmall(b,a),sign)}return new BigInteger(multiplyLong(b,smallToArray(a)),sign)}SmallInteger.prototype._multiplyBySmall=function(a){if(isPrecise(a.value*this.value)){return new SmallInteger(a.value*this.value)}return multiplySmallAndArray(Math.abs(a.value),smallToArray(Math.abs(this.value)),this.sign!==a.sign)};BigInteger.prototype._multiplyBySmall=function(a){if(a.value===0)return Integer[0];if(a.value===1)return this;if(a.value===-1)return this.negate();return multiplySmallAndArray(Math.abs(a.value),this.value,this.sign!==a.sign)};SmallInteger.prototype.multiply=function(v){return parseValue(v)._multiplyBySmall(this)};SmallInteger.prototype.times=SmallInteger.prototype.multiply;function square(a){var l=a.length,r=createArray(l+l),base=BASE,product,carry,i,a_i,a_j;for(i=0;i<l;i++){a_i=a[i];for(var j=0;j<l;j++){a_j=a[j];product=a_i*a_j+r[i+j];carry=Math.floor(product/base);r[i+j]=product-carry*base;r[i+j+1]+=carry}}trim(r);return r}BigInteger.prototype.square=function(){return new BigInteger(square(this.value),false)};SmallInteger.prototype.square=function(){var value=this.value*this.value;if(isPrecise(value))return new SmallInteger(value);return new BigInteger(square(smallToArray(Math.abs(this.value))),false)};function divMod1(a,b){var a_l=a.length,b_l=b.length,base=BASE,result=createArray(b.length),divisorMostSignificantDigit=b[b_l-1],lambda=Math.ceil(base/(2*divisorMostSignificantDigit)),remainder=multiplySmall(a,lambda),divisor=multiplySmall(b,lambda),quotientDigit,shift,carry,borrow,i,l,q;if(remainder.length<=a_l)remainder.push(0);divisor.push(0);divisorMostSignificantDigit=divisor[b_l-1];for(shift=a_l-b_l;shift>=0;shift--){quotientDigit=base-1;if(remainder[shift+b_l]!==divisorMostSignificantDigit){quotientDigit=Math.floor((remainder[shift+b_l]*base+remainder[shift+b_l-1])/divisorMostSignificantDigit)}carry=0;borrow=0;l=divisor.length;for(i=0;i<l;i++){carry+=quotientDigit*divisor[i];q=Math.floor(carry/base);borrow+=remainder[shift+i]-(carry-q*base);carry=q;if(borrow<0){remainder[shift+i]=borrow+base;borrow=-1}else{remainder[shift+i]=borrow;borrow=0}}while(borrow!==0){quotientDigit-=1;carry=0;for(i=0;i<l;i++){carry+=remainder[shift+i]-base+divisor[i];if(carry<0){remainder[shift+i]=carry+base;carry=0}else{remainder[shift+i]=carry;carry=1}}borrow+=carry}result[shift]=quotientDigit}remainder=divModSmall(remainder,lambda)[0];return[arrayToSmall(result),arrayToSmall(remainder)]}function divMod2(a,b){var a_l=a.length,b_l=b.length,result=[],part=[],base=BASE,guess,xlen,highx,highy,check;while(a_l){part.unshift(a[--a_l]);trim(part);if(compareAbs(part,b)<0){result.push(0);continue}xlen=part.length;highx=part[xlen-1]*base+part[xlen-2];highy=b[b_l-1]*base+b[b_l-2];if(xlen>b_l){highx=(highx+1)*base}guess=Math.ceil(highx/highy);do{check=multiplySmall(b,guess);if(compareAbs(check,part)<=0)break;guess--}while(guess);result.push(guess);part=subtract(part,check)}result.reverse();return[arrayToSmall(result),arrayToSmall(part)]}function divModSmall(value,lambda){var length=value.length,quotient=createArray(length),base=BASE,i,q,remainder,divisor;remainder=0;for(i=length-1;i>=0;--i){divisor=remainder*base+value[i];q=truncate(divisor/lambda);remainder=divisor-q*lambda;quotient[i]=q|0}return[quotient,remainder|0]}function divModAny(self,v){var value,n=parseValue(v);var a=self.value,b=n.value;var quotient;if(b===0)throw new Error("Cannot divide by zero");if(self.isSmall){if(n.isSmall){return[new SmallInteger(truncate(a/b)),new SmallInteger(a%b)]}return[Integer[0],self]}if(n.isSmall){if(b===1)return[self,Integer[0]];if(b==-1)return[self.negate(),Integer[0]];var abs=Math.abs(b);if(abs<BASE){value=divModSmall(a,abs);quotient=arrayToSmall(value[0]);var remainder=value[1];if(self.sign)remainder=-remainder;if(typeof quotient==="number"){if(self.sign!==n.sign)quotient=-quotient;return[new SmallInteger(quotient),new SmallInteger(remainder)]}return[new BigInteger(quotient,self.sign!==n.sign),new SmallInteger(remainder)]}b=smallToArray(abs)}var comparison=compareAbs(a,b);if(comparison===-1)return[Integer[0],self];if(comparison===0)return[Integer[self.sign===n.sign?1:-1],Integer[0]];if(a.length+b.length<=200)value=divMod1(a,b);else value=divMod2(a,b);quotient=value[0];var qSign=self.sign!==n.sign,mod=value[1],mSign=self.sign;if(typeof quotient==="number"){if(qSign)quotient=-quotient;quotient=new SmallInteger(quotient)}else quotient=new BigInteger(quotient,qSign);if(typeof mod==="number"){if(mSign)mod=-mod;mod=new SmallInteger(mod)}else mod=new BigInteger(mod,mSign);return[quotient,mod]}BigInteger.prototype.divmod=function(v){var result=divModAny(this,v);return{quotient:result[0],remainder:result[1]}};SmallInteger.prototype.divmod=BigInteger.prototype.divmod;BigInteger.prototype.divide=function(v){return divModAny(this,v)[0]};SmallInteger.prototype.over=SmallInteger.prototype.divide=BigInteger.prototype.over=BigInteger.prototype.divide;BigInteger.prototype.mod=function(v){return divModAny(this,v)[1]};SmallInteger.prototype.remainder=SmallInteger.prototype.mod=BigInteger.prototype.remainder=BigInteger.prototype.mod;BigInteger.prototype.pow=function(v){var n=parseValue(v),a=this.value,b=n.value,value,x,y;if(b===0)return Integer[1];if(a===0)return Integer[0];if(a===1)return Integer[1];if(a===-1)return n.isEven()?Integer[1]:Integer[-1];if(n.sign){return Integer[0]}if(!n.isSmall)throw new Error("The exponent "+n.toString()+" is too large.");if(this.isSmall){if(isPrecise(value=Math.pow(a,b)))return new SmallInteger(truncate(value))}x=this;y=Integer[1];while(true){if(b&1===1){y=y.times(x);--b}if(b===0)break;b/=2;x=x.square()}return y};SmallInteger.prototype.pow=BigInteger.prototype.pow;BigInteger.prototype.modPow=function(exp,mod){exp=parseValue(exp);mod=parseValue(mod);if(mod.isZero())throw new Error("Cannot take modPow with modulus 0");var r=Integer[1],base=this.mod(mod);while(exp.isPositive()){if(base.isZero())return Integer[0];if(exp.isOdd())r=r.multiply(base).mod(mod);exp=exp.divide(2);base=base.square().mod(mod)}return r};SmallInteger.prototype.modPow=BigInteger.prototype.modPow;function compareAbs(a,b){if(a.length!==b.length){return a.length>b.length?1:-1}for(var i=a.length-1;i>=0;i--){if(a[i]!==b[i])return a[i]>b[i]?1:-1}return 0}BigInteger.prototype.compareAbs=function(v){var n=parseValue(v),a=this.value,b=n.value;if(n.isSmall)return 1;return compareAbs(a,b)};SmallInteger.prototype.compareAbs=function(v){var n=parseValue(v),a=Math.abs(this.value),b=n.value;if(n.isSmall){b=Math.abs(b);return a===b?0:a>b?1:-1}return-1};BigInteger.prototype.compare=function(v){if(v===Infinity){return-1}if(v===-Infinity){return 1}var n=parseValue(v),a=this.value,b=n.value;if(this.sign!==n.sign){return n.sign?1:-1}if(n.isSmall){return this.sign?-1:1}return compareAbs(a,b)*(this.sign?-1:1)};BigInteger.prototype.compareTo=BigInteger.prototype.compare;SmallInteger.prototype.compare=function(v){if(v===Infinity){return-1}if(v===-Infinity){return 1}var n=parseValue(v),a=this.value,b=n.value;if(n.isSmall){return a==b?0:a>b?1:-1}if(a<0!==n.sign){return a<0?-1:1}return a<0?1:-1};SmallInteger.prototype.compareTo=SmallInteger.prototype.compare;BigInteger.prototype.equals=function(v){return this.compare(v)===0};SmallInteger.prototype.eq=SmallInteger.prototype.equals=BigInteger.prototype.eq=BigInteger.prototype.equals;BigInteger.prototype.notEquals=function(v){return this.compare(v)!==0};SmallInteger.prototype.neq=SmallInteger.prototype.notEquals=BigInteger.prototype.neq=BigInteger.prototype.notEquals;BigInteger.prototype.greater=function(v){return this.compare(v)>0};SmallInteger.prototype.gt=SmallInteger.prototype.greater=BigInteger.prototype.gt=BigInteger.prototype.greater;BigInteger.prototype.lesser=function(v){return this.compare(v)<0};SmallInteger.prototype.lt=SmallInteger.prototype.lesser=BigInteger.prototype.lt=BigInteger.prototype.lesser;BigInteger.prototype.greaterOrEquals=function(v){return this.compare(v)>=0};SmallInteger.prototype.geq=SmallInteger.prototype.greaterOrEquals=BigInteger.prototype.geq=BigInteger.prototype.greaterOrEquals;BigInteger.prototype.lesserOrEquals=function(v){return this.compare(v)<=0};SmallInteger.prototype.leq=SmallInteger.prototype.lesserOrEquals=BigInteger.prototype.leq=BigInteger.prototype.lesserOrEquals;BigInteger.prototype.isEven=function(){return(this.value[0]&1)===0};SmallInteger.prototype.isEven=function(){return(this.value&1)===0};BigInteger.prototype.isOdd=function(){return(this.value[0]&1)===1};SmallInteger.prototype.isOdd=function(){return(this.value&1)===1};BigInteger.prototype.isPositive=function(){return!this.sign};SmallInteger.prototype.isPositive=function(){return this.value>0};BigInteger.prototype.isNegative=function(){return this.sign};SmallInteger.prototype.isNegative=function(){return this.value<0};BigInteger.prototype.isUnit=function(){return false};SmallInteger.prototype.isUnit=function(){return Math.abs(this.value)===1};BigInteger.prototype.isZero=function(){return false};SmallInteger.prototype.isZero=function(){return this.value===0};BigInteger.prototype.isDivisibleBy=function(v){var n=parseValue(v);var value=n.value;if(value===0)return false;if(value===1)return true;if(value===2)return this.isEven();return this.mod(n).equals(Integer[0])};SmallInteger.prototype.isDivisibleBy=BigInteger.prototype.isDivisibleBy;function isBasicPrime(v){var n=v.abs();if(n.isUnit())return false;if(n.equals(2)||n.equals(3)||n.equals(5))return true;if(n.isEven()||n.isDivisibleBy(3)||n.isDivisibleBy(5))return false;if(n.lesser(25))return true}BigInteger.prototype.isPrime=function(){var isPrime=isBasicPrime(this);if(isPrime!==undefined)return isPrime;var n=this.abs(),nPrev=n.prev();var a=[2,3,5,7,11,13,17,19],b=nPrev,d,t,i,x;while(b.isEven())b=b.divide(2);for(i=0;i<a.length;i++){x=bigInt(a[i]).modPow(b,n);if(x.equals(Integer[1])||x.equals(nPrev))continue;for(t=true,d=b;t&&d.lesser(nPrev);d=d.multiply(2)){x=x.square().mod(n);if(x.equals(nPrev))t=false}if(t)return false}return true};SmallInteger.prototype.isPrime=BigInteger.prototype.isPrime;BigInteger.prototype.isProbablePrime=function(iterations){var isPrime=isBasicPrime(this);if(isPrime!==undefined)return isPrime;var n=this.abs();var t=iterations===undefined?5:iterations;for(var i=0;i<t;i++){var a=bigInt.randBetween(2,n.minus(2));if(!a.modPow(n.prev(),n).isUnit())return false}return true};SmallInteger.prototype.isProbablePrime=BigInteger.prototype.isProbablePrime;BigInteger.prototype.modInv=function(n){var t=bigInt.zero,newT=bigInt.one,r=parseValue(n),newR=this.abs(),q,lastT,lastR;while(!newR.equals(bigInt.zero)){q=r.divide(newR);lastT=t;lastR=r;t=newT;r=newR;newT=lastT.subtract(q.multiply(newT));newR=lastR.subtract(q.multiply(newR))}if(!r.equals(1))throw new Error(this.toString()+" and "+n.toString()+" are not co-prime");if(t.compare(0)===-1){t=t.add(n)}if(this.isNegative()){return t.negate()}return t};SmallInteger.prototype.modInv=BigInteger.prototype.modInv;BigInteger.prototype.next=function(){var value=this.value;if(this.sign){return subtractSmall(value,1,this.sign)}return new BigInteger(addSmall(value,1),this.sign)};SmallInteger.prototype.next=function(){var value=this.value;if(value+1<MAX_INT)return new SmallInteger(value+1);return new BigInteger(MAX_INT_ARR,false)};BigInteger.prototype.prev=function(){var value=this.value;if(this.sign){return new BigInteger(addSmall(value,1),true)}return subtractSmall(value,1,this.sign)};SmallInteger.prototype.prev=function(){var value=this.value;if(value-1>-MAX_INT)return new SmallInteger(value-1);return new BigInteger(MAX_INT_ARR,true)};var powersOfTwo=[1];while(powersOfTwo[powersOfTwo.length-1]<=BASE)powersOfTwo.push(2*powersOfTwo[powersOfTwo.length-1]);var powers2Length=powersOfTwo.length,highestPower2=powersOfTwo[powers2Length-1];function shift_isSmall(n){return(typeof n==="number"||typeof n==="string")&&+Math.abs(n)<=BASE||n instanceof BigInteger&&n.value.length<=1}BigInteger.prototype.shiftLeft=function(n){if(!shift_isSmall(n)){throw new Error(String(n)+" is too large for shifting.")}n=+n;if(n<0)return this.shiftRight(-n);var result=this;while(n>=powers2Length){result=result.multiply(highestPower2);n-=powers2Length-1}return result.multiply(powersOfTwo[n])};SmallInteger.prototype.shiftLeft=BigInteger.prototype.shiftLeft;BigInteger.prototype.shiftRight=function(n){var remQuo;if(!shift_isSmall(n)){throw new Error(String(n)+" is too large for shifting.")}n=+n;if(n<0)return this.shiftLeft(-n);var result=this;while(n>=powers2Length){if(result.isZero())return result;remQuo=divModAny(result,highestPower2);result=remQuo[1].isNegative()?remQuo[0].prev():remQuo[0];n-=powers2Length-1}remQuo=divModAny(result,powersOfTwo[n]);return remQuo[1].isNegative()?remQuo[0].prev():remQuo[0]};SmallInteger.prototype.shiftRight=BigInteger.prototype.shiftRight;function bitwise(x,y,fn){y=parseValue(y);var xSign=x.isNegative(),ySign=y.isNegative();var xRem=xSign?x.not():x,yRem=ySign?y.not():y;var xBits=[],yBits=[];var xStop=false,yStop=false;while(!xStop||!yStop){if(xRem.isZero()){xStop=true;xBits.push(xSign?1:0)}else if(xSign)xBits.push(xRem.isEven()?1:0);else xBits.push(xRem.isEven()?0:1);if(yRem.isZero()){yStop=true;yBits.push(ySign?1:0)}else if(ySign)yBits.push(yRem.isEven()?1:0);else yBits.push(yRem.isEven()?0:1);xRem=xRem.over(2);yRem=yRem.over(2)}var result=[];for(var i=0;i<xBits.length;i++)result.push(fn(xBits[i],yBits[i]));var sum=bigInt(result.pop()).negate().times(bigInt(2).pow(result.length));while(result.length){sum=sum.add(bigInt(result.pop()).times(bigInt(2).pow(result.length)))}return sum}BigInteger.prototype.not=function(){return this.negate().prev()};SmallInteger.prototype.not=BigInteger.prototype.not;BigInteger.prototype.and=function(n){return bitwise(this,n,function(a,b){return a&b})};SmallInteger.prototype.and=BigInteger.prototype.and;BigInteger.prototype.or=function(n){return bitwise(this,n,function(a,b){return a|b})};SmallInteger.prototype.or=BigInteger.prototype.or;BigInteger.prototype.xor=function(n){return bitwise(this,n,function(a,b){return a^b})};SmallInteger.prototype.xor=BigInteger.prototype.xor;var LOBMASK_I=1<<30,LOBMASK_BI=(BASE&-BASE)*(BASE&-BASE)|LOBMASK_I;function roughLOB(n){var v=n.value,x=typeof v==="number"?v|LOBMASK_I:v[0]+v[1]*BASE|LOBMASK_BI;return x&-x}function max(a,b){a=parseValue(a);b=parseValue(b);return a.greater(b)?a:b}function min(a,b){a=parseValue(a);b=parseValue(b);return a.lesser(b)?a:b}function gcd(a,b){a=parseValue(a).abs();b=parseValue(b).abs();if(a.equals(b))return a;if(a.isZero())return b;if(b.isZero())return a;var c=Integer[1],d,t;while(a.isEven()&&b.isEven()){d=Math.min(roughLOB(a),roughLOB(b));a=a.divide(d);b=b.divide(d);c=c.multiply(d)}while(a.isEven()){a=a.divide(roughLOB(a))}do{while(b.isEven()){b=b.divide(roughLOB(b))}if(a.greater(b)){t=b;b=a;a=t}b=b.subtract(a)}while(!b.isZero());return c.isUnit()?a:a.multiply(c)}function lcm(a,b){a=parseValue(a).abs();b=parseValue(b).abs();return a.divide(gcd(a,b)).multiply(b)}function randBetween(a,b){a=parseValue(a);b=parseValue(b);var low=min(a,b),high=max(a,b);var range=high.subtract(low);if(range.isSmall)return low.add(Math.round(Math.random()*range));var length=range.value.length-1;var result=[],restricted=true;for(var i=length;i>=0;i--){var top=restricted?range.value[i]:BASE;var digit=truncate(Math.random()*top);result.unshift(digit);if(digit<top)restricted=false}result=arrayToSmall(result);return low.add(typeof result==="number"?new SmallInteger(result):new BigInteger(result,false))}var parseBase=function(text,base){var length=text.length;var i;var absBase=Math.abs(base);for(var i=0;i<length;i++){var c=text[i].toLowerCase();if(c==="-")continue;if(/[a-z0-9]/.test(c)){if(/[0-9]/.test(c)&&+c>=absBase){if(c==="1"&&absBase===1)continue;throw new Error(c+" is not a valid digit in base "+base+".")}else if(c.charCodeAt(0)-87>=absBase){throw new Error(c+" is not a valid digit in base "+base+".")}}}if(2<=base&&base<=36){if(length<=LOG_MAX_INT/Math.log(base)){var result=parseInt(text,base);if(isNaN(result)){throw new Error(c+" is not a valid digit in base "+base+".")}return new SmallInteger(parseInt(text,base))}}base=parseValue(base);var digits=[];var isNegative=text[0]==="-";for(i=isNegative?1:0;i<text.length;i++){var c=text[i].toLowerCase(),charCode=c.charCodeAt(0);if(48<=charCode&&charCode<=57)digits.push(parseValue(c));else if(97<=charCode&&charCode<=122)digits.push(parseValue(c.charCodeAt(0)-87));else if(c==="<"){var start=i;do{i++}while(text[i]!==">");digits.push(parseValue(text.slice(start+1,i)))}else throw new Error(c+" is not a valid character")}return parseBaseFromArray(digits,base,isNegative)};function parseBaseFromArray(digits,base,isNegative){var val=Integer[0],pow=Integer[1],i;for(i=digits.length-1;i>=0;i--){val=val.add(digits[i].times(pow));pow=pow.times(base)}return isNegative?val.negate():val}function stringify(digit){var v=digit.value;if(typeof v==="number")v=[v];if(v.length===1&&v[0]<=35){return"0123456789abcdefghijklmnopqrstuvwxyz".charAt(v[0])}return"<"+v+">"}function toBase(n,base){base=bigInt(base);if(base.isZero()){if(n.isZero())return"0";throw new Error("Cannot convert nonzero numbers to base 0.")}if(base.equals(-1)){if(n.isZero())return"0";if(n.isNegative())return new Array(1-n).join("10");return"1"+new Array(+n).join("01")}var minusSign="";if(n.isNegative()&&base.isPositive()){minusSign="-";n=n.abs()}if(base.equals(1)){if(n.isZero())return"0";return minusSign+new Array(+n+1).join(1)}var out=[];var left=n,divmod;while(left.isNegative()||left.compareAbs(base)>=0){divmod=left.divmod(base);left=divmod.quotient;var digit=divmod.remainder;if(digit.isNegative()){digit=base.minus(digit).abs();left=left.next()}out.push(stringify(digit))}out.push(stringify(left));return minusSign+out.reverse().join("")}BigInteger.prototype.toString=function(radix){if(radix===undefined)radix=10;if(radix!==10)return toBase(this,radix);var v=this.value,l=v.length,str=String(v[--l]),zeros="0000000",digit;while(--l>=0){digit=String(v[l]);str+=zeros.slice(digit.length)+digit}var sign=this.sign?"-":"";return sign+str};SmallInteger.prototype.toString=function(radix){if(radix===undefined)radix=10;if(radix!=10)return toBase(this,radix);return String(this.value)};BigInteger.prototype.toJSON=SmallInteger.prototype.toJSON=function(){return this.toString()};BigInteger.prototype.valueOf=function(){return+this.toString()};BigInteger.prototype.toJSNumber=BigInteger.prototype.valueOf;SmallInteger.prototype.valueOf=function(){return this.value};SmallInteger.prototype.toJSNumber=SmallInteger.prototype.valueOf;function parseStringValue(v){if(isPrecise(+v)){var x=+v;if(x===truncate(x))return new SmallInteger(x);throw"Invalid integer: "+v}var sign=v[0]==="-";if(sign)v=v.slice(1);var split=v.split(/e/i);if(split.length>2)throw new Error("Invalid integer: "+split.join("e"));if(split.length===2){var exp=split[1];if(exp[0]==="+")exp=exp.slice(1);exp=+exp;if(exp!==truncate(exp)||!isPrecise(exp))throw new Error("Invalid integer: "+exp+" is not a valid exponent.");var text=split[0];var decimalPlace=text.indexOf(".");if(decimalPlace>=0){exp-=text.length-decimalPlace-1;text=text.slice(0,decimalPlace)+text.slice(decimalPlace+1)}if(exp<0)throw new Error("Cannot include negative exponent part for integers");text+=new Array(exp+1).join("0");v=text}var isValid=/^([0-9][0-9]*)$/.test(v);if(!isValid)throw new Error("Invalid integer: "+v);var r=[],max=v.length,l=LOG_BASE,min=max-l;while(max>0){r.push(+v.slice(min,max));min-=l;if(min<0)min=0;max-=l}trim(r);return new BigInteger(r,sign)}function parseNumberValue(v){if(isPrecise(v)){if(v!==truncate(v))throw new Error(v+" is not an integer.");return new SmallInteger(v)}return parseStringValue(v.toString())}function parseValue(v){if(typeof v==="number"){return parseNumberValue(v)}if(typeof v==="string"){return parseStringValue(v)}return v}for(var i=0;i<1e3;i++){Integer[i]=new SmallInteger(i);if(i>0)Integer[-i]=new SmallInteger(-i)}Integer.one=Integer[1];Integer.zero=Integer[0];Integer.minusOne=Integer[-1];Integer.max=max;Integer.min=min;Integer.gcd=gcd;Integer.lcm=lcm;Integer.isInstance=function(x){return x instanceof BigInteger||x instanceof SmallInteger};Integer.randBetween=randBetween;Integer.fromArray=function(digits,base,isNegative){return parseBaseFromArray(digits.map(parseValue),parseValue(base||10),isNegative)};return Integer}();if(typeof module!=="undefined"&&module.hasOwnProperty("exports")){module.exports=bigInt}if(typeof define==="function"&&define.amd){define("big-integer",[],function(){return bigInt})}
\ No newline at end of file
diff --git a/node_modules/big-integer/package.json b/node_modules/big-integer/package.json
index 35ee0dd..8d913e8 100644
--- a/node_modules/big-integer/package.json
+++ b/node_modules/big-integer/package.json
@@ -14,13 +14,13 @@
     ]
   ],
   "_from": "big-integer@>=1.6.7 <2.0.0",
-  "_id": "big-integer@1.6.24",
+  "_id": "big-integer@1.6.25",
   "_inCache": true,
   "_location": "/big-integer",
   "_nodeVersion": "6.10.3",
   "_npmOperationalInternal": {
     "host": "s3://npm-registry-packages",
-    "tmp": "tmp/big-integer-1.6.24.tgz_1503027511676_0.881959781749174"
+    "tmp": "tmp/big-integer-1.6.25.tgz_1504748727289_0.9231066561769694"
   },
   "_npmUser": {
     "name": "peterolson",
@@ -40,8 +40,8 @@
   "_requiredBy": [
     "/bplist-parser"
   ],
-  "_resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.24.tgz",
-  "_shasum": "1ed84d018ac3c1c72b307e7f7d94008e8ee20311",
+  "_resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.25.tgz",
+  "_shasum": "1de45a9f57542ac20121c682f8d642220a34e823",
   "_shrinkwrap": null,
   "_spec": "big-integer@^1.6.7",
   "_where": "/Users/steveng/repo/cordova/cordova-browser/node_modules/bplist-parser",
@@ -72,13 +72,13 @@
   },
   "directories": {},
   "dist": {
-    "shasum": "1ed84d018ac3c1c72b307e7f7d94008e8ee20311",
-    "tarball": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.24.tgz"
+    "shasum": "1de45a9f57542ac20121c682f8d642220a34e823",
+    "tarball": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.25.tgz"
   },
   "engines": {
     "node": ">=0.6"
   },
-  "gitHead": "8ac5ef5b7c4abce8e943776fa2f18d3d41697988",
+  "gitHead": "a0c10d68aae8f5df56a67b3e3eb353b428abf170",
   "homepage": "https://github.com/peterolson/BigInteger.js#readme",
   "keywords": [
     "math",
@@ -112,5 +112,5 @@
     "test": "tsc && node_modules/.bin/karma start my.conf.js && node spec/tsDefinitions.js"
   },
   "typings": "./BigInteger.d.ts",
-  "version": "1.6.24"
+  "version": "1.6.25"
 }
diff --git a/node_modules/body-parser/HISTORY.md b/node_modules/body-parser/HISTORY.md
new file mode 100644
index 0000000..6ab747b
--- /dev/null
+++ b/node_modules/body-parser/HISTORY.md
@@ -0,0 +1,568 @@
+1.18.2 / 2017-09-22
+===================
+
+  * deps: debug@2.6.9
+  * perf: remove argument reassignment
+
+1.18.1 / 2017-09-12
+===================
+
+  * deps: content-type@~1.0.4
+    - perf: remove argument reassignment
+    - perf: skip parameter parsing when no parameters
+  * deps: iconv-lite@0.4.19
+    - Fix ISO-8859-1 regression
+    - Update Windows-1255
+  * deps: qs@6.5.1
+    - Fix parsing & compacting very deep objects
+  * deps: raw-body@2.3.2
+    - deps: iconv-lite@0.4.19
+
+1.18.0 / 2017-09-08
+===================
+
+  * Fix JSON strict violation error to match native parse error
+  * Include the `body` property on verify errors
+  * Include the `type` property on all generated errors
+  * Use `http-errors` to set status code on errors
+  * deps: bytes@3.0.0
+  * deps: debug@2.6.8
+  * deps: depd@~1.1.1
+    - Remove unnecessary `Buffer` loading
+  * deps: http-errors@~1.6.2
+    - deps: depd@1.1.1
+  * deps: iconv-lite@0.4.18
+    - Add support for React Native
+    - Add a warning if not loaded as utf-8
+    - Fix CESU-8 decoding in Node.js 8
+    - Improve speed of ISO-8859-1 encoding
+  * deps: qs@6.5.0
+  * deps: raw-body@2.3.1
+    - Use `http-errors` for standard emitted errors
+    - deps: bytes@3.0.0
+    - deps: iconv-lite@0.4.18
+    - perf: skip buffer decoding on overage chunk
+  * perf: prevent internal `throw` when missing charset
+
+1.17.2 / 2017-05-17
+===================
+
+  * deps: debug@2.6.7
+    - Fix `DEBUG_MAX_ARRAY_LENGTH`
+    - deps: ms@2.0.0
+  * deps: type-is@~1.6.15
+    - deps: mime-types@~2.1.15
+
+1.17.1 / 2017-03-06
+===================
+
+  * deps: qs@6.4.0
+    - Fix regression parsing keys starting with `[`
+
+1.17.0 / 2017-03-01
+===================
+
+  * deps: http-errors@~1.6.1
+    - Make `message` property enumerable for `HttpError`s
+    - deps: setprototypeof@1.0.3
+  * deps: qs@6.3.1
+    - Fix compacting nested arrays
+
+1.16.1 / 2017-02-10
+===================
+
+  * deps: debug@2.6.1
+    - Fix deprecation messages in WebStorm and other editors
+    - Undeprecate `DEBUG_FD` set to `1` or `2`
+
+1.16.0 / 2017-01-17
+===================
+
+  * deps: debug@2.6.0
+    - Allow colors in workers
+    - Deprecated `DEBUG_FD` environment variable
+    - Fix error when running under React Native
+    - Use same color for same namespace
+    - deps: ms@0.7.2
+  * deps: http-errors@~1.5.1
+    - deps: inherits@2.0.3
+    - deps: setprototypeof@1.0.2
+    - deps: statuses@'>= 1.3.1 < 2'
+  * deps: iconv-lite@0.4.15
+    - Added encoding MS-31J
+    - Added encoding MS-932
+    - Added encoding MS-936
+    - Added encoding MS-949
+    - Added encoding MS-950
+    - Fix GBK/GB18030 handling of Euro character
+  * deps: qs@6.2.1
+    - Fix array parsing from skipping empty values
+  * deps: raw-body@~2.2.0
+    - deps: iconv-lite@0.4.15
+  * deps: type-is@~1.6.14
+    - deps: mime-types@~2.1.13
+
+1.15.2 / 2016-06-19
+===================
+
+  * deps: bytes@2.4.0
+  * deps: content-type@~1.0.2
+    - perf: enable strict mode
+  * deps: http-errors@~1.5.0
+    - Use `setprototypeof` module to replace `__proto__` setting
+    - deps: statuses@'>= 1.3.0 < 2'
+    - perf: enable strict mode
+  * deps: qs@6.2.0
+  * deps: raw-body@~2.1.7
+    - deps: bytes@2.4.0
+    - perf: remove double-cleanup on happy path
+  * deps: type-is@~1.6.13
+    - deps: mime-types@~2.1.11
+
+1.15.1 / 2016-05-05
+===================
+
+  * deps: bytes@2.3.0
+    - Drop partial bytes on all parsed units
+    - Fix parsing byte string that looks like hex
+  * deps: raw-body@~2.1.6
+    - deps: bytes@2.3.0
+  * deps: type-is@~1.6.12
+    - deps: mime-types@~2.1.10
+
+1.15.0 / 2016-02-10
+===================
+
+  * deps: http-errors@~1.4.0
+    - Add `HttpError` export, for `err instanceof createError.HttpError`
+    - deps: inherits@2.0.1
+    - deps: statuses@'>= 1.2.1 < 2'
+  * deps: qs@6.1.0
+  * deps: type-is@~1.6.11
+    - deps: mime-types@~2.1.9
+
+1.14.2 / 2015-12-16
+===================
+
+  * deps: bytes@2.2.0
+  * deps: iconv-lite@0.4.13
+  * deps: qs@5.2.0
+  * deps: raw-body@~2.1.5
+    - deps: bytes@2.2.0
+    - deps: iconv-lite@0.4.13
+  * deps: type-is@~1.6.10
+    - deps: mime-types@~2.1.8
+
+1.14.1 / 2015-09-27
+===================
+
+  * Fix issue where invalid charset results in 400 when `verify` used
+  * deps: iconv-lite@0.4.12
+    - Fix CESU-8 decoding in Node.js 4.x
+  * deps: raw-body@~2.1.4
+    - Fix masking critical errors from `iconv-lite`
+    - deps: iconv-lite@0.4.12
+  * deps: type-is@~1.6.9
+    - deps: mime-types@~2.1.7
+
+1.14.0 / 2015-09-16
+===================
+
+  * Fix JSON strict parse error to match syntax errors
+  * Provide static `require` analysis in `urlencoded` parser
+  * deps: depd@~1.1.0
+    - Support web browser loading
+  * deps: qs@5.1.0
+  * deps: raw-body@~2.1.3
+    - Fix sync callback when attaching data listener causes sync read
+  * deps: type-is@~1.6.8
+    - Fix type error when given invalid type to match against
+    - deps: mime-types@~2.1.6
+
+1.13.3 / 2015-07-31
+===================
+
+  * deps: type-is@~1.6.6
+    - deps: mime-types@~2.1.4
+
+1.13.2 / 2015-07-05
+===================
+
+  * deps: iconv-lite@0.4.11
+  * deps: qs@4.0.0
+    - Fix dropping parameters like `hasOwnProperty`
+    - Fix user-visible incompatibilities from 3.1.0
+    - Fix various parsing edge cases
+  * deps: raw-body@~2.1.2
+    - Fix error stack traces to skip `makeError`
+    - deps: iconv-lite@0.4.11
+  * deps: type-is@~1.6.4
+    - deps: mime-types@~2.1.2
+    - perf: enable strict mode
+    - perf: remove argument reassignment
+
+1.13.1 / 2015-06-16
+===================
+
+  * deps: qs@2.4.2
+    - Downgraded from 3.1.0 because of user-visible incompatibilities
+
+1.13.0 / 2015-06-14
+===================
+
+  * Add `statusCode` property on `Error`s, in addition to `status`
+  * Change `type` default to `application/json` for JSON parser
+  * Change `type` default to `application/x-www-form-urlencoded` for urlencoded parser
+  * Provide static `require` analysis
+  * Use the `http-errors` module to generate errors
+  * deps: bytes@2.1.0
+    - Slight optimizations
+  * deps: iconv-lite@0.4.10
+    - The encoding UTF-16 without BOM now defaults to UTF-16LE when detection fails
+    - Leading BOM is now removed when decoding
+  * deps: on-finished@~2.3.0
+    - Add defined behavior for HTTP `CONNECT` requests
+    - Add defined behavior for HTTP `Upgrade` requests
+    - deps: ee-first@1.1.1
+  * deps: qs@3.1.0
+    - Fix dropping parameters like `hasOwnProperty`
+    - Fix various parsing edge cases
+    - Parsed object now has `null` prototype
+  * deps: raw-body@~2.1.1
+    - Use `unpipe` module for unpiping requests
+    - deps: iconv-lite@0.4.10
+  * deps: type-is@~1.6.3
+    - deps: mime-types@~2.1.1
+    - perf: reduce try block size
+    - perf: remove bitwise operations
+  * perf: enable strict mode
+  * perf: remove argument reassignment
+  * perf: remove delete call
+
+1.12.4 / 2015-05-10
+===================
+
+  * deps: debug@~2.2.0
+  * deps: qs@2.4.2
+    - Fix allowing parameters like `constructor`
+  * deps: on-finished@~2.2.1
+  * deps: raw-body@~2.0.1
+    - Fix a false-positive when unpiping in Node.js 0.8
+    - deps: bytes@2.0.1
+  * deps: type-is@~1.6.2
+    - deps: mime-types@~2.0.11
+
+1.12.3 / 2015-04-15
+===================
+
+  * Slight efficiency improvement when not debugging
+  * deps: depd@~1.0.1
+  * deps: iconv-lite@0.4.8
+    - Add encoding alias UNICODE-1-1-UTF-7
+  * deps: raw-body@1.3.4
+    - Fix hanging callback if request aborts during read
+    - deps: iconv-lite@0.4.8
+
+1.12.2 / 2015-03-16
+===================
+
+  * deps: qs@2.4.1
+    - Fix error when parameter `hasOwnProperty` is present
+
+1.12.1 / 2015-03-15
+===================
+
+  * deps: debug@~2.1.3
+    - Fix high intensity foreground color for bold
+    - deps: ms@0.7.0
+  * deps: type-is@~1.6.1
+    - deps: mime-types@~2.0.10
+
+1.12.0 / 2015-02-13
+===================
+
+  * add `debug` messages
+  * accept a function for the `type` option
+  * use `content-type` to parse `Content-Type` headers
+  * deps: iconv-lite@0.4.7
+    - Gracefully support enumerables on `Object.prototype`
+  * deps: raw-body@1.3.3
+    - deps: iconv-lite@0.4.7
+  * deps: type-is@~1.6.0
+    - fix argument reassignment
+    - fix false-positives in `hasBody` `Transfer-Encoding` check
+    - support wildcard for both type and subtype (`*/*`)
+    - deps: mime-types@~2.0.9
+
+1.11.0 / 2015-01-30
+===================
+
+  * make internal `extended: true` depth limit infinity
+  * deps: type-is@~1.5.6
+    - deps: mime-types@~2.0.8
+
+1.10.2 / 2015-01-20
+===================
+
+  * deps: iconv-lite@0.4.6
+    - Fix rare aliases of single-byte encodings
+  * deps: raw-body@1.3.2
+    - deps: iconv-lite@0.4.6
+
+1.10.1 / 2015-01-01
+===================
+
+  * deps: on-finished@~2.2.0
+  * deps: type-is@~1.5.5
+    - deps: mime-types@~2.0.7
+
+1.10.0 / 2014-12-02
+===================
+
+  * make internal `extended: true` array limit dynamic
+
+1.9.3 / 2014-11-21
+==================
+
+  * deps: iconv-lite@0.4.5
+    - Fix Windows-31J and X-SJIS encoding support
+  * deps: qs@2.3.3
+    - Fix `arrayLimit` behavior
+  * deps: raw-body@1.3.1
+    - deps: iconv-lite@0.4.5
+  * deps: type-is@~1.5.3
+    - deps: mime-types@~2.0.3
+
+1.9.2 / 2014-10-27
+==================
+
+  * deps: qs@2.3.2
+    - Fix parsing of mixed objects and values
+
+1.9.1 / 2014-10-22
+==================
+
+  * deps: on-finished@~2.1.1
+    - Fix handling of pipelined requests
+  * deps: qs@2.3.0
+    - Fix parsing of mixed implicit and explicit arrays
+  * deps: type-is@~1.5.2
+    - deps: mime-types@~2.0.2
+
+1.9.0 / 2014-09-24
+==================
+
+  * include the charset in "unsupported charset" error message
+  * include the encoding in "unsupported content encoding" error message
+  * deps: depd@~1.0.0
+
+1.8.4 / 2014-09-23
+==================
+
+  * fix content encoding to be case-insensitive
+
+1.8.3 / 2014-09-19
+==================
+
+  * deps: qs@2.2.4
+    - Fix issue with object keys starting with numbers truncated
+
+1.8.2 / 2014-09-15
+==================
+
+  * deps: depd@0.4.5
+
+1.8.1 / 2014-09-07
+==================
+
+  * deps: media-typer@0.3.0
+  * deps: type-is@~1.5.1
+
+1.8.0 / 2014-09-05
+==================
+
+  * make empty-body-handling consistent between chunked requests
+    - empty `json` produces `{}`
+    - empty `raw` produces `new Buffer(0)`
+    - empty `text` produces `''`
+    - empty `urlencoded` produces `{}`
+  * deps: qs@2.2.3
+    - Fix issue where first empty value in array is discarded
+  * deps: type-is@~1.5.0
+    - fix `hasbody` to be true for `content-length: 0`
+
+1.7.0 / 2014-09-01
+==================
+
+  * add `parameterLimit` option to `urlencoded` parser
+  * change `urlencoded` extended array limit to 100
+  * respond with 413 when over `parameterLimit` in `urlencoded`
+
+1.6.7 / 2014-08-29
+==================
+
+  * deps: qs@2.2.2
+    - Remove unnecessary cloning
+
+1.6.6 / 2014-08-27
+==================
+
+  * deps: qs@2.2.0
+    - Array parsing fix
+    - Performance improvements
+
+1.6.5 / 2014-08-16
+==================
+
+  * deps: on-finished@2.1.0
+
+1.6.4 / 2014-08-14
+==================
+
+  * deps: qs@1.2.2
+
+1.6.3 / 2014-08-10
+==================
+
+  * deps: qs@1.2.1
+
+1.6.2 / 2014-08-07
+==================
+
+  * deps: qs@1.2.0
+    - Fix parsing array of objects
+
+1.6.1 / 2014-08-06
+==================
+
+  * deps: qs@1.1.0
+    - Accept urlencoded square brackets
+    - Accept empty values in implicit array notation
+
+1.6.0 / 2014-08-05
+==================
+
+  * deps: qs@1.0.2
+    - Complete rewrite
+    - Limits array length to 20
+    - Limits object depth to 5
+    - Limits parameters to 1,000
+
+1.5.2 / 2014-07-27
+==================
+
+  * deps: depd@0.4.4
+    - Work-around v8 generating empty stack traces
+
+1.5.1 / 2014-07-26
+==================
+
+  * deps: depd@0.4.3
+    - Fix exception when global `Error.stackTraceLimit` is too low
+
+1.5.0 / 2014-07-20
+==================
+
+  * deps: depd@0.4.2
+    - Add `TRACE_DEPRECATION` environment variable
+    - Remove non-standard grey color from color output
+    - Support `--no-deprecation` argument
+    - Support `--trace-deprecation` argument
+  * deps: iconv-lite@0.4.4
+    - Added encoding UTF-7
+  * deps: raw-body@1.3.0
+    - deps: iconv-lite@0.4.4
+    - Added encoding UTF-7
+    - Fix `Cannot switch to old mode now` error on Node.js 0.10+
+  * deps: type-is@~1.3.2
+
+1.4.3 / 2014-06-19
+==================
+
+  * deps: type-is@1.3.1
+    - fix global variable leak
+
+1.4.2 / 2014-06-19
+==================
+
+  * deps: type-is@1.3.0
+    - improve type parsing
+
+1.4.1 / 2014-06-19
+==================
+
+  * fix urlencoded extended deprecation message
+
+1.4.0 / 2014-06-19
+==================
+
+  * add `text` parser
+  * add `raw` parser
+  * check accepted charset in content-type (accepts utf-8)
+  * check accepted encoding in content-encoding (accepts identity)
+  * deprecate `bodyParser()` middleware; use `.json()` and `.urlencoded()` as needed
+  * deprecate `urlencoded()` without provided `extended` option
+  * lazy-load urlencoded parsers
+  * parsers split into files for reduced mem usage
+  * support gzip and deflate bodies
+    - set `inflate: false` to turn off
+  * deps: raw-body@1.2.2
+    - Support all encodings from `iconv-lite`
+
+1.3.1 / 2014-06-11
+==================
+
+  * deps: type-is@1.2.1
+    - Switch dependency from mime to mime-types@1.0.0
+
+1.3.0 / 2014-05-31
+==================
+
+  * add `extended` option to urlencoded parser
+
+1.2.2 / 2014-05-27
+==================
+
+  * deps: raw-body@1.1.6
+    - assert stream encoding on node.js 0.8
+    - assert stream encoding on node.js < 0.10.6
+    - deps: bytes@1
+
+1.2.1 / 2014-05-26
+==================
+
+  * invoke `next(err)` after request fully read
+    - prevents hung responses and socket hang ups
+
+1.2.0 / 2014-05-11
+==================
+
+  * add `verify` option
+  * deps: type-is@1.2.0
+    - support suffix matching
+
+1.1.2 / 2014-05-11
+==================
+
+  * improve json parser speed
+
+1.1.1 / 2014-05-11
+==================
+
+  * fix repeated limit parsing with every request
+
+1.1.0 / 2014-05-10
+==================
+
+  * add `type` option
+  * deps: pin for safety and consistency
+
+1.0.2 / 2014-04-14
+==================
+
+  * use `type-is` module
+
+1.0.1 / 2014-03-20
+==================
+
+  * lower default limits to 100kb
diff --git a/node_modules/body-parser/LICENSE b/node_modules/body-parser/LICENSE
new file mode 100644
index 0000000..386b7b6
--- /dev/null
+++ b/node_modules/body-parser/LICENSE
@@ -0,0 +1,23 @@
+(The MIT License)
+
+Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
+Copyright (c) 2014-2015 Douglas Christopher Wilson <doug@somethingdoug.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/body-parser/README.md b/node_modules/body-parser/README.md
new file mode 100644
index 0000000..62221e4
--- /dev/null
+++ b/node_modules/body-parser/README.md
@@ -0,0 +1,438 @@
+# body-parser
+
+[![NPM Version][npm-image]][npm-url]
+[![NPM Downloads][downloads-image]][downloads-url]
+[![Build Status][travis-image]][travis-url]
+[![Test Coverage][coveralls-image]][coveralls-url]
+[![Gratipay][gratipay-image]][gratipay-url]
+
+Node.js body parsing middleware.
+
+Parse incoming request bodies in a middleware before your handlers, available
+under the `req.body` property.
+
+[Learn about the anatomy of an HTTP transaction in Node.js](https://nodejs.org/en/docs/guides/anatomy-of-an-http-transaction/).
+
+_This does not handle multipart bodies_, due to their complex and typically
+large nature. For multipart bodies, you may be interested in the following
+modules:
+
+  * [busboy](https://www.npmjs.org/package/busboy#readme) and
+    [connect-busboy](https://www.npmjs.org/package/connect-busboy#readme)
+  * [multiparty](https://www.npmjs.org/package/multiparty#readme) and
+    [connect-multiparty](https://www.npmjs.org/package/connect-multiparty#readme)
+  * [formidable](https://www.npmjs.org/package/formidable#readme)
+  * [multer](https://www.npmjs.org/package/multer#readme)
+
+This module provides the following parsers:
+
+  * [JSON body parser](#bodyparserjsonoptions)
+  * [Raw body parser](#bodyparserrawoptions)
+  * [Text body parser](#bodyparsertextoptions)
+  * [URL-encoded form body parser](#bodyparserurlencodedoptions)
+
+Other body parsers you might be interested in:
+
+- [body](https://www.npmjs.org/package/body#readme)
+- [co-body](https://www.npmjs.org/package/co-body#readme)
+
+## Installation
+
+```sh
+$ npm install body-parser
+```
+
+## API
+
+<!-- eslint-disable no-unused-vars -->
+
+```js
+var bodyParser = require('body-parser')
+```
+
+The `bodyParser` object exposes various factories to create middlewares. All
+middlewares will populate the `req.body` property with the parsed body when
+the `Content-Type` request header matches the `type` option, or an empty
+object (`{}`) if there was no body to parse, the `Content-Type` was not matched,
+or an error occurred.
+
+The various errors returned by this module are described in the
+[errors section](#errors).
+
+### bodyParser.json([options])
+
+Returns middleware that only parses `json` and only looks at requests where
+the `Content-Type` header matches the `type` option. This parser accepts any
+Unicode encoding of the body and supports automatic inflation of `gzip` and
+`deflate` encodings.
+
+A new `body` object containing the parsed data is populated on the `request`
+object after the middleware (i.e. `req.body`).
+
+#### Options
+
+The `json` function takes an optional `options` object that may contain any of
+the following keys:
+
+##### inflate
+
+When set to `true`, then deflated (compressed) bodies will be inflated; when
+`false`, deflated bodies are rejected. Defaults to `true`.
+
+##### limit
+
+Controls the maximum request body size. If this is a number, then the value
+specifies the number of bytes; if it is a string, the value is passed to the
+[bytes](https://www.npmjs.com/package/bytes) library for parsing. Defaults
+to `'100kb'`.
+
+##### reviver
+
+The `reviver` option is passed directly to `JSON.parse` as the second
+argument. You can find more information on this argument
+[in the MDN documentation about JSON.parse](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Example.3A_Using_the_reviver_parameter).
+
+##### strict
+
+When set to `true`, will only accept arrays and objects; when `false` will
+accept anything `JSON.parse` accepts. Defaults to `true`.
+
+##### type
+
+The `type` option is used to determine what media type the middleware will
+parse. This option can be a function or a string. If a string, `type` option
+is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme)
+library and this can be an extension name (like `json`), a mime type (like
+`application/json`), or a mime type with a wildcard (like `*/*` or `*/json`).
+If a function, the `type` option is called as `fn(req)` and the request is
+parsed if it returns a truthy value. Defaults to `application/json`.
+
+##### verify
+
+The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`,
+where `buf` is a `Buffer` of the raw request body and `encoding` is the
+encoding of the request. The parsing can be aborted by throwing an error.
+
+### bodyParser.raw([options])
+
+Returns middleware that parses all bodies as a `Buffer` and only looks at
+requests where the `Content-Type` header matches the `type` option. This
+parser supports automatic inflation of `gzip` and `deflate` encodings.
+
+A new `body` object containing the parsed data is populated on the `request`
+object after the middleware (i.e. `req.body`). This will be a `Buffer` object
+of the body.
+
+#### Options
+
+The `raw` function takes an optional `options` object that may contain any of
+the following keys:
+
+##### inflate
+
+When set to `true`, then deflated (compressed) bodies will be inflated; when
+`false`, deflated bodies are rejected. Defaults to `true`.
+
+##### limit
+
+Controls the maximum request body size. If this is a number, then the value
+specifies the number of bytes; if it is a string, the value is passed to the
+[bytes](https://www.npmjs.com/package/bytes) library for parsing. Defaults
+to `'100kb'`.
+
+##### type
+
+The `type` option is used to determine what media type the middleware will
+parse. This option can be a function or a string. If a string, `type` option
+is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme)
+library and this can be an extension name (like `bin`), a mime type (like
+`application/octet-stream`), or a mime type with a wildcard (like `*/*` or
+`application/*`). If a function, the `type` option is called as `fn(req)`
+and the request is parsed if it returns a truthy value. Defaults to
+`application/octet-stream`.
+
+##### verify
+
+The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`,
+where `buf` is a `Buffer` of the raw request body and `encoding` is the
+encoding of the request. The parsing can be aborted by throwing an error.
+
+### bodyParser.text([options])
+
+Returns middleware that parses all bodies as a string and only looks at
+requests where the `Content-Type` header matches the `type` option. This
+parser supports automatic inflation of `gzip` and `deflate` encodings.
+
+A new `body` string containing the parsed data is populated on the `request`
+object after the middleware (i.e. `req.body`). This will be a string of the
+body.
+
+#### Options
+
+The `text` function takes an optional `options` object that may contain any of
+the following keys:
+
+##### defaultCharset
+
+Specify the default character set for the text content if the charset is not
+specified in the `Content-Type` header of the request. Defaults to `utf-8`.
+
+##### inflate
+
+When set to `true`, then deflated (compressed) bodies will be inflated; when
+`false`, deflated bodies are rejected. Defaults to `true`.
+
+##### limit
+
+Controls the maximum request body size. If this is a number, then the value
+specifies the number of bytes; if it is a string, the value is passed to the
+[bytes](https://www.npmjs.com/package/bytes) library for parsing. Defaults
+to `'100kb'`.
+
+##### type
+
+The `type` option is used to determine what media type the middleware will
+parse. This option can be a function or a string. If a string, `type` option
+is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme)
+library and this can be an extension name (like `txt`), a mime type (like
+`text/plain`), or a mime type with a wildcard (like `*/*` or `text/*`).
+If a function, the `type` option is called as `fn(req)` and the request is
+parsed if it returns a truthy value. Defaults to `text/plain`.
+
+##### verify
+
+The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`,
+where `buf` is a `Buffer` of the raw request body and `encoding` is the
+encoding of the request. The parsing can be aborted by throwing an error.
+
+### bodyParser.urlencoded([options])
+
+Returns middleware that only parses `urlencoded` bodies and only looks at
+requests where the `Content-Type` header matches the `type` option. This
+parser accepts only UTF-8 encoding of the body and supports automatic
+inflation of `gzip` and `deflate` encodings.
+
+A new `body` object containing the parsed data is populated on the `request`
+object after the middleware (i.e. `req.body`). This object will contain
+key-value pairs, where the value can be a string or array (when `extended` is
+`false`), or any type (when `extended` is `true`).
+
+#### Options
+
+The `urlencoded` function takes an optional `options` object that may contain
+any of the following keys:
+
+##### extended
+
+The `extended` option allows to choose between parsing the URL-encoded data
+with the `querystring` library (when `false`) or the `qs` library (when
+`true`). The "extended" syntax allows for rich objects and arrays to be
+encoded into the URL-encoded format, allowing for a JSON-like experience
+with URL-encoded. For more information, please
+[see the qs library](https://www.npmjs.org/package/qs#readme).
+
+Defaults to `true`, but using the default has been deprecated. Please
+research into the difference between `qs` and `querystring` and choose the
+appropriate setting.
+
+##### inflate
+
+When set to `true`, then deflated (compressed) bodies will be inflated; when
+`false`, deflated bodies are rejected. Defaults to `true`.
+
+##### limit
+
+Controls the maximum request body size. If this is a number, then the value
+specifies the number of bytes; if it is a string, the value is passed to the
+[bytes](https://www.npmjs.com/package/bytes) library for parsing. Defaults
+to `'100kb'`.
+
+##### parameterLimit
+
+The `parameterLimit` option controls the maximum number of parameters that
+are allowed in the URL-encoded data. If a request contains more parameters
+than this value, a 413 will be returned to the client. Defaults to `1000`.
+
+##### type
+
+The `type` option is used to determine what media type the middleware will
+parse. This option can be a function or a string. If a string, `type` option
+is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme)
+library and this can be an extension name (like `urlencoded`), a mime type (like
+`application/x-www-form-urlencoded`), or a mime type with a wildcard (like
+`*/x-www-form-urlencoded`). If a function, the `type` option is called as
+`fn(req)` and the request is parsed if it returns a truthy value. Defaults
+to `application/x-www-form-urlencoded`.
+
+##### verify
+
+The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`,
+where `buf` is a `Buffer` of the raw request body and `encoding` is the
+encoding of the request. The parsing can be aborted by throwing an error.
+
+## Errors
+
+The middlewares provided by this module create errors depending on the error
+condition during parsing. The errors will typically have a `status`/`statusCode`
+property that contains the suggested HTTP response code, an `expose` property
+to determine if the `message` property should be displayed to the client, a
+`type` property to determine the type of error without matching against the
+`message`, and a `body` property containing the read body, if available.
+
+The following are the common errors emitted, though any error can come through
+for various reasons.
+
+### content encoding unsupported
+
+This error will occur when the request had a `Content-Encoding` header that
+contained an encoding but the "inflation" option was set to `false`. The
+`status` property is set to `415`, the `type` property is set to
+`'encoding.unsupported'`, and the `charset` property will be set to the
+encoding that is unsupported.
+
+### request aborted
+
+This error will occur when the request is aborted by the client before reading
+the body has finished. The `received` property will be set to the number of
+bytes received before the request was aborted and the `expected` property is
+set to the number of expected bytes. The `status` property is set to `400`
+and `type` property is set to `'request.aborted'`.
+
+### request entity too large
+
+This error will occur when the request body's size is larger than the "limit"
+option. The `limit` property will be set to the byte limit and the `length`
+property will be set to the request body's length. The `status` property is
+set to `413` and the `type` property is set to `'entity.too.large'`.
+
+### request size did not match content length
+
+This error will occur when the request's length did not match the length from
+the `Content-Length` header. This typically occurs when the request is malformed,
+typically when the `Content-Length` header was calculated based on characters
+instead of bytes. The `status` property is set to `400` and the `type` property
+is set to `'request.size.invalid'`.
+
+### stream encoding should not be set
+
+This error will occur when something called the `req.setEncoding` method prior
+to this middleware. This module operates directly on bytes only and you cannot
+call `req.setEncoding` when using this module. The `status` property is set to
+`500` and the `type` property is set to `'stream.encoding.set'`.
+
+### too many parameters
+
+This error will occur when the content of the request exceeds the configured
+`parameterLimit` for the `urlencoded` parser. The `status` property is set to
+`413` and the `type` property is set to `'parameters.too.many'`.
+
+### unsupported charset "BOGUS"
+
+This error will occur when the request had a charset parameter in the
+`Content-Type` header, but the `iconv-lite` module does not support it OR the
+parser does not support it. The charset is contained in the message as well
+as in the `charset` property. The `status` property is set to `415`, the
+`type` property is set to `'charset.unsupported'`, and the `charset` property
+is set to the charset that is unsupported.
+
+### unsupported content encoding "bogus"
+
+This error will occur when the request had a `Content-Encoding` header that
+contained an unsupported encoding. The encoding is contained in the message
+as well as in the `encoding` property. The `status` property is set to `415`,
+the `type` property is set to `'encoding.unsupported'`, and the `encoding`
+property is set to the encoding that is unsupported.
+
+## Examples
+
+### Express/Connect top-level generic
+
+This example demonstrates adding a generic JSON and URL-encoded parser as a
+top-level middleware, which will parse the bodies of all incoming requests.
+This is the simplest setup.
+
+```js
+var express = require('express')
+var bodyParser = require('body-parser')
+
+var app = express()
+
+// parse application/x-www-form-urlencoded
+app.use(bodyParser.urlencoded({ extended: false }))
+
+// parse application/json
+app.use(bodyParser.json())
+
+app.use(function (req, res) {
+  res.setHeader('Content-Type', 'text/plain')
+  res.write('you posted:\n')
+  res.end(JSON.stringify(req.body, null, 2))
+})
+```
+
+### Express route-specific
+
+This example demonstrates adding body parsers specifically to the routes that
+need them. In general, this is the most recommended way to use body-parser with
+Express.
+
+```js
+var express = require('express')
+var bodyParser = require('body-parser')
+
+var app = express()
+
+// create application/json parser
+var jsonParser = bodyParser.json()
+
+// create application/x-www-form-urlencoded parser
+var urlencodedParser = bodyParser.urlencoded({ extended: false })
+
+// POST /login gets urlencoded bodies
+app.post('/login', urlencodedParser, function (req, res) {
+  if (!req.body) return res.sendStatus(400)
+  res.send('welcome, ' + req.body.username)
+})
+
+// POST /api/users gets JSON bodies
+app.post('/api/users', jsonParser, function (req, res) {
+  if (!req.body) return res.sendStatus(400)
+  // create user in req.body
+})
+```
+
+### Change accepted type for parsers
+
+All the parsers accept a `type` option which allows you to change the
+`Content-Type` that the middleware will parse.
+
+```js
+var express = require('express')
+var bodyParser = require('body-parser')
+
+var app = express()
+
+// parse various different custom JSON types as JSON
+app.use(bodyParser.json({ type: 'application/*+json' }))
+
+// parse some custom thing into a Buffer
+app.use(bodyParser.raw({ type: 'application/vnd.custom-type' }))
+
+// parse an HTML body into a string
+app.use(bodyParser.text({ type: 'text/html' }))
+```
+
+## License
+
+[MIT](LICENSE)
+
+[npm-image]: https://img.shields.io/npm/v/body-parser.svg
+[npm-url]: https://npmjs.org/package/body-parser
+[travis-image]: https://img.shields.io/travis/expressjs/body-parser/master.svg
+[travis-url]: https://travis-ci.org/expressjs/body-parser
+[coveralls-image]: https://img.shields.io/coveralls/expressjs/body-parser/master.svg
+[coveralls-url]: https://coveralls.io/r/expressjs/body-parser?branch=master
+[downloads-image]: https://img.shields.io/npm/dm/body-parser.svg
+[downloads-url]: https://npmjs.org/package/body-parser
+[gratipay-image]: https://img.shields.io/gratipay/dougwilson.svg
+[gratipay-url]: https://www.gratipay.com/dougwilson/
diff --git a/node_modules/body-parser/index.js b/node_modules/body-parser/index.js
new file mode 100644
index 0000000..93c3a1f
--- /dev/null
+++ b/node_modules/body-parser/index.js
@@ -0,0 +1,157 @@
+/*!
+ * body-parser
+ * Copyright(c) 2014-2015 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict'
+
+/**
+ * Module dependencies.
+ * @private
+ */
+
+var deprecate = require('depd')('body-parser')
+
+/**
+ * Cache of loaded parsers.
+ * @private
+ */
+
+var parsers = Object.create(null)
+
+/**
+ * @typedef Parsers
+ * @type {function}
+ * @property {function} json
+ * @property {function} raw
+ * @property {function} text
+ * @property {function} urlencoded
+ */
+
+/**
+ * Module exports.
+ * @type {Parsers}
+ */
+
+exports = module.exports = deprecate.function(bodyParser,
+  'bodyParser: use individual json/urlencoded middlewares')
+
+/**
+ * JSON parser.
+ * @public
+ */
+
+Object.defineProperty(exports, 'json', {
+  configurable: true,
+  enumerable: true,
+  get: createParserGetter('json')
+})
+
+/**
+ * Raw parser.
+ * @public
+ */
+
+Object.defineProperty(exports, 'raw', {
+  configurable: true,
+  enumerable: true,
+  get: createParserGetter('raw')
+})
+
+/**
+ * Text parser.
+ * @public
+ */
+
+Object.defineProperty(exports, 'text', {
+  configurable: true,
+  enumerable: true,
+  get: createParserGetter('text')
+})
+
+/**
+ * URL-encoded parser.
+ * @public
+ */
+
+Object.defineProperty(exports, 'urlencoded', {
+  configurable: true,
+  enumerable: true,
+  get: createParserGetter('urlencoded')
+})
+
+/**
+ * Create a middleware to parse json and urlencoded bodies.
+ *
+ * @param {object} [options]
+ * @return {function}
+ * @deprecated
+ * @public
+ */
+
+function bodyParser (options) {
+  var opts = {}
+
+  // exclude type option
+  if (options) {
+    for (var prop in options) {
+      if (prop !== 'type') {
+        opts[prop] = options[prop]
+      }
+    }
+  }
+
+  var _urlencoded = exports.urlencoded(opts)
+  var _json = exports.json(opts)
+
+  return function bodyParser (req, res, next) {
+    _json(req, res, function (err) {
+      if (err) return next(err)
+      _urlencoded(req, res, next)
+    })
+  }
+}
+
+/**
+ * Create a getter for loading a parser.
+ * @private
+ */
+
+function createParserGetter (name) {
+  return function get () {
+    return loadParser(name)
+  }
+}
+
+/**
+ * Load a parser module.
+ * @private
+ */
+
+function loadParser (parserName) {
+  var parser = parsers[parserName]
+
+  if (parser !== undefined) {
+    return parser
+  }
+
+  // this uses a switch for static require analysis
+  switch (parserName) {
+    case 'json':
+      parser = require('./lib/types/json')
+      break
+    case 'raw':
+      parser = require('./lib/types/raw')
+      break
+    case 'text':
+      parser = require('./lib/types/text')
+      break
+    case 'urlencoded':
+      parser = require('./lib/types/urlencoded')
+      break
+  }
+
+  // store to prevent invoking require()
+  return (parsers[parserName] = parser)
+}
diff --git a/node_modules/body-parser/lib/read.js b/node_modules/body-parser/lib/read.js
new file mode 100644
index 0000000..c102609
--- /dev/null
+++ b/node_modules/body-parser/lib/read.js
@@ -0,0 +1,181 @@
+/*!
+ * body-parser
+ * Copyright(c) 2014-2015 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict'
+
+/**
+ * Module dependencies.
+ * @private
+ */
+
+var createError = require('http-errors')
+var getBody = require('raw-body')
+var iconv = require('iconv-lite')
+var onFinished = require('on-finished')
+var zlib = require('zlib')
+
+/**
+ * Module exports.
+ */
+
+module.exports = read
+
+/**
+ * Read a request into a buffer and parse.
+ *
+ * @param {object} req
+ * @param {object} res
+ * @param {function} next
+ * @param {function} parse
+ * @param {function} debug
+ * @param {object} options
+ * @private
+ */
+
+function read (req, res, next, parse, debug, options) {
+  var length
+  var opts = options
+  var stream
+
+  // flag as parsed
+  req._body = true
+
+  // read options
+  var encoding = opts.encoding !== null
+    ? opts.encoding
+    : null
+  var verify = opts.verify
+
+  try {
+    // get the content stream
+    stream = contentstream(req, debug, opts.inflate)
+    length = stream.length
+    stream.length = undefined
+  } catch (err) {
+    return next(err)
+  }
+
+  // set raw-body options
+  opts.length = length
+  opts.encoding = verify
+    ? null
+    : encoding
+
+  // assert charset is supported
+  if (opts.encoding === null && encoding !== null && !iconv.encodingExists(encoding)) {
+    return next(createError(415, 'unsupported charset "' + encoding.toUpperCase() + '"', {
+      charset: encoding.toLowerCase(),
+      type: 'charset.unsupported'
+    }))
+  }
+
+  // read body
+  debug('read body')
+  getBody(stream, opts, function (error, body) {
+    if (error) {
+      var _error
+
+      if (error.type === 'encoding.unsupported') {
+        // echo back charset
+        _error = createError(415, 'unsupported charset "' + encoding.toUpperCase() + '"', {
+          charset: encoding.toLowerCase(),
+          type: 'charset.unsupported'
+        })
+      } else {
+        // set status code on error
+        _error = createError(400, error)
+      }
+
+      // read off entire request
+      stream.resume()
+      onFinished(req, function onfinished () {
+        next(createError(400, _error))
+      })
+      return
+    }
+
+    // verify
+    if (verify) {
+      try {
+        debug('verify body')
+        verify(req, res, body, encoding)
+      } catch (err) {
+        next(createError(403, err, {
+          body: body,
+          type: err.type || 'entity.verify.failed'
+        }))
+        return
+      }
+    }
+
+    // parse
+    var str = body
+    try {
+      debug('parse body')
+      str = typeof body !== 'string' && encoding !== null
+        ? iconv.decode(body, encoding)
+        : body
+      req.body = parse(str)
+    } catch (err) {
+      next(createError(400, err, {
+        body: str,
+        type: err.type || 'entity.parse.failed'
+      }))
+      return
+    }
+
+    next()
+  })
+}
+
+/**
+ * Get the content stream of the request.
+ *
+ * @param {object} req
+ * @param {function} debug
+ * @param {boolean} [inflate=true]
+ * @return {object}
+ * @api private
+ */
+
+function contentstream (req, debug, inflate) {
+  var encoding = (req.headers['content-encoding'] || 'identity').toLowerCase()
+  var length = req.headers['content-length']
+  var stream
+
+  debug('content-encoding "%s"', encoding)
+
+  if (inflate === false && encoding !== 'identity') {
+    throw createError(415, 'content encoding unsupported', {
+      encoding: encoding,
+      type: 'encoding.unsupported'
+    })
+  }
+
+  switch (encoding) {
+    case 'deflate':
+      stream = zlib.createInflate()
+      debug('inflate body')
+      req.pipe(stream)
+      break
+    case 'gzip':
+      stream = zlib.createGunzip()
+      debug('gunzip body')
+      req.pipe(stream)
+      break
+    case 'identity':
+      stream = req
+      stream.length = length
+      break
+    default:
+      throw createError(415, 'unsupported content encoding "' + encoding + '"', {
+        encoding: encoding,
+        type: 'encoding.unsupported'
+      })
+  }
+
+  return stream
+}
diff --git a/node_modules/body-parser/lib/types/json.js b/node_modules/body-parser/lib/types/json.js
new file mode 100644
index 0000000..a7bc838
--- /dev/null
+++ b/node_modules/body-parser/lib/types/json.js
@@ -0,0 +1,232 @@
+/*!
+ * body-parser
+ * Copyright(c) 2014 Jonathan Ong
+ * Copyright(c) 2014-2015 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict'
+
+/**
+ * Module dependencies.
+ * @private
+ */
+
+var bytes = require('bytes')
+var contentType = require('content-type')
+var createError = require('http-errors')
+var debug = require('debug')('body-parser:json')
+var read = require('../read')
+var typeis = require('type-is')
+
+/**
+ * Module exports.
+ */
+
+module.exports = json
+
+/**
+ * RegExp to match the first non-space in a string.
+ *
+ * Allowed whitespace is defined in RFC 7159:
+ *
+ *    ws = *(
+ *            %x20 /              ; Space
+ *            %x09 /              ; Horizontal tab
+ *            %x0A /              ; Line feed or New line
+ *            %x0D )              ; Carriage return
+ */
+
+var FIRST_CHAR_REGEXP = /^[\x20\x09\x0a\x0d]*(.)/ // eslint-disable-line no-control-regex
+
+/**
+ * Create a middleware to parse JSON bodies.
+ *
+ * @param {object} [options]
+ * @return {function}
+ * @public
+ */
+
+function json (options) {
+  var opts = options || {}
+
+  var limit = typeof opts.limit !== 'number'
+    ? bytes.parse(opts.limit || '100kb')
+    : opts.limit
+  var inflate = opts.inflate !== false
+  var reviver = opts.reviver
+  var strict = opts.strict !== false
+  var type = opts.type || 'application/json'
+  var verify = opts.verify || false
+
+  if (verify !== false && typeof verify !== 'function') {
+    throw new TypeError('option verify must be function')
+  }
+
+  // create the appropriate type checking function
+  var shouldParse = typeof type !== 'function'
+    ? typeChecker(type)
+    : type
+
+  function parse (body) {
+    if (body.length === 0) {
+      // special-case empty json body, as it's a common client-side mistake
+      // TODO: maybe make this configurable or part of "strict" option
+      return {}
+    }
+
+    if (strict) {
+      var first = firstchar(body)
+
+      if (first !== '{' && first !== '[') {
+        debug('strict violation')
+        throw createStrictSyntaxError(body, first)
+      }
+    }
+
+    try {
+      debug('parse json')
+      return JSON.parse(body, reviver)
+    } catch (e) {
+      throw normalizeJsonSyntaxError(e, {
+        stack: e.stack
+      })
+    }
+  }
+
+  return function jsonParser (req, res, next) {
+    if (req._body) {
+      debug('body already parsed')
+      next()
+      return
+    }
+
+    req.body = req.body || {}
+
+    // skip requests without bodies
+    if (!typeis.hasBody(req)) {
+      debug('skip empty body')
+      next()
+      return
+    }
+
+    debug('content-type %j', req.headers['content-type'])
+
+    // determine if request should be parsed
+    if (!shouldParse(req)) {
+      debug('skip parsing')
+      next()
+      return
+    }
+
+    // assert charset per RFC 7159 sec 8.1
+    var charset = getCharset(req) || 'utf-8'
+    if (charset.substr(0, 4) !== 'utf-') {
+      debug('invalid charset')
+      next(createError(415, 'unsupported charset "' + charset.toUpperCase() + '"', {
+        charset: charset,
+        type: 'charset.unsupported'
+      }))
+      return
+    }
+
+    // read
+    read(req, res, next, parse, debug, {
+      encoding: charset,
+      inflate: inflate,
+      limit: limit,
+      verify: verify
+    })
+  }
+}
+
+/**
+ * Create strict violation syntax error matching native error.
+ *
+ * @param {string} str
+ * @param {string} char
+ * @return {Error}
+ * @private
+ */
+
+function createStrictSyntaxError (str, char) {
+  var index = str.indexOf(char)
+  var partial = str.substring(0, index) + '#'
+
+  try {
+    JSON.parse(partial); /* istanbul ignore next */ throw new SyntaxError('strict violation')
+  } catch (e) {
+    return normalizeJsonSyntaxError(e, {
+      message: e.message.replace('#', char),
+      stack: e.stack
+    })
+  }
+}
+
+/**
+ * Get the first non-whitespace character in a string.
+ *
+ * @param {string} str
+ * @return {function}
+ * @private
+ */
+
+function firstchar (str) {
+  return FIRST_CHAR_REGEXP.exec(str)[1]
+}
+
+/**
+ * Get the charset of a request.
+ *
+ * @param {object} req
+ * @api private
+ */
+
+function getCharset (req) {
+  try {
+    return (contentType.parse(req).parameters.charset || '').toLowerCase()
+  } catch (e) {
+    return undefined
+  }
+}
+
+/**
+ * Normalize a SyntaxError for JSON.parse.
+ *
+ * @param {SyntaxError} error
+ * @param {object} obj
+ * @return {SyntaxError}
+ */
+
+function normalizeJsonSyntaxError (error, obj) {
+  var keys = Object.getOwnPropertyNames(error)
+
+  for (var i = 0; i < keys.length; i++) {
+    var key = keys[i]
+    if (key !== 'stack' && key !== 'message') {
+      delete error[key]
+    }
+  }
+
+  var props = Object.keys(obj)
+
+  for (var j = 0; j < props.length; j++) {
+    var prop = props[j]
+    error[prop] = obj[prop]
+  }
+
+  return error
+}
+
+/**
+ * Get the simple type checker.
+ *
+ * @param {string} type
+ * @return {function}
+ */
+
+function typeChecker (type) {
+  return function checkType (req) {
+    return Boolean(typeis(req, type))
+  }
+}
diff --git a/node_modules/body-parser/lib/types/raw.js b/node_modules/body-parser/lib/types/raw.js
new file mode 100644
index 0000000..f5d1b67
--- /dev/null
+++ b/node_modules/body-parser/lib/types/raw.js
@@ -0,0 +1,101 @@
+/*!
+ * body-parser
+ * Copyright(c) 2014-2015 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict'
+
+/**
+ * Module dependencies.
+ */
+
+var bytes = require('bytes')
+var debug = require('debug')('body-parser:raw')
+var read = require('../read')
+var typeis = require('type-is')
+
+/**
+ * Module exports.
+ */
+
+module.exports = raw
+
+/**
+ * Create a middleware to parse raw bodies.
+ *
+ * @param {object} [options]
+ * @return {function}
+ * @api public
+ */
+
+function raw (options) {
+  var opts = options || {}
+
+  var inflate = opts.inflate !== false
+  var limit = typeof opts.limit !== 'number'
+    ? bytes.parse(opts.limit || '100kb')
+    : opts.limit
+  var type = opts.type || 'application/octet-stream'
+  var verify = opts.verify || false
+
+  if (verify !== false && typeof verify !== 'function') {
+    throw new TypeError('option verify must be function')
+  }
+
+  // create the appropriate type checking function
+  var shouldParse = typeof type !== 'function'
+    ? typeChecker(type)
+    : type
+
+  function parse (buf) {
+    return buf
+  }
+
+  return function rawParser (req, res, next) {
+    if (req._body) {
+      debug('body already parsed')
+      next()
+      return
+    }
+
+    req.body = req.body || {}
+
+    // skip requests without bodies
+    if (!typeis.hasBody(req)) {
+      debug('skip empty body')
+      next()
+      return
+    }
+
+    debug('content-type %j', req.headers['content-type'])
+
+    // determine if request should be parsed
+    if (!shouldParse(req)) {
+      debug('skip parsing')
+      next()
+      return
+    }
+
+    // read
+    read(req, res, next, parse, debug, {
+      encoding: null,
+      inflate: inflate,
+      limit: limit,
+      verify: verify
+    })
+  }
+}
+
+/**
+ * Get the simple type checker.
+ *
+ * @param {string} type
+ * @return {function}
+ */
+
+function typeChecker (type) {
+  return function checkType (req) {
+    return Boolean(typeis(req, type))
+  }
+}
diff --git a/node_modules/body-parser/lib/types/text.js b/node_modules/body-parser/lib/types/text.js
new file mode 100644
index 0000000..083a009
--- /dev/null
+++ b/node_modules/body-parser/lib/types/text.js
@@ -0,0 +1,121 @@
+/*!
+ * body-parser
+ * Copyright(c) 2014-2015 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict'
+
+/**
+ * Module dependencies.
+ */
+
+var bytes = require('bytes')
+var contentType = require('content-type')
+var debug = require('debug')('body-parser:text')
+var read = require('../read')
+var typeis = require('type-is')
+
+/**
+ * Module exports.
+ */
+
+module.exports = text
+
+/**
+ * Create a middleware to parse text bodies.
+ *
+ * @param {object} [options]
+ * @return {function}
+ * @api public
+ */
+
+function text (options) {
+  var opts = options || {}
+
+  var defaultCharset = opts.defaultCharset || 'utf-8'
+  var inflate = opts.inflate !== false
+  var limit = typeof opts.limit !== 'number'
+    ? bytes.parse(opts.limit || '100kb')
+    : opts.limit
+  var type = opts.type || 'text/plain'
+  var verify = opts.verify || false
+
+  if (verify !== false && typeof verify !== 'function') {
+    throw new TypeError('option verify must be function')
+  }
+
+  // create the appropriate type checking function
+  var shouldParse = typeof type !== 'function'
+    ? typeChecker(type)
+    : type
+
+  function parse (buf) {
+    return buf
+  }
+
+  return function textParser (req, res, next) {
+    if (req._body) {
+      debug('body already parsed')
+      next()
+      return
+    }
+
+    req.body = req.body || {}
+
+    // skip requests without bodies
+    if (!typeis.hasBody(req)) {
+      debug('skip empty body')
+      next()
+      return
+    }
+
+    debug('content-type %j', req.headers['content-type'])
+
+    // determine if request should be parsed
+    if (!shouldParse(req)) {
+      debug('skip parsing')
+      next()
+      return
+    }
+
+    // get charset
+    var charset = getCharset(req) || defaultCharset
+
+    // read
+    read(req, res, next, parse, debug, {
+      encoding: charset,
+      inflate: inflate,
+      limit: limit,
+      verify: verify
+    })
+  }
+}
+
+/**
+ * Get the charset of a request.
+ *
+ * @param {object} req
+ * @api private
+ */
+
+function getCharset (req) {
+  try {
+    return (contentType.parse(req).parameters.charset || '').toLowerCase()
+  } catch (e) {
+    return undefined
+  }
+}
+
+/**
+ * Get the simple type checker.
+ *
+ * @param {string} type
+ * @return {function}
+ */
+
+function typeChecker (type) {
+  return function checkType (req) {
+    return Boolean(typeis(req, type))
+  }
+}
diff --git a/node_modules/body-parser/lib/types/urlencoded.js b/node_modules/body-parser/lib/types/urlencoded.js
new file mode 100644
index 0000000..5ccda21
--- /dev/null
+++ b/node_modules/body-parser/lib/types/urlencoded.js
@@ -0,0 +1,284 @@
+/*!
+ * body-parser
+ * Copyright(c) 2014 Jonathan Ong
+ * Copyright(c) 2014-2015 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict'
+
+/**
+ * Module dependencies.
+ * @private
+ */
+
+var bytes = require('bytes')
+var contentType = require('content-type')
+var createError = require('http-errors')
+var debug = require('debug')('body-parser:urlencoded')
+var deprecate = require('depd')('body-parser')
+var read = require('../read')
+var typeis = require('type-is')
+
+/**
+ * Module exports.
+ */
+
+module.exports = urlencoded
+
+/**
+ * Cache of parser modules.
+ */
+
+var parsers = Object.create(null)
+
+/**
+ * Create a middleware to parse urlencoded bodies.
+ *
+ * @param {object} [options]
+ * @return {function}
+ * @public
+ */
+
+function urlencoded (options) {
+  var opts = options || {}
+
+  // notice because option default will flip in next major
+  if (opts.extended === undefined) {
+    deprecate('undefined extended: provide extended option')
+  }
+
+  var extended = opts.extended !== false
+  var inflate = opts.inflate !== false
+  var limit = typeof opts.limit !== 'number'
+    ? bytes.parse(opts.limit || '100kb')
+    : opts.limit
+  var type = opts.type || 'application/x-www-form-urlencoded'
+  var verify = opts.verify || false
+
+  if (verify !== false && typeof verify !== 'function') {
+    throw new TypeError('option verify must be function')
+  }
+
+  // create the appropriate query parser
+  var queryparse = extended
+    ? extendedparser(opts)
+    : simpleparser(opts)
+
+  // create the appropriate type checking function
+  var shouldParse = typeof type !== 'function'
+    ? typeChecker(type)
+    : type
+
+  function parse (body) {
+    return body.length
+      ? queryparse(body)
+      : {}
+  }
+
+  return function urlencodedParser (req, res, next) {
+    if (req._body) {
+      debug('body already parsed')
+      next()
+      return
+    }
+
+    req.body = req.body || {}
+
+    // skip requests without bodies
+    if (!typeis.hasBody(req)) {
+      debug('skip empty body')
+      next()
+      return
+    }
+
+    debug('content-type %j', req.headers['content-type'])
+
+    // determine if request should be parsed
+    if (!shouldParse(req)) {
+      debug('skip parsing')
+      next()
+      return
+    }
+
+    // assert charset
+    var charset = getCharset(req) || 'utf-8'
+    if (charset !== 'utf-8') {
+      debug('invalid charset')
+      next(createError(415, 'unsupported charset "' + charset.toUpperCase() + '"', {
+        charset: charset,
+        type: 'charset.unsupported'
+      }))
+      return
+    }
+
+    // read
+    read(req, res, next, parse, debug, {
+      debug: debug,
+      encoding: charset,
+      inflate: inflate,
+      limit: limit,
+      verify: verify
+    })
+  }
+}
+
+/**
+ * Get the extended query parser.
+ *
+ * @param {object} options
+ */
+
+function extendedparser (options) {
+  var parameterLimit = options.parameterLimit !== undefined
+    ? options.parameterLimit
+    : 1000
+  var parse = parser('qs')
+
+  if (isNaN(parameterLimit) || parameterLimit < 1) {
+    throw new TypeError('option parameterLimit must be a positive number')
+  }
+
+  if (isFinite(parameterLimit)) {
+    parameterLimit = parameterLimit | 0
+  }
+
+  return function queryparse (body) {
+    var paramCount = parameterCount(body, parameterLimit)
+
+    if (paramCount === undefined) {
+      debug('too many parameters')
+      throw createError(413, 'too many parameters', {
+        type: 'parameters.too.many'
+      })
+    }
+
+    var arrayLimit = Math.max(100, paramCount)
+
+    debug('parse extended urlencoding')
+    return parse(body, {
+      allowPrototypes: true,
+      arrayLimit: arrayLimit,
+      depth: Infinity,
+      parameterLimit: parameterLimit
+    })
+  }
+}
+
+/**
+ * Get the charset of a request.
+ *
+ * @param {object} req
+ * @api private
+ */
+
+function getCharset (req) {
+  try {
+    return (contentType.parse(req).parameters.charset || '').toLowerCase()
+  } catch (e) {
+    return undefined
+  }
+}
+
+/**
+ * Count the number of parameters, stopping once limit reached
+ *
+ * @param {string} body
+ * @param {number} limit
+ * @api private
+ */
+
+function parameterCount (body, limit) {
+  var count = 0
+  var index = 0
+
+  while ((index = body.indexOf('&', index)) !== -1) {
+    count++
+    index++
+
+    if (count === limit) {
+      return undefined
+    }
+  }
+
+  return count
+}
+
+/**
+ * Get parser for module name dynamically.
+ *
+ * @param {string} name
+ * @return {function}
+ * @api private
+ */
+
+function parser (name) {
+  var mod = parsers[name]
+
+  if (mod !== undefined) {
+    return mod.parse
+  }
+
+  // this uses a switch for static require analysis
+  switch (name) {
+    case 'qs':
+      mod = require('qs')
+      break
+    case 'querystring':
+      mod = require('querystring')
+      break
+  }
+
+  // store to prevent invoking require()
+  parsers[name] = mod
+
+  return mod.parse
+}
+
+/**
+ * Get the simple query parser.
+ *
+ * @param {object} options
+ */
+
+function simpleparser (options) {
+  var parameterLimit = options.parameterLimit !== undefined
+    ? options.parameterLimit
+    : 1000
+  var parse = parser('querystring')
+
+  if (isNaN(parameterLimit) || parameterLimit < 1) {
+    throw new TypeError('option parameterLimit must be a positive number')
+  }
+
+  if (isFinite(parameterLimit)) {
+    parameterLimit = parameterLimit | 0
+  }
+
+  return function queryparse (body) {
+    var paramCount = parameterCount(body, parameterLimit)
+
+    if (paramCount === undefined) {
+      debug('too many parameters')
+      throw createError(413, 'too many parameters', {
+        type: 'parameters.too.many'
+      })
+    }
+
+    debug('parse urlencoding')
+    return parse(body, undefined, undefined, {maxKeys: parameterLimit})
+  }
+}
+
+/**
+ * Get the simple type checker.
+ *
+ * @param {string} type
+ * @return {function}
+ */
+
+function typeChecker (type) {
+  return function checkType (req) {
+    return Boolean(typeis(req, type))
+  }
+}
diff --git a/node_modules/body-parser/package.json b/node_modules/body-parser/package.json
new file mode 100644
index 0000000..e399e5e
--- /dev/null
+++ b/node_modules/body-parser/package.json
@@ -0,0 +1,127 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "body-parser@1.18.2",
+        "scope": null,
+        "escapedName": "body-parser",
+        "name": "body-parser",
+        "rawSpec": "1.18.2",
+        "spec": "1.18.2",
+        "type": "version"
+      },
+      "/Users/steveng/repo/cordova/cordova-browser/node_modules/express"
+    ]
+  ],
+  "_from": "body-parser@1.18.2",
+  "_id": "body-parser@1.18.2",
+  "_inCache": true,
+  "_location": "/body-parser",
+  "_nodeVersion": "6.11.1",
+  "_npmOperationalInternal": {
+    "host": "s3://npm-registry-packages",
+    "tmp": "tmp/body-parser-1.18.2.tgz_1506099009907_0.5088193896226585"
+  },
+  "_npmUser": {
+    "name": "dougwilson",
+    "email": "doug@somethingdoug.com"
+  },
+  "_npmVersion": "3.10.10",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "body-parser@1.18.2",
+    "scope": null,
+    "escapedName": "body-parser",
+    "name": "body-parser",
+    "rawSpec": "1.18.2",
+    "spec": "1.18.2",
+    "type": "version"
+  },
+  "_requiredBy": [
+    "/express"
+  ],
+  "_resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz",
+  "_shasum": "87678a19d84b47d859b83199bd59bce222b10454",
+  "_shrinkwrap": null,
+  "_spec": "body-parser@1.18.2",
+  "_where": "/Users/steveng/repo/cordova/cordova-browser/node_modules/express",
+  "bugs": {
+    "url": "https://github.com/expressjs/body-parser/issues"
+  },
+  "contributors": [
+    {
+      "name": "Douglas Christopher Wilson",
+      "email": "doug@somethingdoug.com"
+    },
+    {
+      "name": "Jonathan Ong",
+      "email": "me@jongleberry.com",
+      "url": "http://jongleberry.com"
+    }
+  ],
+  "dependencies": {
+    "bytes": "3.0.0",
+    "content-type": "~1.0.4",
+    "debug": "2.6.9",
+    "depd": "~1.1.1",
+    "http-errors": "~1.6.2",
+    "iconv-lite": "0.4.19",
+    "on-finished": "~2.3.0",
+    "qs": "6.5.1",
+    "raw-body": "2.3.2",
+    "type-is": "~1.6.15"
+  },
+  "description": "Node.js body parsing middleware",
+  "devDependencies": {
+    "eslint": "3.19.0",
+    "eslint-config-standard": "10.2.1",
+    "eslint-plugin-import": "2.7.0",
+    "eslint-plugin-markdown": "1.0.0-beta.6",
+    "eslint-plugin-node": "5.1.1",
+    "eslint-plugin-promise": "3.5.0",
+    "eslint-plugin-standard": "3.0.1",
+    "istanbul": "0.4.5",
+    "methods": "1.1.2",
+    "mocha": "2.5.3",
+    "safe-buffer": "5.1.1",
+    "supertest": "1.1.0"
+  },
+  "directories": {},
+  "dist": {
+    "shasum": "87678a19d84b47d859b83199bd59bce222b10454",
+    "tarball": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz"
+  },
+  "engines": {
+    "node": ">= 0.8"
+  },
+  "files": [
+    "lib/",
+    "LICENSE",
+    "HISTORY.md",
+    "index.js"
+  ],
+  "gitHead": "b2659a7af3b413a2d1df274bef409fe6cdcf6b8f",
+  "homepage": "https://github.com/expressjs/body-parser#readme",
+  "license": "MIT",
+  "maintainers": [
+    {
+      "name": "dougwilson",
+      "email": "doug@somethingdoug.com"
+    }
+  ],
+  "name": "body-parser",
+  "optionalDependencies": {},
+  "readme": "# body-parser\n\n[![NPM Version][npm-image]][npm-url]\n[![NPM Downloads][downloads-image]][downloads-url]\n[![Build Status][travis-image]][travis-url]\n[![Test Coverage][coveralls-image]][coveralls-url]\n[![Gratipay][gratipay-image]][gratipay-url]\n\nNode.js body parsing middleware.\n\nParse incoming request bodies in a middleware before your handlers, available\nunder the `req.body` property.\n\n[Learn about the anatomy of an HTTP transaction in Node.js](https://nodejs.org/en/docs/guides/anatomy-of-an-http-transaction/).\n\n_This does not handle multipart bodies_, due to their complex and typically\nlarge nature. For multipart bodies, you may be interested in the following\nmodules:\n\n  * [busboy](https://www.npmjs.org/package/busboy#readme) and\n    [connect-busboy](https://www.npmjs.org/package/connect-busboy#readme)\n  * [multiparty](https://www.npmjs.org/package/multiparty#readme) and\n    [connect-multiparty](https://www.npmjs.org/package/connect-multiparty#readme)\n  * [formidable](https://www.npmjs.org/package/formidable#readme)\n  * [multer](https://www.npmjs.org/package/multer#readme)\n\nThis module provides the following parsers:\n\n  * [JSON body parser](#bodyparserjsonoptions)\n  * [Raw body parser](#bodyparserrawoptions)\n  * [Text body parser](#bodyparsertextoptions)\n  * [URL-encoded form body parser](#bodyparserurlencodedoptions)\n\nOther body parsers you might be interested in:\n\n- [body](https://www.npmjs.org/package/body#readme)\n- [co-body](https://www.npmjs.org/package/co-body#readme)\n\n## Installation\n\n```sh\n$ npm install body-parser\n```\n\n## API\n\n<!-- eslint-disable no-unused-vars -->\n\n```js\nvar bodyParser = require('body-parser')\n```\n\nThe `bodyParser` object exposes various factories to create middlewares. All\nmiddlewares will populate the `req.body` property with the parsed body when\nthe `Content-Type` request header matches the `type` option, or an empty\nobject (`{}`) if there was no body to parse, the `Content-Type` was not matched,\nor an error occurred.\n\nThe various errors returned by this module are described in the\n[errors section](#errors).\n\n### bodyParser.json([options])\n\nReturns middleware that only parses `json` and only looks at requests where\nthe `Content-Type` header matches the `type` option. This parser accepts any\nUnicode encoding of the body and supports automatic inflation of `gzip` and\n`deflate` encodings.\n\nA new `body` object containing the parsed data is populated on the `request`\nobject after the middleware (i.e. `req.body`).\n\n#### Options\n\nThe `json` function takes an optional `options` object that may contain any of\nthe following keys:\n\n##### inflate\n\nWhen set to `true`, then deflated (compressed) bodies will be inflated; when\n`false`, deflated bodies are rejected. Defaults to `true`.\n\n##### limit\n\nControls the maximum request body size. If this is a number, then the value\nspecifies the number of bytes; if it is a string, the value is passed to the\n[bytes](https://www.npmjs.com/package/bytes) library for parsing. Defaults\nto `'100kb'`.\n\n##### reviver\n\nThe `reviver` option is passed directly to `JSON.parse` as the second\nargument. You can find more information on this argument\n[in the MDN documentation about JSON.parse](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Example.3A_Using_the_reviver_parameter).\n\n##### strict\n\nWhen set to `true`, will only accept arrays and objects; when `false` will\naccept anything `JSON.parse` accepts. Defaults to `true`.\n\n##### type\n\nThe `type` option is used to determine what media type the middleware will\nparse. This option can be a function or a string. If a string, `type` option\nis passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme)\nlibrary and this can be an extension name (like `json`), a mime type (like\n`application/json`), or a mime type with a wildcard (like `*/*` or `*/json`).\nIf a function, the `type` option is called as `fn(req)` and the request is\nparsed if it returns a truthy value. Defaults to `application/json`.\n\n##### verify\n\nThe `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`,\nwhere `buf` is a `Buffer` of the raw request body and `encoding` is the\nencoding of the request. The parsing can be aborted by throwing an error.\n\n### bodyParser.raw([options])\n\nReturns middleware that parses all bodies as a `Buffer` and only looks at\nrequests where the `Content-Type` header matches the `type` option. This\nparser supports automatic inflation of `gzip` and `deflate` encodings.\n\nA new `body` object containing the parsed data is populated on the `request`\nobject after the middleware (i.e. `req.body`). This will be a `Buffer` object\nof the body.\n\n#### Options\n\nThe `raw` function takes an optional `options` object that may contain any of\nthe following keys:\n\n##### inflate\n\nWhen set to `true`, then deflated (compressed) bodies will be inflated; when\n`false`, deflated bodies are rejected. Defaults to `true`.\n\n##### limit\n\nControls the maximum request body size. If this is a number, then the value\nspecifies the number of bytes; if it is a string, the value is passed to the\n[bytes](https://www.npmjs.com/package/bytes) library for parsing. Defaults\nto `'100kb'`.\n\n##### type\n\nThe `type` option is used to determine what media type the middleware will\nparse. This option can be a function or a string. If a string, `type` option\nis passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme)\nlibrary and this can be an extension name (like `bin`), a mime type (like\n`application/octet-stream`), or a mime type with a wildcard (like `*/*` or\n`application/*`). If a function, the `type` option is called as `fn(req)`\nand the request is parsed if it returns a truthy value. Defaults to\n`application/octet-stream`.\n\n##### verify\n\nThe `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`,\nwhere `buf` is a `Buffer` of the raw request body and `encoding` is the\nencoding of the request. The parsing can be aborted by throwing an error.\n\n### bodyParser.text([options])\n\nReturns middleware that parses all bodies as a string and only looks at\nrequests where the `Content-Type` header matches the `type` option. This\nparser supports automatic inflation of `gzip` and `deflate` encodings.\n\nA new `body` string containing the parsed data is populated on the `request`\nobject after the middleware (i.e. `req.body`). This will be a string of the\nbody.\n\n#### Options\n\nThe `text` function takes an optional `options` object that may contain any of\nthe following keys:\n\n##### defaultCharset\n\nSpecify the default character set for the text content if the charset is not\nspecified in the `Content-Type` header of the request. Defaults to `utf-8`.\n\n##### inflate\n\nWhen set to `true`, then deflated (compressed) bodies will be inflated; when\n`false`, deflated bodies are rejected. Defaults to `true`.\n\n##### limit\n\nControls the maximum request body size. If this is a number, then the value\nspecifies the number of bytes; if it is a string, the value is passed to the\n[bytes](https://www.npmjs.com/package/bytes) library for parsing. Defaults\nto `'100kb'`.\n\n##### type\n\nThe `type` option is used to determine what media type the middleware will\nparse. This option can be a function or a string. If a string, `type` option\nis passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme)\nlibrary and this can be an extension name (like `txt`), a mime type (like\n`text/plain`), or a mime type with a wildcard (like `*/*` or `text/*`).\nIf a function, the `type` option is called as `fn(req)` and the request is\nparsed if it returns a truthy value. Defaults to `text/plain`.\n\n##### verify\n\nThe `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`,\nwhere `buf` is a `Buffer` of the raw request body and `encoding` is the\nencoding of the request. The parsing can be aborted by throwing an error.\n\n### bodyParser.urlencoded([options])\n\nReturns middleware that only parses `urlencoded` bodies and only looks at\nrequests where the `Content-Type` header matches the `type` option. This\nparser accepts only UTF-8 encoding of the body and supports automatic\ninflation of `gzip` and `deflate` encodings.\n\nA new `body` object containing the parsed data is populated on the `request`\nobject after the middleware (i.e. `req.body`). This object will contain\nkey-value pairs, where the value can be a string or array (when `extended` is\n`false`), or any type (when `extended` is `true`).\n\n#### Options\n\nThe `urlencoded` function takes an optional `options` object that may contain\nany of the following keys:\n\n##### extended\n\nThe `extended` option allows to choose between parsing the URL-encoded data\nwith the `querystring` library (when `false`) or the `qs` library (when\n`true`). The \"extended\" syntax allows for rich objects and arrays to be\nencoded into the URL-encoded format, allowing for a JSON-like experience\nwith URL-encoded. For more information, please\n[see the qs library](https://www.npmjs.org/package/qs#readme).\n\nDefaults to `true`, but using the default has been deprecated. Please\nresearch into the difference between `qs` and `querystring` and choose the\nappropriate setting.\n\n##### inflate\n\nWhen set to `true`, then deflated (compressed) bodies will be inflated; when\n`false`, deflated bodies are rejected. Defaults to `true`.\n\n##### limit\n\nControls the maximum request body size. If this is a number, then the value\nspecifies the number of bytes; if it is a string, the value is passed to the\n[bytes](https://www.npmjs.com/package/bytes) library for parsing. Defaults\nto `'100kb'`.\n\n##### parameterLimit\n\nThe `parameterLimit` option controls the maximum number of parameters that\nare allowed in the URL-encoded data. If a request contains more parameters\nthan this value, a 413 will be returned to the client. Defaults to `1000`.\n\n##### type\n\nThe `type` option is used to determine what media type the middleware will\nparse. This option can be a function or a string. If a string, `type` option\nis passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme)\nlibrary and this can be an extension name (like `urlencoded`), a mime type (like\n`application/x-www-form-urlencoded`), or a mime type with a wildcard (like\n`*/x-www-form-urlencoded`). If a function, the `type` option is called as\n`fn(req)` and the request is parsed if it returns a truthy value. Defaults\nto `application/x-www-form-urlencoded`.\n\n##### verify\n\nThe `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`,\nwhere `buf` is a `Buffer` of the raw request body and `encoding` is the\nencoding of the request. The parsing can be aborted by throwing an error.\n\n## Errors\n\nThe middlewares provided by this module create errors depending on the error\ncondition during parsing. The errors will typically have a `status`/`statusCode`\nproperty that contains the suggested HTTP response code, an `expose` property\nto determine if the `message` property should be displayed to the client, a\n`type` property to determine the type of error without matching against the\n`message`, and a `body` property containing the read body, if available.\n\nThe following are the common errors emitted, though any error can come through\nfor various reasons.\n\n### content encoding unsupported\n\nThis error will occur when the request had a `Content-Encoding` header that\ncontained an encoding but the \"inflation\" option was set to `false`. The\n`status` property is set to `415`, the `type` property is set to\n`'encoding.unsupported'`, and the `charset` property will be set to the\nencoding that is unsupported.\n\n### request aborted\n\nThis error will occur when the request is aborted by the client before reading\nthe body has finished. The `received` property will be set to the number of\nbytes received before the request was aborted and the `expected` property is\nset to the number of expected bytes. The `status` property is set to `400`\nand `type` property is set to `'request.aborted'`.\n\n### request entity too large\n\nThis error will occur when the request body's size is larger than the \"limit\"\noption. The `limit` property will be set to the byte limit and the `length`\nproperty will be set to the request body's length. The `status` property is\nset to `413` and the `type` property is set to `'entity.too.large'`.\n\n### request size did not match content length\n\nThis error will occur when the request's length did not match the length from\nthe `Content-Length` header. This typically occurs when the request is malformed,\ntypically when the `Content-Length` header was calculated based on characters\ninstead of bytes. The `status` property is set to `400` and the `type` property\nis set to `'request.size.invalid'`.\n\n### stream encoding should not be set\n\nThis error will occur when something called the `req.setEncoding` method prior\nto this middleware. This module operates directly on bytes only and you cannot\ncall `req.setEncoding` when using this module. The `status` property is set to\n`500` and the `type` property is set to `'stream.encoding.set'`.\n\n### too many parameters\n\nThis error will occur when the content of the request exceeds the configured\n`parameterLimit` for the `urlencoded` parser. The `status` property is set to\n`413` and the `type` property is set to `'parameters.too.many'`.\n\n### unsupported charset \"BOGUS\"\n\nThis error will occur when the request had a charset parameter in the\n`Content-Type` header, but the `iconv-lite` module does not support it OR the\nparser does not support it. The charset is contained in the message as well\nas in the `charset` property. The `status` property is set to `415`, the\n`type` property is set to `'charset.unsupported'`, and the `charset` property\nis set to the charset that is unsupported.\n\n### unsupported content encoding \"bogus\"\n\nThis error will occur when the request had a `Content-Encoding` header that\ncontained an unsupported encoding. The encoding is contained in the message\nas well as in the `encoding` property. The `status` property is set to `415`,\nthe `type` property is set to `'encoding.unsupported'`, and the `encoding`\nproperty is set to the encoding that is unsupported.\n\n## Examples\n\n### Express/Connect top-level generic\n\nThis example demonstrates adding a generic JSON and URL-encoded parser as a\ntop-level middleware, which will parse the bodies of all incoming requests.\nThis is the simplest setup.\n\n```js\nvar express = require('express')\nvar bodyParser = require('body-parser')\n\nvar app = express()\n\n// parse application/x-www-form-urlencoded\napp.use(bodyParser.urlencoded({ extended: false }))\n\n// parse application/json\napp.use(bodyParser.json())\n\napp.use(function (req, res) {\n  res.setHeader('Content-Type', 'text/plain')\n  res.write('you posted:\\n')\n  res.end(JSON.stringify(req.body, null, 2))\n})\n```\n\n### Express route-specific\n\nThis example demonstrates adding body parsers specifically to the routes that\nneed them. In general, this is the most recommended way to use body-parser with\nExpress.\n\n```js\nvar express = require('express')\nvar bodyParser = require('body-parser')\n\nvar app = express()\n\n// create application/json parser\nvar jsonParser = bodyParser.json()\n\n// create application/x-www-form-urlencoded parser\nvar urlencodedParser = bodyParser.urlencoded({ extended: false })\n\n// POST /login gets urlencoded bodies\napp.post('/login', urlencodedParser, function (req, res) {\n  if (!req.body) return res.sendStatus(400)\n  res.send('welcome, ' + req.body.username)\n})\n\n// POST /api/users gets JSON bodies\napp.post('/api/users', jsonParser, function (req, res) {\n  if (!req.body) return res.sendStatus(400)\n  // create user in req.body\n})\n```\n\n### Change accepted type for parsers\n\nAll the parsers accept a `type` option which allows you to change the\n`Content-Type` that the middleware will parse.\n\n```js\nvar express = require('express')\nvar bodyParser = require('body-parser')\n\nvar app = express()\n\n// parse various different custom JSON types as JSON\napp.use(bodyParser.json({ type: 'application/*+json' }))\n\n// parse some custom thing into a Buffer\napp.use(bodyParser.raw({ type: 'application/vnd.custom-type' }))\n\n// parse an HTML body into a string\napp.use(bodyParser.text({ type: 'text/html' }))\n```\n\n## License\n\n[MIT](LICENSE)\n\n[npm-image]: https://img.shields.io/npm/v/body-parser.svg\n[npm-url]: https://npmjs.org/package/body-parser\n[travis-image]: https://img.shields.io/travis/expressjs/body-parser/master.svg\n[travis-url]: https://travis-ci.org/expressjs/body-parser\n[coveralls-image]: https://img.shields.io/coveralls/expressjs/body-parser/master.svg\n[coveralls-url]: https://coveralls.io/r/expressjs/body-parser?branch=master\n[downloads-image]: https://img.shields.io/npm/dm/body-parser.svg\n[downloads-url]: https://npmjs.org/package/body-parser\n[gratipay-image]: https://img.shields.io/gratipay/dougwilson.svg\n[gratipay-url]: https://www.gratipay.com/dougwilson/\n",
+  "readmeFilename": "README.md",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/expressjs/body-parser.git"
+  },
+  "scripts": {
+    "lint": "eslint --plugin markdown --ext js,md .",
+    "test": "mocha --require test/support/env --reporter spec --check-leaks --bail test/",
+    "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks test/",
+    "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks test/"
+  },
+  "version": "1.18.2"
+}
diff --git a/node_modules/bytes/History.md b/node_modules/bytes/History.md
index 6b7231d..13d463a 100644
--- a/node_modules/bytes/History.md
+++ b/node_modules/bytes/History.md
@@ -1,3 +1,10 @@
+3.0.0 / 2017-08-31
+==================
+
+  * Change "kB" to "KB" in format output
+  * Remove support for Node.js 0.6
+  * Remove support for ComponentJS
+
 2.5.0 / 2017-03-24
 ==================
 
diff --git a/node_modules/bytes/Readme.md b/node_modules/bytes/Readme.md
index ac555ab..9b53745 100644
--- a/node_modules/bytes/Readme.md
+++ b/node_modules/bytes/Readme.md
@@ -7,6 +7,16 @@
 
 Utility to parse a string bytes (ex: `1TB`) to bytes (`1099511627776`) and vice-versa.
 
+## Installation
+
+This is a [Node.js](https://nodejs.org/en/) module available through the
+[npm registry](https://www.npmjs.com/). Installation is done using the
+[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
+
+```bash
+$ npm install bytes
+```
+
 ## Usage
 
 ```js
@@ -20,8 +30,8 @@
 
 **Arguments**
 
-| Name    | Type   | Description        |
-|---------|--------|--------------------|
+| Name    | Type     | Description        |
+|---------|----------|--------------------|
 | value   | `number` | Value in bytes     |
 | options | `Object` | Conversion options |
 
@@ -32,20 +42,20 @@
 | decimalPlaces | `number`|`null` | Maximum number of decimal places to include in output. Default value to `2`. |
 | fixedDecimals | `boolean`|`null` | Whether to always display the maximum number of decimal places. Default value to `false` |
 | thousandsSeparator | `string`|`null` | Example of values: `' '`, `','` and `.`... Default value to `''`. |
-| unit | `string`|`null` | The unit in which the result will be returned (B/kB/MB/GB/TB). Default value to `''` (which means auto detect). |
+| unit | `string`|`null` | The unit in which the result will be returned (B/KB/MB/GB/TB). Default value to `''` (which means auto detect). |
 | unitSeparator | `string`|`null` | Separator to use between number and unit. Default value to `''`. |
 
 **Returns**
 
-| Name    | Type        | Description             |
-|---------|-------------|-------------------------|
+| Name    | Type             | Description                                     |
+|---------|------------------|-------------------------------------------------|
 | results | `string`|`null` | Return null upon error. String value otherwise. |
 
 **Example**
 
 ```js
 bytes(1024);
-// output: '1kB'
+// output: '1KB'
 
 bytes(1000);
 // output: '1000B'
@@ -54,10 +64,10 @@
 // output: '1 000B'
 
 bytes(1024 * 1.7, {decimalPlaces: 0});
-// output: '2kB'
+// output: '2KB'
 
 bytes(1024, {unitSeparator: ' '});
-// output: '1 kB'
+// output: '1 KB'
 
 ```
 
@@ -91,7 +101,7 @@
 **Example**
 
 ```js
-bytes('1kB');
+bytes('1KB');
 // output: 1024
 
 bytes('1024');
@@ -101,13 +111,6 @@
 // output: 1024
 ```
 
-## Installation
-
-```bash
-npm install bytes --save
-component install visionmedia/bytes.js
-```
-
 ## License 
 
 [MIT](LICENSE)
diff --git a/node_modules/bytes/index.js b/node_modules/bytes/index.js
index b008572..1e39afd 100644
--- a/node_modules/bytes/index.js
+++ b/node_modules/bytes/index.js
@@ -33,9 +33,6 @@
   tb: ((1 << 30) * 1024)
 };
 
-// TODO: use is-finite module?
-var numberIsFinite = Number.isFinite || function (v) { return typeof v === 'number' && isFinite(v); };
-
 var parseRegExp = /^((-|\+)?(\d+(?:\.\d+)?)) *(kb|mb|gb|tb)$/i;
 
 /**
@@ -84,7 +81,7 @@
  */
 
 function format(value, options) {
-  if (!numberIsFinite(value)) {
+  if (!Number.isFinite(value)) {
     return null;
   }
 
@@ -103,7 +100,7 @@
     } else if (mag >= map.mb) {
       unit = 'MB';
     } else if (mag >= map.kb) {
-      unit = 'kB';
+      unit = 'KB';
     } else {
       unit = 'B';
     }
diff --git a/node_modules/bytes/package.json b/node_modules/bytes/package.json
index 8459f96..1eb9ec2 100644
--- a/node_modules/bytes/package.json
+++ b/node_modules/bytes/package.json
@@ -2,48 +2,50 @@
   "_args": [
     [
       {
-        "raw": "bytes@2.5.0",
+        "raw": "bytes@3.0.0",
         "scope": null,
         "escapedName": "bytes",
         "name": "bytes",
-        "rawSpec": "2.5.0",
-        "spec": "2.5.0",
+        "rawSpec": "3.0.0",
+        "spec": "3.0.0",
         "type": "version"
       },
       "/Users/steveng/repo/cordova/cordova-browser/node_modules/compression"
     ]
   ],
-  "_from": "bytes@2.5.0",
-  "_id": "bytes@2.5.0",
+  "_from": "bytes@3.0.0",
+  "_id": "bytes@3.0.0",
   "_inCache": true,
   "_location": "/bytes",
-  "_nodeVersion": "4.7.3",
+  "_nodeVersion": "6.11.1",
   "_npmOperationalInternal": {
-    "host": "packages-12-west.internal.npmjs.com",
-    "tmp": "tmp/bytes-2.5.0.tgz_1490416399283_0.2922299497295171"
+    "host": "s3://npm-registry-packages",
+    "tmp": "tmp/bytes-3.0.0.tgz_1504216364188_0.5158762519713491"
   },
   "_npmUser": {
     "name": "dougwilson",
     "email": "doug@somethingdoug.com"
   },
-  "_npmVersion": "2.15.11",
+  "_npmVersion": "3.10.10",
   "_phantomChildren": {},
   "_requested": {
-    "raw": "bytes@2.5.0",
+    "raw": "bytes@3.0.0",
     "scope": null,
     "escapedName": "bytes",
     "name": "bytes",
-    "rawSpec": "2.5.0",
-    "spec": "2.5.0",
+    "rawSpec": "3.0.0",
+    "spec": "3.0.0",
     "type": "version"
   },
   "_requiredBy": [
-    "/compression"
+    "/body-parser",
+    "/compression",
+    "/raw-body"
   ],
-  "_resolved": "https://registry.npmjs.org/bytes/-/bytes-2.5.0.tgz",
-  "_shasum": "4c9423ea2d252c270c41b2bdefeff9bb6b62c06a",
+  "_resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
+  "_shasum": "d32815404d689699f85a4ea4fa8755dd13a96048",
   "_shrinkwrap": null,
-  "_spec": "bytes@2.5.0",
+  "_spec": "bytes@3.0.0",
   "_where": "/Users/steveng/repo/cordova/cordova-browser/node_modules/compression",
   "author": {
     "name": "TJ Holowaychuk",
@@ -53,11 +55,6 @@
   "bugs": {
     "url": "https://github.com/visionmedia/bytes.js/issues"
   },
-  "component": {
-    "scripts": {
-      "bytes/index.js": "index.js"
-    }
-  },
   "contributors": [
     {
       "name": "Jed Watson",
@@ -71,16 +68,16 @@
   "dependencies": {},
   "description": "Utility to parse a string bytes to bytes and vice-versa",
   "devDependencies": {
-    "mocha": "1.21.5",
-    "nyc": "10.1.2"
+    "mocha": "2.5.3",
+    "nyc": "10.3.2"
   },
   "directories": {},
   "dist": {
-    "shasum": "4c9423ea2d252c270c41b2bdefeff9bb6b62c06a",
-    "tarball": "https://registry.npmjs.org/bytes/-/bytes-2.5.0.tgz"
+    "shasum": "d32815404d689699f85a4ea4fa8755dd13a96048",
+    "tarball": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz"
   },
   "engines": {
-    "node": ">= 0.6"
+    "node": ">= 0.8"
   },
   "files": [
     "History.md",
@@ -88,7 +85,7 @@
     "Readme.md",
     "index.js"
   ],
-  "gitHead": "a4b9af2bf289175f12b3538eb172f2489844b1ec",
+  "gitHead": "25d4cb488aea3b637448a85fa297d9e65b4b4e04",
   "homepage": "https://github.com/visionmedia/bytes.js#readme",
   "keywords": [
     "byte",
@@ -112,7 +109,7 @@
   ],
   "name": "bytes",
   "optionalDependencies": {},
-  "readme": "# Bytes utility\n\n[![NPM Version][npm-image]][npm-url]\n[![NPM Downloads][downloads-image]][downloads-url]\n[![Build Status][travis-image]][travis-url]\n[![Test Coverage][coveralls-image]][coveralls-url]\n\nUtility to parse a string bytes (ex: `1TB`) to bytes (`1099511627776`) and vice-versa.\n\n## Usage\n\n```js\nvar bytes = require('bytes');\n```\n\n#### bytes.format(number value, [options]): string|null\n\nFormat the given value in bytes into a string. If the value is negative, it is kept as such. If it is a float, it is\n rounded.\n\n**Arguments**\n\n| Name    | Type   | Description        |\n|---------|--------|--------------------|\n| value   | `number` | Value in bytes     |\n| options | `Object` | Conversion options |\n\n**Options**\n\n| Property          | Type   | Description                                                                             |\n|-------------------|--------|-----------------------------------------------------------------------------------------|\n| decimalPlaces | `number`|`null` | Maximum number of decimal places to include in output. Default value to `2`. |\n| fixedDecimals | `boolean`|`null` | Whether to always display the maximum number of decimal places. Default value to `false` |\n| thousandsSeparator | `string`|`null` | Example of values: `' '`, `','` and `.`... Default value to `''`. |\n| unit | `string`|`null` | The unit in which the result will be returned (B/kB/MB/GB/TB). Default value to `''` (which means auto detect). |\n| unitSeparator | `string`|`null` | Separator to use between number and unit. Default value to `''`. |\n\n**Returns**\n\n| Name    | Type        | Description             |\n|---------|-------------|-------------------------|\n| results | `string`|`null` | Return null upon error. String value otherwise. |\n\n**Example**\n\n```js\nbytes(1024);\n// output: '1kB'\n\nbytes(1000);\n// output: '1000B'\n\nbytes(1000, {thousandsSeparator: ' '});\n// output: '1 000B'\n\nbytes(1024 * 1.7, {decimalPlaces: 0});\n// output: '2kB'\n\nbytes(1024, {unitSeparator: ' '});\n// output: '1 kB'\n\n```\n\n#### bytes.parse(string|number value): number|null\n\nParse the string value into an integer in bytes. If no unit is given, or `value`\nis a number, it is assumed the value is in bytes.\n\nSupported units and abbreviations are as follows and are case-insensitive:\n\n  * `b` for bytes\n  * `kb` for kilobytes\n  * `mb` for megabytes\n  * `gb` for gigabytes\n  * `tb` for terabytes\n\nThe units are in powers of two, not ten. This means 1kb = 1024b according to this parser.\n\n**Arguments**\n\n| Name          | Type   | Description        |\n|---------------|--------|--------------------|\n| value   | `string`|`number` | String to parse, or number in bytes.   |\n\n**Returns**\n\n| Name    | Type        | Description             |\n|---------|-------------|-------------------------|\n| results | `number`|`null` | Return null upon error. Value in bytes otherwise. |\n\n**Example**\n\n```js\nbytes('1kB');\n// output: 1024\n\nbytes('1024');\n// output: 1024\n\nbytes(1024);\n// output: 1024\n```\n\n## Installation\n\n```bash\nnpm install bytes --save\ncomponent install visionmedia/bytes.js\n```\n\n## License \n\n[MIT](LICENSE)\n\n[downloads-image]: https://img.shields.io/npm/dm/bytes.svg\n[downloads-url]: https://npmjs.org/package/bytes\n[npm-image]: https://img.shields.io/npm/v/bytes.svg\n[npm-url]: https://npmjs.org/package/bytes\n[travis-image]: https://img.shields.io/travis/visionmedia/bytes.js/master.svg\n[travis-url]: https://travis-ci.org/visionmedia/bytes.js\n[coveralls-image]: https://img.shields.io/coveralls/visionmedia/bytes.js/master.svg\n[coveralls-url]: https://coveralls.io/r/visionmedia/bytes.js?branch=master\n",
+  "readme": "# Bytes utility\n\n[![NPM Version][npm-image]][npm-url]\n[![NPM Downloads][downloads-image]][downloads-url]\n[![Build Status][travis-image]][travis-url]\n[![Test Coverage][coveralls-image]][coveralls-url]\n\nUtility to parse a string bytes (ex: `1TB`) to bytes (`1099511627776`) and vice-versa.\n\n## Installation\n\nThis is a [Node.js](https://nodejs.org/en/) module available through the\n[npm registry](https://www.npmjs.com/). Installation is done using the\n[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):\n\n```bash\n$ npm install bytes\n```\n\n## Usage\n\n```js\nvar bytes = require('bytes');\n```\n\n#### bytes.format(number value, [options]): string|null\n\nFormat the given value in bytes into a string. If the value is negative, it is kept as such. If it is a float, it is\n rounded.\n\n**Arguments**\n\n| Name    | Type     | Description        |\n|---------|----------|--------------------|\n| value   | `number` | Value in bytes     |\n| options | `Object` | Conversion options |\n\n**Options**\n\n| Property          | Type   | Description                                                                             |\n|-------------------|--------|-----------------------------------------------------------------------------------------|\n| decimalPlaces | `number`|`null` | Maximum number of decimal places to include in output. Default value to `2`. |\n| fixedDecimals | `boolean`|`null` | Whether to always display the maximum number of decimal places. Default value to `false` |\n| thousandsSeparator | `string`|`null` | Example of values: `' '`, `','` and `.`... Default value to `''`. |\n| unit | `string`|`null` | The unit in which the result will be returned (B/KB/MB/GB/TB). Default value to `''` (which means auto detect). |\n| unitSeparator | `string`|`null` | Separator to use between number and unit. Default value to `''`. |\n\n**Returns**\n\n| Name    | Type             | Description                                     |\n|---------|------------------|-------------------------------------------------|\n| results | `string`|`null` | Return null upon error. String value otherwise. |\n\n**Example**\n\n```js\nbytes(1024);\n// output: '1KB'\n\nbytes(1000);\n// output: '1000B'\n\nbytes(1000, {thousandsSeparator: ' '});\n// output: '1 000B'\n\nbytes(1024 * 1.7, {decimalPlaces: 0});\n// output: '2KB'\n\nbytes(1024, {unitSeparator: ' '});\n// output: '1 KB'\n\n```\n\n#### bytes.parse(string|number value): number|null\n\nParse the string value into an integer in bytes. If no unit is given, or `value`\nis a number, it is assumed the value is in bytes.\n\nSupported units and abbreviations are as follows and are case-insensitive:\n\n  * `b` for bytes\n  * `kb` for kilobytes\n  * `mb` for megabytes\n  * `gb` for gigabytes\n  * `tb` for terabytes\n\nThe units are in powers of two, not ten. This means 1kb = 1024b according to this parser.\n\n**Arguments**\n\n| Name          | Type   | Description        |\n|---------------|--------|--------------------|\n| value   | `string`|`number` | String to parse, or number in bytes.   |\n\n**Returns**\n\n| Name    | Type        | Description             |\n|---------|-------------|-------------------------|\n| results | `number`|`null` | Return null upon error. Value in bytes otherwise. |\n\n**Example**\n\n```js\nbytes('1KB');\n// output: 1024\n\nbytes('1024');\n// output: 1024\n\nbytes(1024);\n// output: 1024\n```\n\n## License \n\n[MIT](LICENSE)\n\n[downloads-image]: https://img.shields.io/npm/dm/bytes.svg\n[downloads-url]: https://npmjs.org/package/bytes\n[npm-image]: https://img.shields.io/npm/v/bytes.svg\n[npm-url]: https://npmjs.org/package/bytes\n[travis-image]: https://img.shields.io/travis/visionmedia/bytes.js/master.svg\n[travis-url]: https://travis-ci.org/visionmedia/bytes.js\n[coveralls-image]: https://img.shields.io/coveralls/visionmedia/bytes.js/master.svg\n[coveralls-url]: https://coveralls.io/r/visionmedia/bytes.js?branch=master\n",
   "readmeFilename": "Readme.md",
   "repository": {
     "type": "git",
@@ -123,5 +120,5 @@
     "test-ci": "nyc --reporter=text npm test",
     "test-cov": "nyc --reporter=html --reporter=text npm test"
   },
-  "version": "2.5.0"
+  "version": "3.0.0"
 }
diff --git a/node_modules/compressible/package.json b/node_modules/compressible/package.json
index ccaee38..7a51c62 100644
--- a/node_modules/compressible/package.json
+++ b/node_modules/compressible/package.json
@@ -2,18 +2,18 @@
   "_args": [
     [
       {
-        "raw": "compressible@~2.0.10",
+        "raw": "compressible@~2.0.11",
         "scope": null,
         "escapedName": "compressible",
         "name": "compressible",
-        "rawSpec": "~2.0.10",
-        "spec": ">=2.0.10 <2.1.0",
+        "rawSpec": "~2.0.11",
+        "spec": ">=2.0.11 <2.1.0",
         "type": "range"
       },
       "/Users/steveng/repo/cordova/cordova-browser/node_modules/compression"
     ]
   ],
-  "_from": "compressible@>=2.0.10 <2.1.0",
+  "_from": "compressible@>=2.0.11 <2.1.0",
   "_id": "compressible@2.0.11",
   "_inCache": true,
   "_location": "/compressible",
@@ -29,12 +29,12 @@
   "_npmVersion": "3.10.10",
   "_phantomChildren": {},
   "_requested": {
-    "raw": "compressible@~2.0.10",
+    "raw": "compressible@~2.0.11",
     "scope": null,
     "escapedName": "compressible",
     "name": "compressible",
-    "rawSpec": "~2.0.10",
-    "spec": ">=2.0.10 <2.1.0",
+    "rawSpec": "~2.0.11",
+    "spec": ">=2.0.11 <2.1.0",
     "type": "range"
   },
   "_requiredBy": [
@@ -43,7 +43,7 @@
   "_resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.11.tgz",
   "_shasum": "16718a75de283ed8e604041625a2064586797d8a",
   "_shrinkwrap": null,
-  "_spec": "compressible@~2.0.10",
+  "_spec": "compressible@~2.0.11",
   "_where": "/Users/steveng/repo/cordova/cordova-browser/node_modules/compression",
   "bugs": {
     "url": "https://github.com/jshttp/compressible/issues"
diff --git a/node_modules/compression/HISTORY.md b/node_modules/compression/HISTORY.md
index b85b2ff..3cb6fbb 100644
--- a/node_modules/compression/HISTORY.md
+++ b/node_modules/compression/HISTORY.md
@@ -1,3 +1,15 @@
+1.7.1 / 2017-09-26
+==================
+
+  * deps: accepts@~1.3.4
+    - deps: mime-types@~2.1.16
+  * deps: bytes@3.0.0
+  * deps: compressible@~2.0.11
+    - deps: mime-db@'>= 1.29.0 < 2'
+  * deps: debug@2.6.9
+  * deps: vary@~1.1.2
+    - perf: improve header token parsing speed
+
 1.7.0 / 2017-07-10
 ==================
 
diff --git a/node_modules/compression/package.json b/node_modules/compression/package.json
index 6eb8c0c..e393af6 100644
--- a/node_modules/compression/package.json
+++ b/node_modules/compression/package.json
@@ -14,13 +14,13 @@
     ]
   ],
   "_from": "compression@>=1.6.0 <2.0.0",
-  "_id": "compression@1.7.0",
+  "_id": "compression@1.7.1",
   "_inCache": true,
   "_location": "/compression",
-  "_nodeVersion": "6.10.3",
+  "_nodeVersion": "6.11.1",
   "_npmOperationalInternal": {
     "host": "s3://npm-registry-packages",
-    "tmp": "tmp/compression-1.7.0.tgz_1499753654730_0.6516832136549056"
+    "tmp": "tmp/compression-1.7.1.tgz_1506489019778_0.34800254576839507"
   },
   "_npmUser": {
     "name": "dougwilson",
@@ -40,8 +40,8 @@
   "_requiredBy": [
     "/cordova-serve"
   ],
-  "_resolved": "https://registry.npmjs.org/compression/-/compression-1.7.0.tgz",
-  "_shasum": "030c9f198f1643a057d776a738e922da4373012d",
+  "_resolved": "https://registry.npmjs.org/compression/-/compression-1.7.1.tgz",
+  "_shasum": "eff2603efc2e22cf86f35d2eb93589f9875373db",
   "_shrinkwrap": null,
   "_spec": "compression@^1.6.0",
   "_where": "/Users/steveng/repo/cordova/cordova-browser/node_modules/cordova-serve",
@@ -60,13 +60,13 @@
     }
   ],
   "dependencies": {
-    "accepts": "~1.3.3",
-    "bytes": "2.5.0",
-    "compressible": "~2.0.10",
-    "debug": "2.6.8",
+    "accepts": "~1.3.4",
+    "bytes": "3.0.0",
+    "compressible": "~2.0.11",
+    "debug": "2.6.9",
     "on-headers": "~1.0.1",
     "safe-buffer": "5.1.1",
-    "vary": "~1.1.1"
+    "vary": "~1.1.2"
   },
   "description": "Node.js compression middleware",
   "devDependencies": {
@@ -74,17 +74,17 @@
     "eslint-config-standard": "10.2.1",
     "eslint-plugin-import": "2.7.0",
     "eslint-plugin-markdown": "1.0.0-beta.6",
-    "eslint-plugin-node": "5.1.0",
+    "eslint-plugin-node": "5.1.1",
     "eslint-plugin-promise": "3.5.0",
     "eslint-plugin-standard": "3.0.1",
     "istanbul": "0.4.5",
-    "mocha": "2.4.5",
+    "mocha": "2.5.3",
     "supertest": "1.1.0"
   },
   "directories": {},
   "dist": {
-    "shasum": "030c9f198f1643a057d776a738e922da4373012d",
-    "tarball": "https://registry.npmjs.org/compression/-/compression-1.7.0.tgz"
+    "shasum": "eff2603efc2e22cf86f35d2eb93589f9875373db",
+    "tarball": "https://registry.npmjs.org/compression/-/compression-1.7.1.tgz"
   },
   "engines": {
     "node": ">= 0.8.0"
@@ -94,7 +94,7 @@
     "HISTORY.md",
     "index.js"
   ],
-  "gitHead": "8c3f7eabba0be7dfb7fec86297cb28458efc3c58",
+  "gitHead": "93586e75a0a1c5bbfd353c4cec1cfcee2e52adde",
   "homepage": "https://github.com/expressjs/compression#readme",
   "license": "MIT",
   "maintainers": [
@@ -117,5 +117,5 @@
     "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --check-leaks --reporter dot",
     "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --check-leaks --reporter spec"
   },
-  "version": "1.7.0"
+  "version": "1.7.1"
 }
diff --git a/node_modules/content-type/HISTORY.md b/node_modules/content-type/HISTORY.md
index 01652ff..8f5cb70 100644
--- a/node_modules/content-type/HISTORY.md
+++ b/node_modules/content-type/HISTORY.md
@@ -1,3 +1,13 @@
+1.0.4 / 2017-09-11
+==================
+
+  * perf: skip parameter parsing when no parameters
+
+1.0.3 / 2017-09-10
+==================
+
+  * perf: remove argument reassignment
+
 1.0.2 / 2016-05-09
 ==================
 
diff --git a/node_modules/content-type/index.js b/node_modules/content-type/index.js
index 61ba6b5..6ce03f2 100644
--- a/node_modules/content-type/index.js
+++ b/node_modules/content-type/index.js
@@ -20,9 +20,9 @@
  * obs-text      = %x80-FF
  * quoted-pair   = "\" ( HTAB / SP / VCHAR / obs-text )
  */
-var paramRegExp = /; *([!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+) *= *("(?:[\u000b\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u000b\u0020-\u00ff])*"|[!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+) */g
-var textRegExp = /^[\u000b\u0020-\u007e\u0080-\u00ff]+$/
-var tokenRegExp = /^[!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+$/
+var PARAM_REGEXP = /; *([!#$%&'*+.^_`|~0-9A-Za-z-]+) *= *("(?:[\u000b\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u000b\u0020-\u00ff])*"|[!#$%&'*+.^_`|~0-9A-Za-z-]+) */g
+var TEXT_REGEXP = /^[\u000b\u0020-\u007e\u0080-\u00ff]+$/
+var TOKEN_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/
 
 /**
  * RegExp to match quoted-pair in RFC 7230 sec 3.2.6
@@ -30,21 +30,21 @@
  * quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
  * obs-text    = %x80-FF
  */
-var qescRegExp = /\\([\u000b\u0020-\u00ff])/g
+var QESC_REGEXP = /\\([\u000b\u0020-\u00ff])/g
 
 /**
  * RegExp to match chars that must be quoted-pair in RFC 7230 sec 3.2.6
  */
-var quoteRegExp = /([\\"])/g
+var QUOTE_REGEXP = /([\\"])/g
 
 /**
- * RegExp to match type in RFC 6838
+ * RegExp to match type in RFC 7231 sec 3.1.1.1
  *
  * media-type = type "/" subtype
  * type       = token
  * subtype    = token
  */
-var typeRegExp = /^[!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+\/[!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+$/
+var TYPE_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\/[!#$%&'*+.^_`|~0-9A-Za-z-]+$/
 
 /**
  * Module exports.
@@ -62,7 +62,7 @@
  * @public
  */
 
-function format(obj) {
+function format (obj) {
   if (!obj || typeof obj !== 'object') {
     throw new TypeError('argument obj is required')
   }
@@ -70,7 +70,7 @@
   var parameters = obj.parameters
   var type = obj.type
 
-  if (!type || !typeRegExp.test(type)) {
+  if (!type || !TYPE_REGEXP.test(type)) {
     throw new TypeError('invalid type')
   }
 
@@ -84,7 +84,7 @@
     for (var i = 0; i < params.length; i++) {
       param = params[i]
 
-      if (!tokenRegExp.test(param)) {
+      if (!TOKEN_REGEXP.test(param)) {
         throw new TypeError('invalid parameter name')
       }
 
@@ -103,61 +103,61 @@
  * @public
  */
 
-function parse(string) {
+function parse (string) {
   if (!string) {
     throw new TypeError('argument string is required')
   }
 
-  if (typeof string === 'object') {
-    // support req/res-like objects as argument
-    string = getcontenttype(string)
+  // support req/res-like objects as argument
+  var header = typeof string === 'object'
+    ? getcontenttype(string)
+    : string
 
-    if (typeof string !== 'string') {
-      throw new TypeError('content-type header is missing from object');
-    }
-  }
-
-  if (typeof string !== 'string') {
+  if (typeof header !== 'string') {
     throw new TypeError('argument string is required to be a string')
   }
 
-  var index = string.indexOf(';')
+  var index = header.indexOf(';')
   var type = index !== -1
-    ? string.substr(0, index).trim()
-    : string.trim()
+    ? header.substr(0, index).trim()
+    : header.trim()
 
-  if (!typeRegExp.test(type)) {
+  if (!TYPE_REGEXP.test(type)) {
     throw new TypeError('invalid media type')
   }
 
-  var key
-  var match
   var obj = new ContentType(type.toLowerCase())
-  var value
 
-  paramRegExp.lastIndex = index
+  // parse parameters
+  if (index !== -1) {
+    var key
+    var match
+    var value
 
-  while (match = paramRegExp.exec(string)) {
-    if (match.index !== index) {
+    PARAM_REGEXP.lastIndex = index
+
+    while ((match = PARAM_REGEXP.exec(header))) {
+      if (match.index !== index) {
+        throw new TypeError('invalid parameter format')
+      }
+
+      index += match[0].length
+      key = match[1].toLowerCase()
+      value = match[2]
+
+      if (value[0] === '"') {
+        // remove quotes and escapes
+        value = value
+          .substr(1, value.length - 2)
+          .replace(QESC_REGEXP, '$1')
+      }
+
+      obj.parameters[key] = value
+    }
+
+    if (index !== header.length) {
       throw new TypeError('invalid parameter format')
     }
-
-    index += match[0].length
-    key = match[1].toLowerCase()
-    value = match[2]
-
-    if (value[0] === '"') {
-      // remove quotes and escapes
-      value = value
-        .substr(1, value.length - 2)
-        .replace(qescRegExp, '$1')
-    }
-
-    obj.parameters[key] = value
-  }
-
-  if (index !== -1 && index !== string.length) {
-    throw new TypeError('invalid parameter format')
   }
 
   return obj
@@ -171,16 +171,22 @@
  * @private
  */
 
-function getcontenttype(obj) {
+function getcontenttype (obj) {
+  var header
+
   if (typeof obj.getHeader === 'function') {
     // res-like
-    return obj.getHeader('content-type')
+    header = obj.getHeader('content-type')
+  } else if (typeof obj.headers === 'object') {
+    // req-like
+    header = obj.headers && obj.headers['content-type']
   }
 
-  if (typeof obj.headers === 'object') {
-    // req-like
-    return obj.headers && obj.headers['content-type']
+  if (typeof header !== 'string') {
+    throw new TypeError('content-type header is missing from object')
   }
+
+  return header
 }
 
 /**
@@ -191,26 +197,26 @@
  * @private
  */
 
-function qstring(val) {
+function qstring (val) {
   var str = String(val)
 
   // no need to quote tokens
-  if (tokenRegExp.test(str)) {
+  if (TOKEN_REGEXP.test(str)) {
     return str
   }
 
-  if (str.length > 0 && !textRegExp.test(str)) {
+  if (str.length > 0 && !TEXT_REGEXP.test(str)) {
     throw new TypeError('invalid parameter value')
   }
 
-  return '"' + str.replace(quoteRegExp, '\\$1') + '"'
+  return '"' + str.replace(QUOTE_REGEXP, '\\$1') + '"'
 }
 
 /**
  * Class to represent a content type.
  * @private
  */
-function ContentType(type) {
+function ContentType (type) {
   this.parameters = Object.create(null)
   this.type = type
 }
diff --git a/node_modules/content-type/package.json b/node_modules/content-type/package.json
index 7285aae..91deedf 100644
--- a/node_modules/content-type/package.json
+++ b/node_modules/content-type/package.json
@@ -2,48 +2,49 @@
   "_args": [
     [
       {
-        "raw": "content-type@~1.0.2",
+        "raw": "content-type@~1.0.4",
         "scope": null,
         "escapedName": "content-type",
         "name": "content-type",
-        "rawSpec": "~1.0.2",
-        "spec": ">=1.0.2 <1.1.0",
+        "rawSpec": "~1.0.4",
+        "spec": ">=1.0.4 <1.1.0",
         "type": "range"
       },
       "/Users/steveng/repo/cordova/cordova-browser/node_modules/express"
     ]
   ],
-  "_from": "content-type@>=1.0.2 <1.1.0",
-  "_id": "content-type@1.0.2",
+  "_from": "content-type@>=1.0.4 <1.1.0",
+  "_id": "content-type@1.0.4",
   "_inCache": true,
   "_location": "/content-type",
-  "_nodeVersion": "4.4.3",
+  "_nodeVersion": "6.11.3",
   "_npmOperationalInternal": {
-    "host": "packages-12-west.internal.npmjs.com",
-    "tmp": "tmp/content-type-1.0.2.tgz_1462852785748_0.5491233412176371"
+    "host": "s3://npm-registry-packages",
+    "tmp": "tmp/content-type-1.0.4.tgz_1505166155546_0.06956395204178989"
   },
   "_npmUser": {
     "name": "dougwilson",
     "email": "doug@somethingdoug.com"
   },
-  "_npmVersion": "2.15.1",
+  "_npmVersion": "5.3.0",
   "_phantomChildren": {},
   "_requested": {
-    "raw": "content-type@~1.0.2",
+    "raw": "content-type@~1.0.4",
     "scope": null,
     "escapedName": "content-type",
     "name": "content-type",
-    "rawSpec": "~1.0.2",
-    "spec": ">=1.0.2 <1.1.0",
+    "rawSpec": "~1.0.4",
+    "spec": ">=1.0.4 <1.1.0",
     "type": "range"
   },
   "_requiredBy": [
+    "/body-parser",
     "/express"
   ],
-  "_resolved": "http://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz",
-  "_shasum": "b7d113aee7a8dd27bd21133c4dc2529df1721eed",
+  "_resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+  "_shasum": "e138cc75e040c727b1966fe5e5f8c9aee256fe3b",
   "_shrinkwrap": null,
-  "_spec": "content-type@~1.0.2",
+  "_spec": "content-type@~1.0.4",
   "_where": "/Users/steveng/repo/cordova/cordova-browser/node_modules/express",
   "author": {
     "name": "Douglas Christopher Wilson",
@@ -55,13 +56,20 @@
   "dependencies": {},
   "description": "Create and parse HTTP Content-Type header",
   "devDependencies": {
-    "istanbul": "0.4.3",
+    "eslint": "3.19.0",
+    "eslint-config-standard": "10.2.1",
+    "eslint-plugin-import": "2.7.0",
+    "eslint-plugin-node": "5.1.1",
+    "eslint-plugin-promise": "3.5.0",
+    "eslint-plugin-standard": "3.0.1",
+    "istanbul": "0.4.5",
     "mocha": "~1.21.5"
   },
   "directories": {},
   "dist": {
-    "shasum": "b7d113aee7a8dd27bd21133c4dc2529df1721eed",
-    "tarball": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz"
+    "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
+    "shasum": "e138cc75e040c727b1966fe5e5f8c9aee256fe3b",
+    "tarball": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz"
   },
   "engines": {
     "node": ">= 0.6"
@@ -72,7 +80,7 @@
     "README.md",
     "index.js"
   ],
-  "gitHead": "8118763adfbbac80cf1254191889330aec8b8be7",
+  "gitHead": "d22f8ac6c407789c906bd6fed137efde8f772b09",
   "homepage": "https://github.com/jshttp/content-type#readme",
   "keywords": [
     "content-type",
@@ -97,9 +105,10 @@
     "url": "git+https://github.com/jshttp/content-type.git"
   },
   "scripts": {
+    "lint": "eslint .",
     "test": "mocha --reporter spec --check-leaks --bail test/",
     "test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/",
     "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/"
   },
-  "version": "1.0.2"
+  "version": "1.0.4"
 }
diff --git a/node_modules/cordova-common/.jshintignore b/node_modules/cordova-common/.eslintignore
similarity index 93%
rename from node_modules/cordova-common/.jshintignore
rename to node_modules/cordova-common/.eslintignore
index d606f61..161d0c6 100644
--- a/node_modules/cordova-common/.jshintignore
+++ b/node_modules/cordova-common/.eslintignore
@@ -1 +1 @@
-spec/fixtures/*
+spec/fixtures/*
\ No newline at end of file
diff --git a/node_modules/cordova-common/.eslintrc.yml b/node_modules/cordova-common/.eslintrc.yml
new file mode 100644
index 0000000..7701c82
--- /dev/null
+++ b/node_modules/cordova-common/.eslintrc.yml
@@ -0,0 +1,11 @@
+root: true
+extends: semistandard
+rules:
+  indent:
+    - error
+    - 4
+  camelcase: off
+  padded-blocks: off
+  operator-linebreak: off
+  no-throw-literal: off
+  
\ No newline at end of file
diff --git a/node_modules/cordova-common/.ratignore b/node_modules/cordova-common/.ratignore
index d9f5e52..f107416 100644
--- a/node_modules/cordova-common/.ratignore
+++ b/node_modules/cordova-common/.ratignore
@@ -1,3 +1,4 @@
 fixtures
 coverage
 jasmine.json
+appveyor.yml
diff --git a/node_modules/cordova-common/.travis.yml b/node_modules/cordova-common/.travis.yml
new file mode 100644
index 0000000..459273a
--- /dev/null
+++ b/node_modules/cordova-common/.travis.yml
@@ -0,0 +1,15 @@
+language: node_js
+sudo: false
+git:
+  depth: 10
+node_js:
+  - "4"
+  - "6"
+install:
+  - npm install
+  - npm install -g codecov
+script:
+  - npm test
+  - npm run cover
+after_script:
+  - codecov
diff --git a/node_modules/cordova-common/README.md b/node_modules/cordova-common/README.md
index c5dcfd5..5659c57 100644
--- a/node_modules/cordova-common/README.md
+++ b/node_modules/cordova-common/README.md
@@ -19,6 +19,10 @@
 #
 -->
 
+[![Build status](https://ci.appveyor.com/api/projects/status/wxkmo0jalsr8gane?svg=true)](https://ci.appveyor.com/project/ApacheSoftwareFoundation/cordova-common/branch/master)
+[![Build Status](https://travis-ci.org/apache/cordova-common.svg?branch=master)](https://travis-ci.org/apache/cordova-common)
+[![NPM](https://nodei.co/npm/cordova-common.png)](https://nodei.co/npm/cordova-common/)
+
 # cordova-common
 Expoeses shared functionality used by [cordova-lib](https://github.com/apache/cordova-lib/) and Cordova platforms.
 ## Exposed APIs
diff --git a/node_modules/cordova-common/RELEASENOTES.md b/node_modules/cordova-common/RELEASENOTES.md
index fa7f1d2..89593ea 100644
--- a/node_modules/cordova-common/RELEASENOTES.md
+++ b/node_modules/cordova-common/RELEASENOTES.md
@@ -20,6 +20,20 @@
 -->
 # Cordova-common Release Notes
 
+### 2.1.1 (Oct 04, 2017)
+* [CB-13145](https://issues.apache.org/jira/browse/CB-13145) added `getFrameworks` to unit tests
+* [CB-13145](https://issues.apache.org/jira/browse/CB-13145) added variable replacing to framework tag
+
+### 2.1.0 (August 30, 2017)
+* [CB-13145](https://issues.apache.org/jira/browse/CB-13145) added variable replacing to `framework` tag
+* [CB-13211](https://issues.apache.org/jira/browse/CB-13211) Add `allows-arbitrary-loads-for-media` attribute parsing for `getAccesses`
+* [CB-11968](https://issues.apache.org/jira/browse/CB-11968) Added support for `<config-file>` in `config.xml`
+* [CB-12895](https://issues.apache.org/jira/browse/CB-12895) set up `eslint` and removed `jshint`
+* [CB-12785](https://issues.apache.org/jira/browse/CB-12785) added `.gitignore`, `travis`, and `appveyor` support
+* [CB-12250](https://issues.apache.org/jira/browse/CB-12250) & [CB-12409](https://issues.apache.org/jira/browse/CB-12409) *iOS*: Fix bug with escaping properties from `plist` file
+* [CB-12762](https://issues.apache.org/jira/browse/CB-12762) updated `common`, `fetch`, and `serve` `pkgJson` to point `pkgJson` repo items to github mirrors
+* [CB-12766](https://issues.apache.org/jira/browse/CB-12766) Consistently write `JSON` with 2 spaces indentation
+
 ### 2.0.3 (May 02, 2017)
 * [CB-8978](https://issues.apache.org/jira/browse/CB-8978) Add option to get `resource-file` from `root`
 * [CB-11908](https://issues.apache.org/jira/browse/CB-11908) Add tests for `edit-config` in `config.xml`
diff --git a/node_modules/cordova-common/appveyor.yml b/node_modules/cordova-common/appveyor.yml
new file mode 100644
index 0000000..94714f2
--- /dev/null
+++ b/node_modules/cordova-common/appveyor.yml
@@ -0,0 +1,18 @@
+# appveyor file
+# http://www.appveyor.com/docs/appveyor-yml
+
+environment:
+  matrix:
+  - nodejs_version: "4"
+  - nodejs_version: "6"
+  
+install:
+  - ps: Install-Product node $env:nodejs_version
+  - npm install
+
+build: off
+
+test_script:
+  - node --version
+  - npm --version
+  - npm test
diff --git a/node_modules/cordova-common/package.json b/node_modules/cordova-common/package.json
index 24df63b..987d0f5 100644
--- a/node_modules/cordova-common/package.json
+++ b/node_modules/cordova-common/package.json
@@ -2,48 +2,48 @@
   "_args": [
     [
       {
-        "raw": "cordova-common@^2.0.1",
+        "raw": "cordova-common@^2.1.1",
         "scope": null,
         "escapedName": "cordova-common",
         "name": "cordova-common",
-        "rawSpec": "^2.0.1",
-        "spec": ">=2.0.1 <3.0.0",
+        "rawSpec": "^2.1.1",
+        "spec": ">=2.1.1 <3.0.0",
         "type": "range"
       },
       "/Users/steveng/repo/cordova/cordova-browser"
     ]
   ],
-  "_from": "cordova-common@>=2.0.1 <3.0.0",
-  "_id": "cordova-common@2.0.3",
+  "_from": "cordova-common@>=2.1.1 <3.0.0",
+  "_id": "cordova-common@2.1.1",
   "_inCache": true,
   "_location": "/cordova-common",
   "_nodeVersion": "6.6.0",
   "_npmOperationalInternal": {
-    "host": "packages-18-east.internal.npmjs.com",
-    "tmp": "tmp/cordova-common-2.0.3.tgz_1493907568090_0.012110879644751549"
+    "host": "s3://npm-registry-packages",
+    "tmp": "tmp/cordova-common-2.1.1.tgz_1507594418999_0.47268117731437087"
   },
   "_npmUser": {
     "name": "stevegill",
     "email": "stevengill97@gmail.com"
   },
-  "_npmVersion": "4.1.1",
+  "_npmVersion": "4.6.1",
   "_phantomChildren": {},
   "_requested": {
-    "raw": "cordova-common@^2.0.1",
+    "raw": "cordova-common@^2.1.1",
     "scope": null,
     "escapedName": "cordova-common",
     "name": "cordova-common",
-    "rawSpec": "^2.0.1",
-    "spec": ">=2.0.1 <3.0.0",
+    "rawSpec": "^2.1.1",
+    "spec": ">=2.1.1 <3.0.0",
     "type": "range"
   },
   "_requiredBy": [
     "/"
   ],
-  "_resolved": "file:cordova-dist/tools/cordova-common-2.0.3.tgz",
-  "_shasum": "2214ee04ae1c2ec012a52c7c185313e341a6fb38",
+  "_resolved": "file:cordova-dist/tools/cordova-common-2.1.1.tgz",
+  "_shasum": "e3a16a4f3d29a8e2b523128ac65478aca9ea1749",
   "_shrinkwrap": null,
-  "_spec": "cordova-common@^2.0.1",
+  "_spec": "cordova-common@^2.1.1",
   "_where": "/Users/steveng/repo/cordova/cordova-browser",
   "author": {
     "name": "Apache Software Foundation"
@@ -70,65 +70,80 @@
   },
   "description": "Apache Cordova tools and platforms shared routines",
   "devDependencies": {
+    "eslint": "^4.0.0",
+    "eslint-config-semistandard": "^11.0.0",
+    "eslint-config-standard": "^10.2.1",
+    "eslint-plugin-import": "^2.3.0",
+    "eslint-plugin-node": "^5.0.0",
+    "eslint-plugin-promise": "^3.5.0",
+    "eslint-plugin-standard": "^3.0.1",
     "istanbul": "^0.4.5",
     "jasmine": "^2.5.2",
-    "jshint": "^2.8.0",
     "promise-matchers": "^0.9.6",
     "rewire": "^2.5.1"
   },
   "directories": {},
   "dist": {
-    "shasum": "2214ee04ae1c2ec012a52c7c185313e341a6fb38",
-    "tarball": "https://registry.npmjs.org/cordova-common/-/cordova-common-2.0.3.tgz"
+    "shasum": "e3a16a4f3d29a8e2b523128ac65478aca9ea1749",
+    "tarball": "https://registry.npmjs.org/cordova-common/-/cordova-common-2.1.1.tgz"
   },
   "engines": {
     "node": ">=4.0.0"
   },
+  "homepage": "https://github.com/apache/cordova-lib#readme",
   "license": "Apache-2.0",
   "main": "cordova-common.js",
   "maintainers": [
     {
-      "name": "bowserj",
-      "email": "bowserj@apache.org"
+      "name": "audreyso",
+      "email": "audreyeso@gmail.com"
+    },
+    {
+      "name": "apachebuilds",
+      "email": "root@apache.org"
     },
     {
       "name": "filmaj",
       "email": "maj.fil@gmail.com"
     },
     {
-      "name": "kotikov.vladimir",
-      "email": "kotikov.vladimir@gmail.com"
-    },
-    {
-      "name": "purplecabbage",
-      "email": "purplecabbage@gmail.com"
+      "name": "timbarham",
+      "email": "npmjs@barhams.info"
     },
     {
       "name": "shazron",
       "email": "shazron@gmail.com"
     },
     {
+      "name": "bowserj",
+      "email": "bowserj@apache.org"
+    },
+    {
+      "name": "purplecabbage",
+      "email": "purplecabbage@gmail.com"
+    },
+    {
       "name": "stevegill",
       "email": "stevengill97@gmail.com"
     },
     {
-      "name": "timbarham",
-      "email": "npmjs@barhams.info"
+      "name": "kotikov.vladimir",
+      "email": "kotikov.vladimir@gmail.com"
     }
   ],
   "name": "cordova-common",
   "optionalDependencies": {},
-  "readme": "<!--\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#  KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n#\n-->\n\n# cordova-common\nExpoeses shared functionality used by [cordova-lib](https://github.com/apache/cordova-lib/) and Cordova platforms.\n## Exposed APIs\n\n### `events`\n  \nRepresents special instance of NodeJS EventEmitter which is intended to be used to post events to cordova-lib and cordova-cli\n\nUsage:\n```js\nvar events = require('cordova-common').events;\nevents.emit('warn', 'Some warning message')\n```\n\nThere are the following events supported by cordova-cli: `verbose`, `log`, `info`, `warn`, `error`.\n\n### `CordovaError`\n\nAn error class used by Cordova to throw cordova-specific errors. The CordovaError class is inherited from Error, so CordovaError instances is also valid Error instances (`instanceof` check succeeds).\n\nUsage:\n\n```js\nvar CordovaError = require('cordova-common').CordovaError;\nthrow new CordovaError('Some error message', SOME_ERR_CODE);\n```\n\nSee [CordovaError](src/CordovaError/CordovaError.js) for supported error codes.\n\n### `ConfigParser`\n\nExposes functionality to deal with cordova project `config.xml` files. For ConfigParser API reference check [ConfigParser Readme](src/ConfigParser/README.md).\n\nUsage:\n```js\nvar ConfigParser = require('cordova-common').ConfigParser;\nvar appConfig = new ConfigParser('path/to/cordova-app/config.xml');\nconsole.log(appconfig.name() + ':' + appConfig.version());\n```\n\n### `PluginInfoProvider` and `PluginInfo`\n\n`PluginInfo` is a wrapper for cordova plugins' `plugin.xml` files. This class may be instantiated directly or via `PluginInfoProvider`. The difference is that `PluginInfoProvider` caches `PluginInfo` instances based on plugin source directory.\n\nUsage:\n```js\nvar PluginInfo: require('cordova-common').PluginInfo;\nvar PluginInfoProvider: require('cordova-common').PluginInfoProvider;\n\n// The following instances are equal\nvar plugin1 = new PluginInfo('path/to/plugin_directory');\nvar plugin2 = new PluginInfoProvider().get('path/to/plugin_directory');\n\nconsole.log('The plugin ' + plugin1.id + ' has version ' + plugin1.version)\n```\n\n### `ActionStack`\n\nUtility module for dealing with sequential tasks. Provides a set of tasks that are needed to be done and reverts all tasks that are already completed if one of those tasks fail to complete. Used internally by cordova-lib and platform's plugin installation routines.\n\nUsage:\n```js\nvar ActionStack = require('cordova-common').ActionStack;\nvar stack = new ActionStack()\n\nvar action1 = stack.createAction(task1, [<task parameters>], task1_reverter, [<reverter_parameters>]);\nvar action2 = stack.createAction(task2, [<task parameters>], task2_reverter, [<reverter_parameters>]);\n\nstack.push(action1);\nstack.push(action2);\n\nstack.process()\n.then(function() {\n    // all actions succeded\n})\n.catch(function(error){\n    // One of actions failed with error\n})\n```\n\n### `superspawn`\n\nModule for spawning child processes with some advanced logic.\n\nUsage:\n```js\nvar superspawn = require('cordova-common').superspawn;\nsuperspawn.spawn('adb', ['devices'])\n.progress(function(data){\n    if (data.stderr)\n        console.error('\"adb devices\" raised an error: ' + data.stderr);\n})\n.then(function(devices){\n    // Do something...\n})\n```\n\n### `xmlHelpers`\n\nA set of utility methods for dealing with xml files.\n\nUsage:\n```js\nvar xml = require('cordova-common').xmlHelpers;\n\nvar xmlDoc1 = xml.parseElementtreeSync('some/xml/file');\nvar xmlDoc2 = xml.parseElementtreeSync('another/xml/file');\n\nxml.mergeXml(doc1, doc2); // doc2 now contains all the nodes from doc1\n```\n\n### Other APIs\n\nThe APIs listed below are also exposed but are intended to be only used internally by cordova plugin installation routines.\n\n```\nPlatformJson\nConfigChanges\nConfigKeeper\nConfigFile\nmungeUtil\n```\n\n## Setup\n* Clone this repository onto your local machine\n    `git clone https://git-wip-us.apache.org/repos/asf/cordova-lib.git`\n* In terminal, navigate to the inner cordova-common directory\n    `cd cordova-lib/cordova-common`\n* Install dependencies and npm-link\n    `npm install && npm link`\n* Navigate to cordova-lib directory and link cordova-common\n    `cd ../cordova-lib && npm link cordova-common && npm install`\n",
+  "readme": "<!--\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#  KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n#\n-->\n\n[![Build status](https://ci.appveyor.com/api/projects/status/wxkmo0jalsr8gane?svg=true)](https://ci.appveyor.com/project/ApacheSoftwareFoundation/cordova-common/branch/master)\n[![Build Status](https://travis-ci.org/apache/cordova-common.svg?branch=master)](https://travis-ci.org/apache/cordova-common)\n[![NPM](https://nodei.co/npm/cordova-common.png)](https://nodei.co/npm/cordova-common/)\n\n# cordova-common\nExpoeses shared functionality used by [cordova-lib](https://github.com/apache/cordova-lib/) and Cordova platforms.\n## Exposed APIs\n\n### `events`\n  \nRepresents special instance of NodeJS EventEmitter which is intended to be used to post events to cordova-lib and cordova-cli\n\nUsage:\n```js\nvar events = require('cordova-common').events;\nevents.emit('warn', 'Some warning message')\n```\n\nThere are the following events supported by cordova-cli: `verbose`, `log`, `info`, `warn`, `error`.\n\n### `CordovaError`\n\nAn error class used by Cordova to throw cordova-specific errors. The CordovaError class is inherited from Error, so CordovaError instances is also valid Error instances (`instanceof` check succeeds).\n\nUsage:\n\n```js\nvar CordovaError = require('cordova-common').CordovaError;\nthrow new CordovaError('Some error message', SOME_ERR_CODE);\n```\n\nSee [CordovaError](src/CordovaError/CordovaError.js) for supported error codes.\n\n### `ConfigParser`\n\nExposes functionality to deal with cordova project `config.xml` files. For ConfigParser API reference check [ConfigParser Readme](src/ConfigParser/README.md).\n\nUsage:\n```js\nvar ConfigParser = require('cordova-common').ConfigParser;\nvar appConfig = new ConfigParser('path/to/cordova-app/config.xml');\nconsole.log(appconfig.name() + ':' + appConfig.version());\n```\n\n### `PluginInfoProvider` and `PluginInfo`\n\n`PluginInfo` is a wrapper for cordova plugins' `plugin.xml` files. This class may be instantiated directly or via `PluginInfoProvider`. The difference is that `PluginInfoProvider` caches `PluginInfo` instances based on plugin source directory.\n\nUsage:\n```js\nvar PluginInfo: require('cordova-common').PluginInfo;\nvar PluginInfoProvider: require('cordova-common').PluginInfoProvider;\n\n// The following instances are equal\nvar plugin1 = new PluginInfo('path/to/plugin_directory');\nvar plugin2 = new PluginInfoProvider().get('path/to/plugin_directory');\n\nconsole.log('The plugin ' + plugin1.id + ' has version ' + plugin1.version)\n```\n\n### `ActionStack`\n\nUtility module for dealing with sequential tasks. Provides a set of tasks that are needed to be done and reverts all tasks that are already completed if one of those tasks fail to complete. Used internally by cordova-lib and platform's plugin installation routines.\n\nUsage:\n```js\nvar ActionStack = require('cordova-common').ActionStack;\nvar stack = new ActionStack()\n\nvar action1 = stack.createAction(task1, [<task parameters>], task1_reverter, [<reverter_parameters>]);\nvar action2 = stack.createAction(task2, [<task parameters>], task2_reverter, [<reverter_parameters>]);\n\nstack.push(action1);\nstack.push(action2);\n\nstack.process()\n.then(function() {\n    // all actions succeded\n})\n.catch(function(error){\n    // One of actions failed with error\n})\n```\n\n### `superspawn`\n\nModule for spawning child processes with some advanced logic.\n\nUsage:\n```js\nvar superspawn = require('cordova-common').superspawn;\nsuperspawn.spawn('adb', ['devices'])\n.progress(function(data){\n    if (data.stderr)\n        console.error('\"adb devices\" raised an error: ' + data.stderr);\n})\n.then(function(devices){\n    // Do something...\n})\n```\n\n### `xmlHelpers`\n\nA set of utility methods for dealing with xml files.\n\nUsage:\n```js\nvar xml = require('cordova-common').xmlHelpers;\n\nvar xmlDoc1 = xml.parseElementtreeSync('some/xml/file');\nvar xmlDoc2 = xml.parseElementtreeSync('another/xml/file');\n\nxml.mergeXml(doc1, doc2); // doc2 now contains all the nodes from doc1\n```\n\n### Other APIs\n\nThe APIs listed below are also exposed but are intended to be only used internally by cordova plugin installation routines.\n\n```\nPlatformJson\nConfigChanges\nConfigKeeper\nConfigFile\nmungeUtil\n```\n\n## Setup\n* Clone this repository onto your local machine\n    `git clone https://git-wip-us.apache.org/repos/asf/cordova-lib.git`\n* In terminal, navigate to the inner cordova-common directory\n    `cd cordova-lib/cordova-common`\n* Install dependencies and npm-link\n    `npm install && npm link`\n* Navigate to cordova-lib directory and link cordova-common\n    `cd ../cordova-lib && npm link cordova-common && npm install`\n",
   "readmeFilename": "README.md",
   "repository": {
     "type": "git",
-    "url": "git://git-wip-us.apache.org/repos/asf/cordova-common.git"
+    "url": "git+https://github.com/apache/cordova-lib.git"
   },
   "scripts": {
     "cover": "istanbul cover --root src --print detail jasmine",
+    "eslint": "eslint src && eslint spec",
     "jasmine": "jasmine JASMINE_CONFIG_PATH=spec/support/jasmine.json",
-    "jshint": "jshint src && jshint spec",
-    "test": "npm run jshint && npm run jasmine"
+    "test": "npm run eslint && npm run jasmine"
   },
-  "version": "2.0.3"
+  "version": "2.1.1"
 }
diff --git a/node_modules/cordova-common/src/.jshintrc b/node_modules/cordova-common/src/.jshintrc
deleted file mode 100644
index 89a121c..0000000
--- a/node_modules/cordova-common/src/.jshintrc
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-    "node": true
-  , "bitwise": true
-  , "undef": true
-  , "trailing": true
-  , "quotmark": true
-  , "indent": 4
-  , "unused": "vars"
-  , "latedef": "nofunc"
-}
diff --git a/node_modules/cordova-common/src/ActionStack.js b/node_modules/cordova-common/src/ActionStack.js
index 5ef6f84..6983c5c 100644
--- a/node_modules/cordova-common/src/ActionStack.js
+++ b/node_modules/cordova-common/src/ActionStack.js
@@ -19,32 +19,32 @@
 
 /* jshint quotmark:false */
 
-var events = require('./events'),
-    Q = require('q');
+var events = require('./events');
+var Q = require('q');
 
-function ActionStack() {
+function ActionStack () {
     this.stack = [];
     this.completed = [];
 }
 
 ActionStack.prototype = {
-    createAction:function(handler, action_params, reverter, revert_params) {
+    createAction: function (handler, action_params, reverter, revert_params) {
         return {
-            handler:{
-                run:handler,
-                params:action_params
+            handler: {
+                run: handler,
+                params: action_params
             },
-            reverter:{
-                run:reverter,
-                params:revert_params
+            reverter: {
+                run: reverter,
+                params: revert_params
             }
         };
     },
-    push:function(tx) {
+    push: function (tx) {
         this.stack.push(tx);
     },
     // Returns a promise.
-    process:function(platform) {
+    process: function (platform) {
         events.emit('verbose', 'Beginning processing of action stack for ' + platform + ' project...');
 
         while (this.stack.length) {
@@ -54,19 +54,19 @@
 
             try {
                 handler.apply(null, action_params);
-            } catch(e) {
+            } catch (e) {
                 events.emit('warn', 'Error during processing of action! Attempting to revert...');
                 this.stack.unshift(action);
                 var issue = 'Uh oh!\n';
                 // revert completed tasks
-                while(this.completed.length) {
+                while (this.completed.length) {
                     var undo = this.completed.shift();
                     var revert = undo.reverter.run;
                     var revert_params = undo.reverter.params;
 
                     try {
                         revert.apply(null, revert_params);
-                    } catch(err) {
+                    } catch (err) {
                         events.emit('warn', 'Error during reversion of action! We probably really messed up your project now, sorry! D:');
                         issue += 'A reversion action failed: ' + err.message + '\n';
                     }
diff --git a/node_modules/cordova-common/src/ConfigChanges/ConfigChanges.js b/node_modules/cordova-common/src/ConfigChanges/ConfigChanges.js
index 4a58132..e0af8a9 100644
--- a/node_modules/cordova-common/src/ConfigChanges/ConfigChanges.js
+++ b/node_modules/cordova-common/src/ConfigChanges/ConfigChanges.js
@@ -15,7 +15,7 @@
     KIND, either express or implied.  See the License for the
     specific language governing permissions and limitations
     under the License.
-*/ 
+*/
 
 /*
  * This module deals with shared configuration / dependency "stuff". That is:
@@ -29,19 +29,17 @@
  * reference counts.
  */
 
-/* jshint sub:true */
-
-var path = require('path'),
-    et   = require('elementtree'),
-    ConfigKeeper = require('./ConfigKeeper'),
-    CordovaLogger = require('../CordovaLogger');
+var path = require('path');
+var et = require('elementtree');
+var ConfigKeeper = require('./ConfigKeeper');
+var CordovaLogger = require('../CordovaLogger');
 
 var mungeutil = require('./munge-util');
 var xml_helpers = require('../util/xml-helpers');
 
 exports.PlatformMunger = PlatformMunger;
 
-exports.process = function(plugins_dir, project_dir, platform, platformJson, pluginInfoProvider) {
+exports.process = function (plugins_dir, project_dir, platform, platformJson, pluginInfoProvider) {
     var munger = new PlatformMunger(platform, project_dir, platformJson, pluginInfoProvider);
     munger.process(plugins_dir);
     munger.save_all();
@@ -53,7 +51,7 @@
 * Can deal with config file of a single project.
 * Parsed config files are cached in a ConfigKeeper object.
 ******************************************************************************/
-function PlatformMunger(platform, project_dir, platformJson, pluginInfoProvider) {
+function PlatformMunger (platform, project_dir, platformJson, pluginInfoProvider) {
     this.platform = platform;
     this.project_dir = project_dir;
     this.config_keeper = new ConfigKeeper(project_dir);
@@ -63,7 +61,7 @@
 
 // Write out all unsaved files.
 PlatformMunger.prototype.save_all = PlatformMunger_save_all;
-function PlatformMunger_save_all() {
+function PlatformMunger_save_all () {
     this.config_keeper.save_all();
     this.platformJson.save();
 }
@@ -71,7 +69,7 @@
 // Apply a munge object to a single config file.
 // The remove parameter tells whether to add the change or remove it.
 PlatformMunger.prototype.apply_file_munge = PlatformMunger_apply_file_munge;
-function PlatformMunger_apply_file_munge(file, munge, remove) {
+function PlatformMunger_apply_file_munge (file, munge, remove) {
     var self = this;
 
     for (var selector in munge.parents) {
@@ -86,16 +84,15 @@
     }
 }
 
-
 PlatformMunger.prototype.remove_plugin_changes = remove_plugin_changes;
-function remove_plugin_changes(pluginInfo, is_top_level) {
+function remove_plugin_changes (pluginInfo, is_top_level) {
     var self = this;
     var platform_config = self.platformJson.root;
     var plugin_vars = is_top_level ?
         platform_config.installed_plugins[pluginInfo.id] :
         platform_config.dependent_plugins[pluginInfo.id];
     var edit_config_changes = null;
-    if(pluginInfo.getEditConfigs) {
+    if (pluginInfo.getEditConfigs) {
         edit_config_changes = pluginInfo.getEditConfigs(self.platform);
     }
 
@@ -114,14 +111,13 @@
     return self;
 }
 
-
 PlatformMunger.prototype.add_plugin_changes = add_plugin_changes;
-function add_plugin_changes(pluginInfo, plugin_vars, is_top_level, should_increment, plugin_force) {
+function add_plugin_changes (pluginInfo, plugin_vars, is_top_level, should_increment, plugin_force) {
     var self = this;
     var platform_config = self.platformJson.root;
 
     var edit_config_changes = null;
-    if(pluginInfo.getEditConfigs) {
+    if (pluginInfo.getEditConfigs) {
         edit_config_changes = pluginInfo.getEditConfigs(self.platform);
     }
 
@@ -130,8 +126,7 @@
     if (!edit_config_changes || edit_config_changes.length === 0) {
         // get config munge, aka how should this plugin change various config files
         config_munge = self.generate_plugin_config_munge(pluginInfo, plugin_vars);
-    }
-    else {
+    } else {
         var isConflictingInfo = is_conflicting(edit_config_changes, platform_config.config_munge, self, plugin_force);
 
         if (isConflictingInfo.conflictWithConfigxml) {
@@ -149,13 +144,11 @@
 
             // force add new munges
             config_munge = self.generate_plugin_config_munge(pluginInfo, plugin_vars, edit_config_changes);
-        }
-        else if(isConflictingInfo.conflictFound) {
+        } else if (isConflictingInfo.conflictFound) {
             throw new Error('There was a conflict trying to modify attributes with <edit-config> in plugin ' + pluginInfo.id +
             '. The conflicting plugin, ' + isConflictingInfo.conflictingPlugin + ', already modified the same attributes. The conflict must be resolved before ' +
             pluginInfo.id + ' can be added. You may use --force to add the plugin and overwrite the conflicting attributes.');
-        }
-        else {
+        } else {
             // no conflicts, will handle edit-config
             config_munge = self.generate_plugin_config_munge(pluginInfo, plugin_vars, edit_config_changes);
         }
@@ -168,27 +161,32 @@
     return self;
 }
 
-
 // Handle edit-config changes from config.xml
 PlatformMunger.prototype.add_config_changes = add_config_changes;
-function add_config_changes(config, should_increment) {
+function add_config_changes (config, should_increment) {
     var self = this;
     var platform_config = self.platformJson.root;
 
     var config_munge;
-    var edit_config_changes = null;
-    if(config.getEditConfigs) {
-        edit_config_changes = config.getEditConfigs(self.platform);
+    var changes = [];
+
+    if (config.getEditConfigs) {
+        var edit_config_changes = config.getEditConfigs(self.platform);
+        if (edit_config_changes) {
+            changes = changes.concat(edit_config_changes);
+        }
     }
 
-    if (!edit_config_changes || edit_config_changes.length === 0) {
-        // There are no edit-config changes to add, return here
-        return self;
+    if (config.getConfigFiles) {
+        var config_files_changes = config.getConfigFiles(self.platform);
+        if (config_files_changes) {
+            changes = changes.concat(config_files_changes);
+        }
     }
-    else {
-        var isConflictingInfo = is_conflicting(edit_config_changes, platform_config.config_munge, self, true /*always force overwrite other edit-config*/);
 
-        if(isConflictingInfo.conflictFound) {
+    if (changes && changes.length > 0) {
+        var isConflictingInfo = is_conflicting(changes, platform_config.config_munge, self, true /* always force overwrite other edit-config */);
+        if (isConflictingInfo.conflictFound) {
             var conflict_munge;
             var conflict_file;
 
@@ -209,17 +207,17 @@
                 }
             }
         }
-        // Add config.xml edit-config munges
-        config_munge = self.generate_config_xml_munge(config, edit_config_changes, 'config.xml');
     }
 
+    // Add config.xml edit-config and config-file munges
+    config_munge = self.generate_config_xml_munge(config, changes, 'config.xml');
     self = munge_helper(should_increment, self, platform_config, config_munge);
 
     // Move to installed/dependent_plugins
     return self;
 }
 
-function munge_helper(should_increment, self, platform_config, config_munge) {
+function munge_helper (should_increment, self, platform_config, config_munge) {
     // global munge looks at all changes to config files
 
     // TODO: The should_increment param is only used by cordova-cli and is going away soon.
@@ -241,11 +239,10 @@
     return self;
 }
 
-
 // Load the global munge from platform json and apply all of it.
 // Used by cordova prepare to re-generate some config file from platform
 // defaults and the global munge.
-PlatformMunger.prototype.reapply_global_munge = reapply_global_munge ;
+PlatformMunger.prototype.reapply_global_munge = reapply_global_munge;
 function reapply_global_munge () {
     var self = this;
 
@@ -261,58 +258,56 @@
 // generate_plugin_config_munge
 // Generate the munge object from config.xml
 PlatformMunger.prototype.generate_config_xml_munge = generate_config_xml_munge;
-function generate_config_xml_munge(config, edit_config_changes, type) {
-
+function generate_config_xml_munge (config, config_changes, type) {
     var munge = { files: {} };
-    var changes = edit_config_changes;
     var id;
 
-    if(!changes) {
+    if (!config_changes) {
         return munge;
     }
 
     if (type === 'config.xml') {
         id = type;
-    }
-    else {
+    } else {
         id = config.id;
     }
 
-    changes.forEach(function(change) {
-        change.xmls.forEach(function(xml) {
+    config_changes.forEach(function (change) {
+        change.xmls.forEach(function (xml) {
             // 1. stringify each xml
-            var stringified = (new et.ElementTree(xml)).write({xml_declaration:false});
+            var stringified = (new et.ElementTree(xml)).write({xml_declaration: false});
             // 2. add into munge
             if (change.mode) {
                 mungeutil.deep_add(munge, change.file, change.target, { xml: stringified, count: 1, mode: change.mode, id: id });
+            } else {
+                mungeutil.deep_add(munge, change.target, change.parent, { xml: stringified, count: 1, after: change.after });
             }
         });
     });
     return munge;
 }
 
-
 // generate_plugin_config_munge
 // Generate the munge object from plugin.xml + vars
 PlatformMunger.prototype.generate_plugin_config_munge = generate_plugin_config_munge;
-function generate_plugin_config_munge(pluginInfo, vars, edit_config_changes) {
+function generate_plugin_config_munge (pluginInfo, vars, edit_config_changes) {
     var self = this;
 
     vars = vars || {};
     var munge = { files: {} };
     var changes = pluginInfo.getConfigFiles(self.platform);
 
-    if(edit_config_changes) {
+    if (edit_config_changes) {
         Array.prototype.push.apply(changes, edit_config_changes);
     }
 
-    changes.forEach(function(change) {
-        change.xmls.forEach(function(xml) {
+    changes.forEach(function (change) {
+        change.xmls.forEach(function (xml) {
             // 1. stringify each xml
-            var stringified = (new et.ElementTree(xml)).write({xml_declaration:false});
+            var stringified = (new et.ElementTree(xml)).write({xml_declaration: false});
             // interp vars
             if (vars) {
-                Object.keys(vars).forEach(function(key) {
+                Object.keys(vars).forEach(function (key) {
                     var regExp = new RegExp('\\$' + key, 'g');
                     stringified = stringified.replace(regExp, vars[key]);
                 });
@@ -322,8 +317,7 @@
                 if (change.mode !== 'remove') {
                     mungeutil.deep_add(munge, change.file, change.target, { xml: stringified, count: 1, mode: change.mode, plugin: pluginInfo.id });
                 }
-            }
-            else {
+            } else {
                 mungeutil.deep_add(munge, change.target, change.parent, { xml: stringified, count: 1, after: change.after });
             }
         });
@@ -331,7 +325,7 @@
     return munge;
 }
 
-function is_conflicting(editchanges, config_munge, self, force) {
+function is_conflicting (editchanges, config_munge, self, force) {
     var files = config_munge.files;
     var conflictFound = false;
     var conflictWithConfigxml = false;
@@ -340,7 +334,7 @@
     var conflictingParent;
     var conflictingPlugin;
 
-    editchanges.forEach(function(editchange) {
+    editchanges.forEach(function (editchange) {
         if (files[editchange.file]) {
             var parents = files[editchange.file].parents;
             var target = parents[editchange.target];
@@ -361,8 +355,7 @@
                         }
                     }
                 }
-            }
-            else {
+            } else {
                 conflictingParent = editchange.target;
             }
 
@@ -374,13 +367,11 @@
                     if (target[0].id === 'config.xml') {
                         // Keep track of config.xml/config.xml edit-config conflicts
                         mungeutil.deep_add(configxmlMunge, editchange.file, conflictingParent, target[0]);
-                    }
-                    else {
+                    } else {
                         // Keep track of config.xml x plugin.xml edit-config conflicts
                         mungeutil.deep_add(conflictingMunge, editchange.file, conflictingParent, target[0]);
                     }
-                }
-                else {
+                } else {
                     if (target[0].id === 'config.xml') {
                         // plugin.xml cannot overwrite config.xml changes even if --force is used
                         conflictWithConfigxml = true;
@@ -390,36 +381,38 @@
                     if (force) {
                         // Need to find all conflicts when --force is used, track conflicting munges
                         mungeutil.deep_add(conflictingMunge, editchange.file, conflictingParent, target[0]);
-                    }
-                    else {
+                    } else {
                         // plugin cannot overwrite other plugin changes without --force
                         conflictingPlugin = target[0].plugin;
-                        return;
+
                     }
                 }
             }
         }
     });
 
-    return {conflictFound: conflictFound, conflictingPlugin: conflictingPlugin, conflictingMunge: conflictingMunge,
-        configxmlMunge: configxmlMunge, conflictWithConfigxml:conflictWithConfigxml};
+    return {conflictFound: conflictFound,
+        conflictingPlugin: conflictingPlugin,
+        conflictingMunge: conflictingMunge,
+        configxmlMunge: configxmlMunge,
+        conflictWithConfigxml: conflictWithConfigxml};
 }
 
 // Go over the prepare queue and apply the config munges for each plugin
 // that has been (un)installed.
 PlatformMunger.prototype.process = PlatformMunger_process;
-function PlatformMunger_process(plugins_dir) {
+function PlatformMunger_process (plugins_dir) {
     var self = this;
     var platform_config = self.platformJson.root;
 
     // Uninstallation first
-    platform_config.prepare_queue.uninstalled.forEach(function(u) {
+    platform_config.prepare_queue.uninstalled.forEach(function (u) {
         var pluginInfo = self.pluginInfoProvider.get(path.join(plugins_dir, u.plugin));
         self.remove_plugin_changes(pluginInfo, u.topLevel);
     });
 
     // Now handle installation
-    platform_config.prepare_queue.installed.forEach(function(u) {
+    platform_config.prepare_queue.installed.forEach(function (u) {
         var pluginInfo = self.pluginInfoProvider.get(path.join(plugins_dir, u.plugin));
         self.add_plugin_changes(pluginInfo, u.vars, u.topLevel, true, u.force);
     });
@@ -428,4 +421,4 @@
     platform_config.prepare_queue.uninstalled = [];
     platform_config.prepare_queue.installed = [];
 }
-/**** END of PlatformMunger ****/
+/** ** END of PlatformMunger ****/
diff --git a/node_modules/cordova-common/src/ConfigChanges/ConfigFile.js b/node_modules/cordova-common/src/ConfigChanges/ConfigFile.js
index 8f880a4..a4a7331 100644
--- a/node_modules/cordova-common/src/ConfigChanges/ConfigFile.js
+++ b/node_modules/cordova-common/src/ConfigChanges/ConfigFile.js
@@ -14,6 +14,8 @@
  *
 */
 
+/* eslint no-control-regex: 0 */
+
 var fs = require('fs');
 var path = require('path');
 
@@ -42,7 +44,7 @@
 * TODO: Consider moving it out to a separate file and maybe partially with
 * overrides in platform handlers.
 ******************************************************************************/
-function ConfigFile(project_dir, platform, file_tag) {
+function ConfigFile (project_dir, platform, file_tag) {
     this.project_dir = project_dir;
     this.platform = platform;
     this.file_tag = file_tag;
@@ -53,13 +55,13 @@
 
 // ConfigFile.load()
 ConfigFile.prototype.load = ConfigFile_load;
-function ConfigFile_load() {
+function ConfigFile_load () {
     var self = this;
 
     // config file may be in a place not exactly specified in the target
     var filepath = self.filepath = resolveConfigFilePath(self.project_dir, self.platform, self.file_tag);
 
-    if ( !filepath || !fs.existsSync(filepath) ) {
+    if (!filepath || !fs.existsSync(filepath)) {
         self.exists = false;
         return;
     }
@@ -69,7 +71,7 @@
     var ext = path.extname(filepath);
     // Windows8 uses an appxmanifest, and wp8 will likely use
     // the same in a future release
-    if (ext == '.xml' || ext == '.appxmanifest') {
+    if (ext === '.xml' || ext === '.appxmanifest') {
         self.type = 'xml';
         self.data = modules.xml_helpers.parseElementtreeSync(filepath);
     } else {
@@ -80,12 +82,12 @@
         //       Do we still need to support binary plist?
         //       If yes, use plist.parseStringSync() and read the file once.
         self.data = isBinaryPlist(filepath) ?
-                modules.bplist.parseBuffer(fs.readFileSync(filepath)) :
-                modules.plist.parse(fs.readFileSync(filepath, 'utf8'));
+            modules.bplist.parseBuffer(fs.readFileSync(filepath)) :
+            modules.plist.parse(fs.readFileSync(filepath, 'utf8'));
     }
 }
 
-ConfigFile.prototype.save = function ConfigFile_save() {
+ConfigFile.prototype.save = function ConfigFile_save () {
     var self = this;
     if (self.type === 'xml') {
         fs.writeFileSync(self.filepath, self.data.write({indent: 4}), 'utf-8');
@@ -97,54 +99,54 @@
     self.is_changed = false;
 };
 
-ConfigFile.prototype.graft_child = function ConfigFile_graft_child(selector, xml_child) {
+ConfigFile.prototype.graft_child = function ConfigFile_graft_child (selector, xml_child) {
     var self = this;
     var filepath = self.filepath;
     var result;
     if (self.type === 'xml') {
         var xml_to_graft = [modules.et.XML(xml_child.xml)];
         switch (xml_child.mode) {
-            case 'merge':
-                result = modules.xml_helpers.graftXMLMerge(self.data, xml_to_graft, selector, xml_child);
-                break;
-            case 'overwrite':
-                result = modules.xml_helpers.graftXMLOverwrite(self.data, xml_to_graft, selector, xml_child);
-                break;
-            case 'remove':
-                result = modules.xml_helpers.pruneXMLRemove(self.data, selector, xml_to_graft);
-                break;
-            default:
-                result = modules.xml_helpers.graftXML(self.data, xml_to_graft, selector, xml_child.after);
+        case 'merge':
+            result = modules.xml_helpers.graftXMLMerge(self.data, xml_to_graft, selector, xml_child);
+            break;
+        case 'overwrite':
+            result = modules.xml_helpers.graftXMLOverwrite(self.data, xml_to_graft, selector, xml_child);
+            break;
+        case 'remove':
+            result = modules.xml_helpers.pruneXMLRemove(self.data, selector, xml_to_graft);
+            break;
+        default:
+            result = modules.xml_helpers.graftXML(self.data, xml_to_graft, selector, xml_child.after);
         }
-        if ( !result) {
+        if (!result) {
             throw new Error('Unable to graft xml at selector "' + selector + '" from "' + filepath + '" during config install');
         }
     } else {
         // plist file
         result = modules.plist_helpers.graftPLIST(self.data, xml_child.xml, selector);
-        if ( !result ) {
+        if (!result) {
             throw new Error('Unable to graft plist "' + filepath + '" during config install');
         }
     }
     self.is_changed = true;
 };
 
-ConfigFile.prototype.prune_child = function ConfigFile_prune_child(selector, xml_child) {
+ConfigFile.prototype.prune_child = function ConfigFile_prune_child (selector, xml_child) {
     var self = this;
     var filepath = self.filepath;
     var result;
     if (self.type === 'xml') {
         var xml_to_graft = [modules.et.XML(xml_child.xml)];
         switch (xml_child.mode) {
-            case 'merge':
-            case 'overwrite':
-                result = modules.xml_helpers.pruneXMLRestore(self.data, selector, xml_child);
-                break;
-            case 'remove':
-                result = modules.xml_helpers.pruneXMLRemove(self.data, selector, xml_to_graft);
-                break;
-            default:
-                result = modules.xml_helpers.pruneXML(self.data, xml_to_graft, selector);
+        case 'merge':
+        case 'overwrite':
+            result = modules.xml_helpers.pruneXMLRestore(self.data, selector, xml_child);
+            break;
+        case 'remove':
+            result = modules.xml_helpers.pruneXMLRemove(self.data, selector, xml_to_graft);
+            break;
+        default:
+            result = modules.xml_helpers.pruneXML(self.data, xml_to_graft, selector);
         }
     } else {
         // plist file
@@ -160,7 +162,7 @@
 // Some config-file target attributes are not qualified with a full leading directory, or contain wildcards.
 // Resolve to a real path in this function.
 // TODO: getIOSProjectname is slow because of glob, try to avoid calling it several times per project.
-function resolveConfigFilePath(project_dir, platform, file) {
+function resolveConfigFilePath (project_dir, platform, file) {
     var filepath = path.join(project_dir, file);
     var matches;
 
@@ -170,10 +172,10 @@
         if (matches.length) filepath = matches[0];
 
         // [CB-5989] multiple Info.plist files may exist. default to $PROJECT_NAME-Info.plist
-        if(matches.length > 1 && file.indexOf('-Info.plist')>-1){
-            var plistName =  getIOSProjectname(project_dir)+'-Info.plist';
-            for (var i=0; i < matches.length; i++) {
-                if(matches[i].indexOf(plistName) > -1){
+        if (matches.length > 1 && file.indexOf('-Info.plist') > -1) {
+            var plistName = getIOSProjectname(project_dir) + '-Info.plist';
+            for (var i = 0; i < matches.length; i++) {
+                if (matches[i].indexOf(plistName) > -1) {
                     filepath = matches[i];
                     break;
                 }
@@ -184,13 +186,13 @@
 
     // special-case config.xml target that is just "config.xml". This should be resolved to the real location of the file.
     // TODO: move the logic that contains the locations of config.xml from cordova CLI into plugman.
-    if (file == 'config.xml') {
-        if (platform == 'ubuntu') {
+    if (file === 'config.xml') {
+        if (platform === 'ubuntu') {
             filepath = path.join(project_dir, 'config.xml');
-        } else if (platform == 'ios') {
+        } else if (platform === 'ios') {
             var iospath = getIOSProjectname(project_dir);
-            filepath = path.join(project_dir,iospath, 'config.xml');
-        } else if (platform == 'android') {
+            filepath = path.join(project_dir, iospath, 'config.xml');
+        } else if (platform === 'android') {
             filepath = path.join(project_dir, 'res', 'xml', 'config.xml');
         } else {
             matches = modules.glob.sync(path.join(project_dir, '**', 'config.xml'));
@@ -201,8 +203,8 @@
 
     // XXX this checks for android studio projects
     // only if none of the options above are satisfied does this get called
-    if(platform === 'android' && !fs.existsSync(filepath)) {
-      filepath = path.join(project_dir, 'app', 'src', 'main', 'res', 'xml', 'config.xml');
+    if (platform === 'android' && !fs.existsSync(filepath)) {
+        filepath = path.join(project_dir, 'app', 'src', 'main', 'res', 'xml', 'config.xml');
     }
 
     // None of the special cases matched, returning project_dir/file.
@@ -211,11 +213,11 @@
 
 // Find out the real name of an iOS project
 // TODO: glob is slow, need a better way or caching, or avoid using more than once.
-function getIOSProjectname(project_dir) {
+function getIOSProjectname (project_dir) {
     var matches = modules.glob.sync(path.join(project_dir, '*.xcodeproj'));
     var iospath;
     if (matches.length === 1) {
-        iospath = path.basename(matches[0],'.xcodeproj');
+        iospath = path.basename(matches[0], '.xcodeproj');
     } else {
         var msg;
         if (matches.length === 0) {
@@ -229,7 +231,7 @@
 }
 
 // determine if a plist file is binary
-function isBinaryPlist(filename) {
+function isBinaryPlist (filename) {
     // I wish there was a synchronous way to read only the first 6 bytes of a
     // file. This is wasteful :/
     var buf = '' + fs.readFileSync(filename, 'utf8');
diff --git a/node_modules/cordova-common/src/ConfigChanges/ConfigKeeper.js b/node_modules/cordova-common/src/ConfigChanges/ConfigKeeper.js
index 894e922..0ef0435 100644
--- a/node_modules/cordova-common/src/ConfigChanges/ConfigKeeper.js
+++ b/node_modules/cordova-common/src/ConfigChanges/ConfigKeeper.js
@@ -28,18 +28,18 @@
 * project_dir/platform/file
 * where file is the name used for the file in config munges.
 ******************************************************************************/
-function ConfigKeeper(project_dir, plugins_dir) {
+function ConfigKeeper (project_dir, plugins_dir) {
     this.project_dir = project_dir;
     this.plugins_dir = plugins_dir;
     this._cached = {};
 }
 
-ConfigKeeper.prototype.get = function ConfigKeeper_get(project_dir, platform, file) {
+ConfigKeeper.prototype.get = function ConfigKeeper_get (project_dir, platform, file) {
     var self = this;
 
     // This fixes a bug with older plugins - when specifying config xml instead of res/xml/config.xml
     // https://issues.apache.org/jira/browse/CB-6414
-    if(file == 'config.xml' && platform == 'android'){
+    if (file === 'config.xml' && platform === 'android') {
         file = 'res/xml/config.xml';
     }
     var fake_path = path.join(project_dir, platform, file);
@@ -53,8 +53,7 @@
     return config_file;
 };
 
-
-ConfigKeeper.prototype.save_all = function ConfigKeeper_save_all() {
+ConfigKeeper.prototype.save_all = function ConfigKeeper_save_all () {
     var self = this;
     Object.keys(self._cached).forEach(function (fake_path) {
         var config_file = self._cached[fake_path];
diff --git a/node_modules/cordova-common/src/ConfigChanges/munge-util.js b/node_modules/cordova-common/src/ConfigChanges/munge-util.js
index 0149bab..62648d8 100644
--- a/node_modules/cordova-common/src/ConfigChanges/munge-util.js
+++ b/node_modules/cordova-common/src/ConfigChanges/munge-util.js
@@ -19,14 +19,14 @@
 
 // add the count of [key1][key2]...[keyN] to obj
 // return true if it didn't exist before
-exports.deep_add = function deep_add(obj, keys /* or key1, key2 .... */ ) {
-    if ( !Array.isArray(keys) ) {
+exports.deep_add = function deep_add (obj, keys /* or key1, key2 .... */) {
+    if (!Array.isArray(keys)) {
         keys = Array.prototype.slice.call(arguments, 1);
     }
 
-    return exports.process_munge(obj, true/*createParents*/, function (parentArray, k) {
-        var found = _.find(parentArray, function(element) {
-            return element.xml == k.xml;
+    return exports.process_munge(obj, true/* createParents */, function (parentArray, k) {
+        var found = _.find(parentArray, function (element) {
+            return element.xml === k.xml;
         });
         if (found) {
             found.after = found.after || k.after;
@@ -40,16 +40,16 @@
 
 // decrement the count of [key1][key2]...[keyN] from obj and remove if it reaches 0
 // return true if it was removed or not found
-exports.deep_remove = function deep_remove(obj, keys /* or key1, key2 .... */ ) {
-    if ( !Array.isArray(keys) ) {
+exports.deep_remove = function deep_remove (obj, keys /* or key1, key2 .... */) {
+    if (!Array.isArray(keys)) {
         keys = Array.prototype.slice.call(arguments, 1);
     }
 
-    var result = exports.process_munge(obj, false/*createParents*/, function (parentArray, k) {
+    var result = exports.process_munge(obj, false/* createParents */, function (parentArray, k) {
         var index = -1;
         var found = _.find(parentArray, function (element) {
             index++;
-            return element.xml == k.xml;
+            return element.xml === k.xml;
         });
         if (found) {
             if (parentArray[index].oldAttrib) {
@@ -58,8 +58,7 @@
             found.count -= k.count;
             if (found.count > 0) {
                 return false;
-            }
-            else {
+            } else {
                 parentArray.splice(index, 1);
             }
         }
@@ -71,14 +70,14 @@
 
 // search for [key1][key2]...[keyN]
 // return the object or undefined if not found
-exports.deep_find = function deep_find(obj, keys /* or key1, key2 .... */ ) {
-    if ( !Array.isArray(keys) ) {
+exports.deep_find = function deep_find (obj, keys /* or key1, key2 .... */) {
+    if (!Array.isArray(keys)) {
         keys = Array.prototype.slice.call(arguments, 1);
     }
 
-    return exports.process_munge(obj, false/*createParents?*/, function (parentArray, k) {
+    return exports.process_munge(obj, false/* createParents? */, function (parentArray, k) {
         return _.find(parentArray, function (element) {
-            return element.xml == (k.xml || k);
+            return element.xml === (k.xml || k);
         });
     }, keys);
 };
@@ -87,20 +86,20 @@
 // When createParents is true, add the file and parent items  they are missing
 // When createParents is false, stop and return undefined if the file and/or parent items are missing
 
-exports.process_munge = function process_munge(obj, createParents, func, keys /* or key1, key2 .... */ ) {
-    if ( !Array.isArray(keys) ) {
+exports.process_munge = function process_munge (obj, createParents, func, keys /* or key1, key2 .... */) {
+    if (!Array.isArray(keys)) {
         keys = Array.prototype.slice.call(arguments, 1);
     }
     var k = keys[0];
-    if (keys.length == 1) {
+    if (keys.length === 1) {
         return func(obj, k);
-    } else if (keys.length == 2) {
+    } else if (keys.length === 2) {
         if (!obj.parents[k] && !createParents) {
             return undefined;
         }
         obj.parents[k] = obj.parents[k] || [];
         return exports.process_munge(obj.parents[k], createParents, func, keys.slice(1));
-    } else if (keys.length == 3){
+    } else if (keys.length === 3) {
         if (!obj.files[k] && !createParents) {
             return undefined;
         }
@@ -115,7 +114,7 @@
 // base[file][selector][child] += munge[file][selector][child]
 // Returns a munge object containing values that exist in munge
 // but not in base.
-exports.increment_munge = function increment_munge(base, munge) {
+exports.increment_munge = function increment_munge (base, munge) {
     var diff = { files: {} };
 
     for (var file in munge.files) {
@@ -138,7 +137,7 @@
 // base[file][selector][child] -= munge[file][selector][child]
 // nodes that reached zero value are removed from base and added to the returned munge
 // object.
-exports.decrement_munge = function decrement_munge(base, munge) {
+exports.decrement_munge = function decrement_munge (base, munge) {
     var zeroed = { files: {} };
 
     for (var file in munge.files) {
@@ -158,6 +157,6 @@
 };
 
 // For better readability where used
-exports.clone_munge = function clone_munge(munge) {
+exports.clone_munge = function clone_munge (munge) {
     return exports.increment_munge({}, munge);
 };
diff --git a/node_modules/cordova-common/src/ConfigParser/ConfigParser.js b/node_modules/cordova-common/src/ConfigParser/ConfigParser.js
index 0b02b4c..9c3943e 100644
--- a/node_modules/cordova-common/src/ConfigParser/ConfigParser.js
+++ b/node_modules/cordova-common/src/ConfigParser/ConfigParser.js
@@ -17,24 +17,21 @@
     under the License.
 */
 
-/* jshint sub:true */
-
-var et = require('elementtree'),
-    xml= require('../util/xml-helpers'),
-    CordovaError = require('../CordovaError/CordovaError'),
-    fs = require('fs'),
-    events = require('../events');
-
+var et = require('elementtree');
+var xml = require('../util/xml-helpers');
+var CordovaError = require('../CordovaError/CordovaError');
+var fs = require('fs');
+var events = require('../events');
 
 /** Wraps a config.xml file */
-function ConfigParser(path) {
+function ConfigParser (path) {
     this.path = path;
     try {
         this.doc = xml.parseElementtreeSync(path);
         this.cdvNamespacePrefix = getCordovaNamespacePrefix(this.doc);
         et.register_namespace(this.cdvNamespacePrefix, 'http://cordova.apache.org/ns/1.0');
     } catch (e) {
-        console.error('Parsing '+path+' failed');
+        console.error('Parsing ' + path + ' failed');
         throw e;
     }
     var r = this.doc.getroot();
@@ -43,11 +40,11 @@
     }
 }
 
-function getNodeTextSafe(el) {
+function getNodeTextSafe (el) {
     return el && el.text && el.text.trim();
 }
 
-function findOrCreate(doc, name) {
+function findOrCreate (doc, name) {
     var ret = doc.find(name);
     if (!ret) {
         ret = new et.Element(name);
@@ -56,12 +53,12 @@
     return ret;
 }
 
-function getCordovaNamespacePrefix(doc){
+function getCordovaNamespacePrefix (doc) {
     var rootAtribs = Object.getOwnPropertyNames(doc.getroot().attrib);
     var prefix = 'cdv';
-    for (var j = 0; j < rootAtribs.length; j++ ) {
-        if(rootAtribs[j].indexOf('xmlns:') === 0 &&
-            doc.getroot().attrib[rootAtribs[j]] === 'http://cordova.apache.org/ns/1.0'){
+    for (var j = 0; j < rootAtribs.length; j++) {
+        if (rootAtribs[j].indexOf('xmlns:') === 0 &&
+            doc.getroot().attrib[rootAtribs[j]] === 'http://cordova.apache.org/ns/1.0') {
             var strings = rootAtribs[j].split(':');
             prefix = strings[1];
             break;
@@ -76,7 +73,7 @@
  * @param  {Array}  elems         An array of ElementTree nodes
  * @return {String}
  */
-function findElementAttributeValue(attributeName, elems) {
+function findElementAttributeValue (attributeName, elems) {
 
     elems = Array.isArray(elems) ? elems : [ elems ];
 
@@ -86,69 +83,69 @@
         return filteredElems.attrib.value;
     }).pop();
 
-    return value ? value : '';
+    return value || '';
 }
 
 ConfigParser.prototype = {
-    getAttribute: function(attr) {
+    getAttribute: function (attr) {
         return this.doc.getroot().attrib[attr];
     },
 
-    packageName: function(id) {
+    packageName: function (id) {
         return this.getAttribute('id');
     },
-    setPackageName: function(id) {
+    setPackageName: function (id) {
         this.doc.getroot().attrib['id'] = id;
     },
-    android_packageName: function() {
+    android_packageName: function () {
         return this.getAttribute('android-packageName');
     },
-    android_activityName: function() {
+    android_activityName: function () {
         return this.getAttribute('android-activityName');
     },
-    ios_CFBundleIdentifier: function() {
+    ios_CFBundleIdentifier: function () {
         return this.getAttribute('ios-CFBundleIdentifier');
     },
-    name: function() {
+    name: function () {
         return getNodeTextSafe(this.doc.find('name'));
     },
-    setName: function(name) {
+    setName: function (name) {
         var el = findOrCreate(this.doc, 'name');
         el.text = name;
     },
-    shortName: function() {
+    shortName: function () {
         return this.doc.find('name').attrib['short'] || this.name();
     },
-    setShortName: function(shortname) {
+    setShortName: function (shortname) {
         var el = findOrCreate(this.doc, 'name');
         if (!el.text) {
             el.text = shortname;
         }
         el.attrib['short'] = shortname;
     },
-    description: function() {
+    description: function () {
         return getNodeTextSafe(this.doc.find('description'));
     },
-    setDescription: function(text) {
+    setDescription: function (text) {
         var el = findOrCreate(this.doc, 'description');
         el.text = text;
     },
-    version: function() {
+    version: function () {
         return this.getAttribute('version');
     },
-    windows_packageVersion: function() {
+    windows_packageVersion: function () {
         return this.getAttribute('windows-packageVersion');
     },
-    android_versionCode: function() {
+    android_versionCode: function () {
         return this.getAttribute('android-versionCode');
     },
-    ios_CFBundleVersion: function() {
+    ios_CFBundleVersion: function () {
         return this.getAttribute('ios-CFBundleVersion');
     },
-    setVersion: function(value) {
+    setVersion: function (value) {
         this.doc.getroot().attrib['version'] = value;
     },
-    author: function() {
+    author: function () {
         return getNodeTextSafe(this.doc.find('author'));
     },
     getGlobalPreference: function (name) {
@@ -166,7 +163,7 @@
     getPlatformPreference: function (name, platform) {
         return findElementAttributeValue(name, this.doc.findall('platform[@name=\'' + platform + '\']/preference'));
     },
-    getPreference: function(name, platform) {
+    getPreference: function (name, platform) {
 
         var platformPreference = '';
 
@@ -174,7 +171,7 @@
             platformPreference = this.getPlatformPreference(name, platform);
         }
 
-        return platformPreference ? platformPreference : this.getGlobalPreference(name);
+        return platformPreference || this.getGlobalPreference(name);
 
     },
     /**
@@ -184,11 +181,11 @@
      *                               "icon" and "splash" currently supported.
      * @return {Array}               Resources for the platform specified.
      */
-    getStaticResources: function(platform, resourceName) {
-        var ret = [],
-            staticResources = [];
+    getStaticResources: function (platform, resourceName) {
+        var ret = [];
+        var staticResources = [];
         if (platform) { // platform specific icons
-            this.doc.findall('platform[@name=\'' + platform + '\']/' + resourceName).forEach(function(elt){
+            this.doc.findall('platform[@name=\'' + platform + '\']/' + resourceName).forEach(function (elt) {
                 elt.platform = platform; // mark as platform specific resource
                 staticResources.push(elt);
             });
@@ -201,7 +198,7 @@
             var res = {};
             res.src = elt.attrib.src;
             res.target = elt.attrib.target || undefined;
-            res.density = elt.attrib['density'] || elt.attrib[that.cdvNamespacePrefix+':density'] || elt.attrib['gap:density'];
+            res.density = elt.attrib['density'] || elt.attrib[that.cdvNamespacePrefix + ':density'] || elt.attrib['gap:density'];
             res.platform = elt.platform || null; // null means icon represents default icon (shared between platforms)
             res.width = +elt.attrib.width || undefined;
             res.height = +elt.attrib.height || undefined;
@@ -219,13 +216,13 @@
          * @param  {number} height Height of resource.
          * @return {Resource} Resource object or null if not found.
          */
-        ret.getBySize = function(width, height) {
-            return ret.filter(function(res) {
+        ret.getBySize = function (width, height) {
+            return ret.filter(function (res) {
                 if (!res.width && !res.height) {
                     return false;
                 }
-                return ((!res.width || (width == res.width)) &&
-                    (!res.height || (height == res.height)));
+                return ((!res.width || (width === res.width)) &&
+                    (!res.height || (height === res.height)));
             })[0] || null;
         };
 
@@ -234,14 +231,14 @@
          * @param  {string} density Density of resource.
          * @return {Resource}       Resource object or null if not found.
          */
-        ret.getByDensity = function(density) {
-            return ret.filter(function(res) {
-                return res.density == density;
+        ret.getByDensity = function (density) {
+            return ret.filter(function (res) {
+                return res.density === density;
             })[0] || null;
         };
 
         /** Returns default icons */
-        ret.getDefault = function() {
+        ret.getDefault = function () {
             return ret.defaultResource;
         };
 
@@ -253,7 +250,7 @@
      * @param  {string} platform Platform name
      * @return {Resource[]}      Array of icon objects.
      */
-    getIcons: function(platform) {
+    getIcons: function (platform) {
         return this.getStaticResources(platform, 'icon');
     },
 
@@ -262,7 +259,7 @@
      * @param  {string} platform Platform name
      * @return {Resource[]}      Array of Splash objects.
      */
-    getSplashScreens: function(platform) {
+    getSplashScreens: function (platform) {
         return this.getStaticResources(platform, 'splash');
     },
 
@@ -273,11 +270,11 @@
      *                                 root level.
      * @return {Resource[]}      Array of resource file objects.
      */
-    getFileResources: function(platform, includeGlobal) {
+    getFileResources: function (platform, includeGlobal) {
         var fileResources = [];
 
         if (platform) { // platform specific resources
-            fileResources = this.doc.findall('platform[@name=\'' + platform + '\']/resource-file').map(function(tag) {
+            fileResources = this.doc.findall('platform[@name=\'' + platform + '\']/resource-file').map(function (tag) {
                 return {
                     platform: platform,
                     src: tag.attrib.src,
@@ -290,7 +287,7 @@
         }
 
         if (includeGlobal) {
-            this.doc.findall('resource-file').forEach(function(tag) {
+            this.doc.findall('resource-file').forEach(function (tag) {
                 fileResources.push({
                     platform: platform || null,
                     src: tag.attrib.src,
@@ -311,23 +308,23 @@
      * @param {Array}  platforms Platforms to look for scripts into (root scripts will be included as well).
      * @return {Array}               Script elements.
      */
-    getHookScripts: function(hook, platforms) {
+    getHookScripts: function (hook, platforms) {
         var self = this;
         var scriptElements = self.doc.findall('./hook');
 
-        if(platforms) {
+        if (platforms) {
             platforms.forEach(function (platform) {
                 scriptElements = scriptElements.concat(self.doc.findall('./platform[@name="' + platform + '"]/hook'));
             });
         }
 
-        function filterScriptByHookType(el) {
+        function filterScriptByHookType (el) {
             return el.attrib.src && el.attrib.type && el.attrib.type.toLowerCase() === hook;
         }
 
         return scriptElements.filter(filterScriptByHookType);
     },
-   /**
+    /**
     * Returns a list of plugin (IDs).
     *
     * This function also returns any plugin's that
@@ -336,13 +333,13 @@
     */
     getPluginIdList: function () {
         var plugins = this.doc.findall('plugin');
-        var result = plugins.map(function(plugin){
+        var result = plugins.map(function (plugin) {
             return plugin.attrib.name;
         });
         var features = this.doc.findall('feature');
-        features.forEach(function(element ){
+        features.forEach(function (element) {
             var idTag = element.find('./param[@name="id"]');
-            if(idTag){
+            if (idTag) {
                 result.push(idTag.attrib.value);
             }
         });
@@ -371,9 +368,9 @@
         // support arbitrary object as variables source
         if (variables && typeof variables === 'object' && !Array.isArray(variables)) {
             variables = Object.keys(variables)
-            .map(function (variableName) {
-                return {name: variableName, value: variables[variableName]};
-            });
+                .map(function (variableName) {
+                    return {name: variableName, value: variables[variableName]};
+                });
         }
 
         if (variables) {
@@ -393,15 +390,15 @@
      * @param {String} id
      * @returns {object} plugin including any variables
      */
-    getPlugin: function(id){
-        if(!id){
+    getPlugin: function (id) {
+        if (!id) {
             return undefined;
         }
         var pluginElement = this.doc.find('./plugin/[@name="' + id + '"]');
-        if (null === pluginElement) {
-            var legacyFeature =  this.doc.find('./feature/param[@name="id"][@value="' + id + '"]/..');
-            if(legacyFeature){
-                 events.emit('log', 'Found deprecated feature entry for ' + id +' in config.xml.');
+        if (pluginElement === null) {
+            var legacyFeature = this.doc.find('./feature/param[@name="id"][@value="' + id + '"]/..');
+            if (legacyFeature) {
+                events.emit('log', 'Found deprecated feature entry for ' + id + ' in config.xml.');
                 return featureToPlugin(legacyFeature);
             }
             return undefined;
@@ -412,10 +409,10 @@
         plugin.spec = pluginElement.attrib.spec || pluginElement.attrib.src || pluginElement.attrib.version;
         plugin.variables = {};
         var variableElements = pluginElement.findall('variable');
-        variableElements.forEach(function(varElement){
+        variableElements.forEach(function (varElement) {
             var name = varElement.attrib.name;
             var value = varElement.attrib.value;
-            if(name){
+            if (name) {
                 plugin.variables[name] = value;
             }
         });
@@ -430,8 +427,8 @@
      * @function
      * @param id name of the plugin
      */
-    removePlugin: function(id){
-        if(id){
+    removePlugin: function (id) {
+        if (id) {
             var plugins = this.doc.findall('./plugin/[@name="' + id + '"]')
                 .concat(this.doc.findall('./feature/param[@name="id"][@value="' + id + '"]/..'));
             var children = this.doc.getroot().getchildren();
@@ -445,7 +442,7 @@
     },
 
     // Add any element to the root
-    addElement: function(name, attributes) {
+    addElement: function (name, attributes) {
         var el = et.Element(name);
         for (var a in attributes) {
             el.attrib[a] = attributes[a];
@@ -458,11 +455,11 @@
      * @param  {String} name the engine name
      * @param  {String} spec engine source location or version (optional)
      */
-    addEngine: function(name, spec){
-        if(!name) return;
+    addEngine: function (name, spec) {
+        if (!name) return;
         var el = et.Element('engine');
         el.attrib.name = name;
-        if(spec){
+        if (spec) {
             el.attrib.spec = spec;
         }
         this.doc.getroot().append(el);
@@ -471,52 +468,54 @@
      * Removes all the engines with given name
      * @param  {String} name the engine name.
      */
-    removeEngine: function(name){
-        var engines = this.doc.findall('./engine/[@name="' +name+'"]');
-        for(var i=0; i < engines.length; i++){
+    removeEngine: function (name) {
+        var engines = this.doc.findall('./engine/[@name="' + name + '"]');
+        for (var i = 0; i < engines.length; i++) {
             var children = this.doc.getroot().getchildren();
             var idx = children.indexOf(engines[i]);
-            if(idx > -1){
-                children.splice(idx,1);
+            if (idx > -1) {
+                children.splice(idx, 1);
             }
         }
     },
-    getEngines: function(){
+    getEngines: function () {
         var engines = this.doc.findall('./engine');
-        return engines.map(function(engine){
+        return engines.map(function (engine) {
             var spec = engine.attrib.spec || engine.attrib.version;
             return {
                 'name': engine.attrib.name,
-                'spec': spec ? spec : null
+                'spec': spec || null
             };
         });
     },
     /* Get all the access tags */
-    getAccesses: function() {
+    getAccesses: function () {
         var accesses = this.doc.findall('./access');
-        return accesses.map(function(access){
+        return accesses.map(function (access) {
             var minimum_tls_version = access.attrib['minimum-tls-version']; /* String */
             var requires_forward_secrecy = access.attrib['requires-forward-secrecy']; /* Boolean */
             var requires_certificate_transparency = access.attrib['requires-certificate-transparency']; /* Boolean */
             var allows_arbitrary_loads_in_web_content = access.attrib['allows-arbitrary-loads-in-web-content']; /* Boolean */
-            var allows_arbitrary_loads_in_media = access.attrib['allows-arbitrary-loads-in-media']; /* Boolean */
+            var allows_arbitrary_loads_in_media = access.attrib['allows-arbitrary-loads-in-media']; /* Boolean (DEPRECATED) */
+            var allows_arbitrary_loads_for_media = access.attrib['allows-arbitrary-loads-for-media']; /* Boolean */
             var allows_local_networking = access.attrib['allows-local-networking']; /* Boolean */
-            
+
             return {
                 'origin': access.attrib.origin,
                 'minimum_tls_version': minimum_tls_version,
-                'requires_forward_secrecy' : requires_forward_secrecy,
-                'requires_certificate_transparency' : requires_certificate_transparency,
-                'allows_arbitrary_loads_in_web_content' : allows_arbitrary_loads_in_web_content,
-                'allows_arbitrary_loads_in_media' : allows_arbitrary_loads_in_media,
-                'allows_local_networking' : allows_local_networking
+                'requires_forward_secrecy': requires_forward_secrecy,
+                'requires_certificate_transparency': requires_certificate_transparency,
+                'allows_arbitrary_loads_in_web_content': allows_arbitrary_loads_in_web_content,
+                'allows_arbitrary_loads_in_media': allows_arbitrary_loads_in_media,
+                'allows_arbitrary_loads_for_media': allows_arbitrary_loads_for_media,
+                'allows_local_networking': allows_local_networking
             };
         });
     },
     /* Get all the allow-navigation tags */
-    getAllowNavigations: function() {
+    getAllowNavigations: function () {
         var allow_navigations = this.doc.findall('./allow-navigation');
-        return allow_navigations.map(function(allow_navigation){
+        return allow_navigations.map(function (allow_navigation) {
             var minimum_tls_version = allow_navigation.attrib['minimum-tls-version']; /* String */
             var requires_forward_secrecy = allow_navigation.attrib['requires-forward-secrecy']; /* Boolean */
             var requires_certificate_transparency = allow_navigation.attrib['requires-certificate-transparency']; /* Boolean */
@@ -524,45 +523,68 @@
             return {
                 'href': allow_navigation.attrib.href,
                 'minimum_tls_version': minimum_tls_version,
-                'requires_forward_secrecy' : requires_forward_secrecy,
-                'requires_certificate_transparency' : requires_certificate_transparency
+                'requires_forward_secrecy': requires_forward_secrecy,
+                'requires_certificate_transparency': requires_certificate_transparency
             };
         });
     },
     /* Get all the allow-intent tags */
-    getAllowIntents: function() {
+    getAllowIntents: function () {
         var allow_intents = this.doc.findall('./allow-intent');
-        return allow_intents.map(function(allow_intent){
+        return allow_intents.map(function (allow_intent) {
             return {
                 'href': allow_intent.attrib.href
             };
         });
     },
     /* Get all edit-config tags */
-    getEditConfigs: function(platform) {
+    getEditConfigs: function (platform) {
         var platform_tag = this.doc.find('./platform[@name="' + platform + '"]');
         var platform_edit_configs = platform_tag ? platform_tag.findall('edit-config') : [];
 
         var edit_configs = this.doc.findall('edit-config').concat(platform_edit_configs);
 
-        return edit_configs.map(function(tag) {
+        return edit_configs.map(function (tag) {
             var editConfig =
                 {
-                    file : tag.attrib['file'],
-                    target : tag.attrib['target'],
-                    mode : tag.attrib['mode'],
-                    id : 'config.xml',
-                    xmls : tag.getchildren()
+                    file: tag.attrib['file'],
+                    target: tag.attrib['target'],
+                    mode: tag.attrib['mode'],
+                    id: 'config.xml',
+                    xmls: tag.getchildren()
                 };
             return editConfig;
         });
     },
-    write:function() {
+
+    /* Get all config-file tags */
+    getConfigFiles: function (platform) {
+        var platform_tag = this.doc.find('./platform[@name="' + platform + '"]');
+        var platform_config_files = platform_tag ? platform_tag.findall('config-file') : [];
+
+        var config_files = this.doc.findall('config-file').concat(platform_config_files);
+
+        return config_files.map(function (tag) {
+            var configFile =
+                {
+                    target: tag.attrib['target'],
+                    parent: tag.attrib['parent'],
+                    after: tag.attrib['after'],
+                    xmls: tag.getchildren(),
+                    // To support demuxing via versions
+                    versions: tag.attrib['versions'],
+                    deviceTarget: tag.attrib['device-target']
+                };
+            return configFile;
+        });
+    },
+
+    write: function () {
         fs.writeFileSync(this.path, this.doc.write({indent: 4}), 'utf-8');
     }
 };
 
-function featureToPlugin(featureElement) {
+function featureToPlugin (featureElement) {
     var plugin = {};
     plugin.variables = [];
     var pluginVersion,
diff --git a/node_modules/cordova-common/src/CordovaCheck.js b/node_modules/cordova-common/src/CordovaCheck.js
index 46e733f..28f629d 100644
--- a/node_modules/cordova-common/src/CordovaCheck.js
+++ b/node_modules/cordova-common/src/CordovaCheck.js
@@ -17,10 +17,10 @@
     under the License.
 */
 
-var fs = require('fs'),
-    path = require('path');
+var fs = require('fs');
+var path = require('path');
 
-function isRootDir(dir) {
+function isRootDir (dir) {
     if (fs.existsSync(path.join(dir, 'www'))) {
         if (fs.existsSync(path.join(dir, 'config.xml'))) {
             // For sure is.
@@ -41,12 +41,12 @@
 // Runs up the directory chain looking for a .cordova directory.
 // IF it is found we are in a Cordova project.
 // Omit argument to use CWD.
-function isCordova(dir) {
+function isCordova (dir) {
     if (!dir) {
         // Prefer PWD over cwd so that symlinked dirs within your PWD work correctly (CB-5687).
         var pwd = process.env.PWD;
         var cwd = process.cwd();
-        if (pwd && pwd != cwd && pwd != 'undefined') {
+        if (pwd && pwd !== cwd && pwd !== 'undefined') {
             return isCordova(pwd) || isCordova(cwd);
         }
         return isCordova(cwd);
@@ -62,7 +62,7 @@
         }
         var parentDir = path.normalize(path.join(dir, '..'));
         // Detect fs root.
-        if (parentDir == dir) {
+        if (parentDir === dir) {
             return bestReturnValueSoFar;
         }
         dir = parentDir;
@@ -72,5 +72,5 @@
 }
 
 module.exports = {
-    findProjectRoot : isCordova
+    findProjectRoot: isCordova
 };
diff --git a/node_modules/cordova-common/src/CordovaError/CordovaError.js b/node_modules/cordova-common/src/CordovaError/CordovaError.js
index 7262448..24de6af 100644
--- a/node_modules/cordova-common/src/CordovaError/CordovaError.js
+++ b/node_modules/cordova-common/src/CordovaError/CordovaError.js
@@ -17,7 +17,7 @@
     under the License.
 */
 
-/* jshint proto:true */
+/* eslint no-proto: 0 */
 
 var EOL = require('os').EOL;
 
@@ -30,7 +30,7 @@
  * @param {CordovaExternalToolErrorContext} [context] External tool error context object
  * @constructor
  */
-function CordovaError(message, code, context) {
+function CordovaError (message, code, context) {
     Error.captureStackTrace(this, this.constructor);
     this.name = this.constructor.name;
     this.message = message;
@@ -47,10 +47,10 @@
  * Translates instance's error code number into error code name, e.g. 0 -> UNKNOWN_ERROR
  * @returns {string} Error code string name
  */
-CordovaError.prototype.getErrorCodeName = function() {
-    for(var key in CordovaError) {
-        if(CordovaError.hasOwnProperty(key)) {
-            if(CordovaError[key] === this.code) {
+CordovaError.prototype.getErrorCodeName = function () {
+    for (var key in CordovaError) {
+        if (CordovaError.hasOwnProperty(key)) {
+            if (CordovaError[key] === this.code) {
                 return key;
             }
         }
@@ -63,16 +63,17 @@
  *   details including information about error code name and context
  * @return  {String}              Stringified error representation
  */
-CordovaError.prototype.toString = function(isVerbose) {
-    var message = '', codePrefix = '';
+CordovaError.prototype.toString = function (isVerbose) {
+    var message = '';
+    var codePrefix = '';
 
-    if(this.code !== CordovaError.UNKNOWN_ERROR) {
+    if (this.code !== CordovaError.UNKNOWN_ERROR) {
         codePrefix = 'code: ' + this.code + (isVerbose ? (' (' + this.getErrorCodeName() + ')') : '') + ' ';
     }
 
-    if(this.code === CordovaError.EXTERNAL_TOOL_ERROR) {
-        if(typeof this.context !== 'undefined') {
-            if(isVerbose) {
+    if (this.code === CordovaError.EXTERNAL_TOOL_ERROR) {
+        if (typeof this.context !== 'undefined') {
+            if (isVerbose) {
                 message = codePrefix + EOL + this.context.toString(isVerbose) + '\n failed with an error: ' +
                     this.message + EOL + 'Stack trace: ' + this.stack;
             } else {
diff --git a/node_modules/cordova-common/src/CordovaError/CordovaExternalToolErrorContext.js b/node_modules/cordova-common/src/CordovaError/CordovaExternalToolErrorContext.js
index ca9a4aa..30699b4 100644
--- a/node_modules/cordova-common/src/CordovaError/CordovaExternalToolErrorContext.js
+++ b/node_modules/cordova-common/src/CordovaError/CordovaExternalToolErrorContext.js
@@ -27,7 +27,7 @@
  * @param {String} [cwd] Command working directory
  * @constructor
  */
-function CordovaExternalToolErrorContext(cmd, args, cwd) {
+function CordovaExternalToolErrorContext (cmd, args, cwd) {
     this.cmd = cmd;
     // Helper field for readability
     this.cmdShortName = path.basename(cmd);
@@ -35,8 +35,8 @@
     this.cwd = cwd;
 }
 
-CordovaExternalToolErrorContext.prototype.toString = function(isVerbose) {
-    if(isVerbose) {
+CordovaExternalToolErrorContext.prototype.toString = function (isVerbose) {
+    if (isVerbose) {
         return 'External tool \'' + this.cmdShortName + '\'' +
             '\nCommand full path: ' + this.cmd + '\nCommand args: ' + this.args +
             (typeof this.cwd !== 'undefined' ? '\nCommand cwd: ' + this.cwd : '');
diff --git a/node_modules/cordova-common/src/CordovaLogger.js b/node_modules/cordova-common/src/CordovaLogger.js
index 71bc7e8..ea6e9ce 100644
--- a/node_modules/cordova-common/src/CordovaLogger.js
+++ b/node_modules/cordova-common/src/CordovaLogger.js
@@ -41,11 +41,11 @@
     this.stderrCursor = ansi(this.stderr);
 
     this.addLevel('verbose', 1000, 'grey');
-    this.addLevel('normal' , 2000);
-    this.addLevel('warn'   , 2000, 'yellow');
-    this.addLevel('info'   , 3000, 'blue');
-    this.addLevel('error'  , 5000, 'red');
-    this.addLevel('results' , 10000);
+    this.addLevel('normal', 2000);
+    this.addLevel('warn', 2000, 'yellow');
+    this.addLevel('info', 3000, 'blue');
+    this.addLevel('error', 5000, 'red');
+    this.addLevel('results', 10000);
 
     this.setLevel('normal');
 }
@@ -82,9 +82,10 @@
 CordovaLogger.prototype.log = function (logLevel, message) {
     // if there is no such logLevel defined, or provided level has
     // less severity than active level, then just ignore this call and return
-    if (!this.levels[logLevel] || this.levels[logLevel] < this.levels[this.logLevel])
+    if (!this.levels[logLevel] || this.levels[logLevel] < this.levels[this.logLevel]) {
         // return instance to allow to chain calls
         return this;
+    }
 
     var isVerbose = this.logLevel === 'verbose';
     var cursor = this.stdoutCursor;
@@ -179,8 +180,7 @@
  */
 CordovaLogger.prototype.subscribe = function (eventEmitter) {
 
-    if (!(eventEmitter instanceof EventEmitter))
-        throw new Error('Subscribe method only accepts an EventEmitter instance as argument');
+    if (!(eventEmitter instanceof EventEmitter)) { throw new Error('Subscribe method only accepts an EventEmitter instance as argument'); }
 
     eventEmitter.on('verbose', this.verbose)
         .on('log', this.normal)
@@ -193,7 +193,7 @@
     return this;
 };
 
-function formatError(error, isVerbose) {
+function formatError (error, isVerbose) {
     var message = '';
 
     if (error instanceof CordovaError) {
diff --git a/node_modules/cordova-common/src/FileUpdater.js b/node_modules/cordova-common/src/FileUpdater.js
index 8b6876b..c4eeb97 100644
--- a/node_modules/cordova-common/src/FileUpdater.js
+++ b/node_modules/cordova-common/src/FileUpdater.js
@@ -17,12 +17,12 @@
     under the License.
 */
 
-"use strict";
+'use strict';
 
-var fs = require("fs");
-var path = require("path");
-var shell = require("shelljs");
-var minimatch = require("minimatch");
+var fs = require('fs');
+var path = require('path');
+var shell = require('shelljs');
+var minimatch = require('minimatch');
 
 /**
  * Logging callback used in the FileUpdater methods.
@@ -55,27 +55,27 @@
  * @return {boolean} true if any changes were made, or false if the force flag is not set
  *     and everything was up to date
  */
-function updatePathWithStats(sourcePath, sourceStats, targetPath, targetStats, options, log) {
+function updatePathWithStats (sourcePath, sourceStats, targetPath, targetStats, options, log) {
     var updated = false;
 
-    var rootDir = (options && options.rootDir) || "";
+    var rootDir = (options && options.rootDir) || '';
     var copyAll = (options && options.all) || false;
 
-    var targetFullPath = path.join(rootDir || "", targetPath);
+    var targetFullPath = path.join(rootDir || '', targetPath);
 
     if (sourceStats) {
-        var sourceFullPath = path.join(rootDir || "", sourcePath);
+        var sourceFullPath = path.join(rootDir || '', sourcePath);
 
         if (targetStats) {
             // The target exists. But if the directory status doesn't match the source, delete it.
             if (targetStats.isDirectory() && !sourceStats.isDirectory()) {
-                log("rmdir  " + targetPath + " (source is a file)");
-                shell.rm("-rf", targetFullPath);
+                log('rmdir  ' + targetPath + ' (source is a file)');
+                shell.rm('-rf', targetFullPath);
                 targetStats = null;
                 updated = true;
             } else if (!targetStats.isDirectory() && sourceStats.isDirectory()) {
-                log("delete " + targetPath + " (source is a directory)");
-                shell.rm("-f", targetFullPath);
+                log('delete ' + targetPath + ' (source is a directory)');
+                shell.rm('-f', targetFullPath);
                 targetStats = null;
                 updated = true;
             }
@@ -84,21 +84,21 @@
         if (!targetStats) {
             if (sourceStats.isDirectory()) {
                 // The target directory does not exist, so it should be created.
-                log("mkdir " + targetPath);
-                shell.mkdir("-p", targetFullPath);
+                log('mkdir ' + targetPath);
+                shell.mkdir('-p', targetFullPath);
                 updated = true;
             } else if (sourceStats.isFile()) {
                 // The target file does not exist, so it should be copied from the source.
-                log("copy  " + sourcePath + " " + targetPath + (copyAll ? "" : " (new file)"));
-                shell.cp("-f", sourceFullPath, targetFullPath);
+                log('copy  ' + sourcePath + ' ' + targetPath + (copyAll ? '' : ' (new file)'));
+                shell.cp('-f', sourceFullPath, targetFullPath);
                 updated = true;
             }
         } else if (sourceStats.isFile() && targetStats.isFile()) {
             // The source and target paths both exist and are files.
             if (copyAll) {
                 // The caller specified all files should be copied.
-                log("copy  " + sourcePath + " " + targetPath);
-                shell.cp("-f", sourceFullPath, targetFullPath);
+                log('copy  ' + sourcePath + ' ' + targetPath);
+                shell.cp('-f', sourceFullPath, targetFullPath);
                 updated = true;
             } else {
                 // Copy if the source has been modified since it was copied to the target, or if
@@ -107,8 +107,8 @@
                 // for timestamps lacking sub-second precision in some filesystems.
                 if (sourceStats.mtime.getTime() >= targetStats.mtime.getTime() ||
                         sourceStats.size !== targetStats.size) {
-                    log("copy  " + sourcePath + " " + targetPath + " (updated file)");
-                    shell.cp("-f", sourceFullPath, targetFullPath);
+                    log('copy  ' + sourcePath + ' ' + targetPath + ' (updated file)');
+                    shell.cp('-f', sourceFullPath, targetFullPath);
                     updated = true;
                 }
             }
@@ -116,11 +116,11 @@
     } else if (targetStats) {
         // The target exists but the source is null, so the target should be deleted.
         if (targetStats.isDirectory()) {
-            log("rmdir  " + targetPath + (copyAll ? "" : " (no source)"));
-            shell.rm("-rf", targetFullPath);
+            log('rmdir  ' + targetPath + (copyAll ? '' : ' (no source)'));
+            shell.rm('-rf', targetFullPath);
         } else {
-            log("delete " + targetPath + (copyAll ? "" : " (no source)"));
-            shell.rm("-f", targetFullPath);
+            log('delete ' + targetPath + (copyAll ? '' : ' (no source)'));
+            shell.rm('-f', targetFullPath);
         }
         updated = true;
     }
@@ -132,8 +132,8 @@
  * Helper for updatePath and updatePaths functions. Queries stats for source and target
  * and ensures target directory exists before copying a file.
  */
-function updatePathInternal(sourcePath, targetPath, options, log) {
-    var rootDir = (options && options.rootDir) || "";
+function updatePathInternal (sourcePath, targetPath, options, log) {
+    var rootDir = (options && options.rootDir) || '';
     var targetFullPath = path.join(rootDir, targetPath);
     var targetStats = fs.existsSync(targetFullPath) ? fs.statSync(targetFullPath) : null;
     var sourceStats = null;
@@ -142,7 +142,7 @@
         // A non-null source path was specified. It should exist.
         var sourceFullPath = path.join(rootDir, sourcePath);
         if (!fs.existsSync(sourceFullPath)) {
-            throw new Error("Source path does not exist: " + sourcePath);
+            throw new Error('Source path does not exist: ' + sourcePath);
         }
 
         sourceStats = fs.statSync(sourceFullPath);
@@ -150,7 +150,7 @@
         // Create the target's parent directory if it doesn't exist.
         var parentDir = path.dirname(targetFullPath);
         if (!fs.existsSync(parentDir)) {
-            shell.mkdir("-p", parentDir);
+            shell.mkdir('-p', parentDir);
         }
     }
 
@@ -177,16 +177,16 @@
  * @return {boolean} true if any changes were made, or false if the force flag is not set
  *     and everything was up to date
  */
-function updatePath(sourcePath, targetPath, options, log) {
-    if (sourcePath !== null && typeof sourcePath !== "string") {
-        throw new Error("A source path (or null) is required.");
+function updatePath (sourcePath, targetPath, options, log) {
+    if (sourcePath !== null && typeof sourcePath !== 'string') {
+        throw new Error('A source path (or null) is required.');
     }
 
-    if (!targetPath || typeof targetPath !== "string") {
-        throw new Error("A target path is required.");
+    if (!targetPath || typeof targetPath !== 'string') {
+        throw new Error('A target path is required.');
     }
 
-    log = log || function(message) { };
+    log = log || function (message) { };
 
     return updatePathInternal(sourcePath, targetPath, options, log);
 }
@@ -208,12 +208,12 @@
  * @return {boolean} true if any changes were made, or false if the force flag is not set
  *     and everything was up to date
  */
-function updatePaths(pathMap, options, log) {
-    if (!pathMap || typeof pathMap !== "object" || Array.isArray(pathMap)) {
-        throw new Error("An object mapping from target paths to source paths is required.");
+function updatePaths (pathMap, options, log) {
+    if (!pathMap || typeof pathMap !== 'object' || Array.isArray(pathMap)) {
+        throw new Error('An object mapping from target paths to source paths is required.');
     }
 
-    log = log || function(message) { };
+    log = log || function (message) { };
 
     var updated = false;
 
@@ -255,44 +255,44 @@
  * @return {boolean} true if any changes were made, or false if the force flag is not set
  *     and everything was up to date
  */
-function mergeAndUpdateDir(sourceDirs, targetDir, options, log) {
-    if (sourceDirs && typeof sourceDirs === "string") {
+function mergeAndUpdateDir (sourceDirs, targetDir, options, log) {
+    if (sourceDirs && typeof sourceDirs === 'string') {
         sourceDirs = [ sourceDirs ];
     } else if (!Array.isArray(sourceDirs)) {
-        throw new Error("A source directory path or array of paths is required.");
+        throw new Error('A source directory path or array of paths is required.');
     }
 
-    if (!targetDir || typeof targetDir !== "string") {
-        throw new Error("A target directory path is required.");
+    if (!targetDir || typeof targetDir !== 'string') {
+        throw new Error('A target directory path is required.');
     }
 
-    log = log || function(message) { };
+    log = log || function (message) { };
 
-    var rootDir = (options && options.rootDir) || "";
+    var rootDir = (options && options.rootDir) || '';
 
-    var include = (options && options.include) || [ "**" ];
-    if (typeof include === "string") {
+    var include = (options && options.include) || [ '**' ];
+    if (typeof include === 'string') {
         include = [ include ];
     } else if (!Array.isArray(include)) {
-        throw new Error("Include parameter must be a glob string or array of glob strings.");
+        throw new Error('Include parameter must be a glob string or array of glob strings.');
     }
 
     var exclude = (options && options.exclude) || [];
-    if (typeof exclude === "string") {
+    if (typeof exclude === 'string') {
         exclude = [ exclude ];
     } else if (!Array.isArray(exclude)) {
-        throw new Error("Exclude parameter must be a glob string or array of glob strings.");
+        throw new Error('Exclude parameter must be a glob string or array of glob strings.');
     }
 
     // Scan the files in each of the source directories.
     var sourceMaps = sourceDirs.map(function (sourceDir) {
-            return path.join(rootDir, sourceDir);
-        }).map(function (sourcePath) {
-            if (!fs.existsSync(sourcePath)) {
-                throw new Error("Source directory does not exist: " + sourcePath);
-            }
-            return mapDirectory(rootDir, path.relative(rootDir, sourcePath), include, exclude);
-        });
+        return path.join(rootDir, sourceDir);
+    }).map(function (sourcePath) {
+        if (!fs.existsSync(sourcePath)) {
+            throw new Error('Source directory does not exist: ' + sourcePath);
+        }
+        return mapDirectory(rootDir, path.relative(rootDir, sourcePath), include, exclude);
+    });
 
     // Scan the files in the target directory, if it exists.
     var targetMap = {};
@@ -323,18 +323,18 @@
 /**
  * Creates a dictionary map of all files and directories under a path.
  */
-function mapDirectory(rootDir, subDir, include, exclude) {
-    var dirMap = { "": { subDir: subDir, stats: fs.statSync(path.join(rootDir, subDir)) } };
-    mapSubdirectory(rootDir, subDir, "", include, exclude, dirMap);
+function mapDirectory (rootDir, subDir, include, exclude) {
+    var dirMap = { '': { subDir: subDir, stats: fs.statSync(path.join(rootDir, subDir)) } };
+    mapSubdirectory(rootDir, subDir, '', include, exclude, dirMap);
     return dirMap;
 
-    function mapSubdirectory(rootDir, subDir, relativeDir, include, exclude, dirMap) {
+    function mapSubdirectory (rootDir, subDir, relativeDir, include, exclude, dirMap) {
         var itemMapped = false;
         var items = fs.readdirSync(path.join(rootDir, subDir, relativeDir));
 
-        items.forEach(function(item) {
+        items.forEach(function (item) {
             var relativePath = path.join(relativeDir, item);
-            if(!matchGlobArray(relativePath, exclude)) {
+            if (!matchGlobArray(relativePath, exclude)) {
                 // Stats obtained here (required at least to know where to recurse in directories)
                 // are saved for later, where the modified times may also be used. This minimizes
                 // the number of file I/O operations performed.
@@ -361,9 +361,9 @@
         return itemMapped;
     }
 
-    function matchGlobArray(path, globs) {
-        return globs.some(function(elem) {
-            return minimatch(path, elem, {dot:true});
+    function matchGlobArray (path, globs) {
+        return globs.some(function (elem) {
+            return minimatch(path, elem, {dot: true});
         });
     }
 }
@@ -372,13 +372,13 @@
  * Merges together multiple source maps and a target map into a single mapping from
  * relative paths to objects with target and source paths and stats.
  */
-function mergePathMaps(sourceMaps, targetMap, targetDir) {
+function mergePathMaps (sourceMaps, targetMap, targetDir) {
     // Merge multiple source maps together, along with target path info.
     // Entries in later source maps override those in earlier source maps.
     // Target stats will be filled in below for targets that exist.
     var pathMap = {};
     sourceMaps.forEach(function (sourceMap) {
-        Object.keys(sourceMap).forEach(function(sourceSubPath){
+        Object.keys(sourceMap).forEach(function (sourceSubPath) {
             var sourceEntry = sourceMap[sourceSubPath];
             pathMap[sourceSubPath] = {
                 targetPath: path.join(targetDir, sourceSubPath),
@@ -391,7 +391,7 @@
 
     // Fill in target stats for targets that exist, and create entries
     // for targets that don't have any corresponding sources.
-    Object.keys(targetMap).forEach(function(subPath){
+    Object.keys(targetMap).forEach(function (subPath) {
         var entry = pathMap[subPath];
         if (entry) {
             entry.targetStats = targetMap[subPath].stats;
@@ -413,4 +413,3 @@
     updatePaths: updatePaths,
     mergeAndUpdateDir: mergeAndUpdateDir
 };
-
diff --git a/node_modules/cordova-common/src/PlatformJson.js b/node_modules/cordova-common/src/PlatformJson.js
index ab94b5f..7eaf1a2 100644
--- a/node_modules/cordova-common/src/PlatformJson.js
+++ b/node_modules/cordova-common/src/PlatformJson.js
@@ -13,7 +13,6 @@
  * under the License.
  *
 */
-/* jshint sub:true */
 
 var fs = require('fs');
 var path = require('path');
@@ -22,13 +21,13 @@
 var pluginMappernto = require('cordova-registry-mapper').newToOld;
 var pluginMapperotn = require('cordova-registry-mapper').oldToNew;
 
-function PlatformJson(filePath, platform, root) {
+function PlatformJson (filePath, platform, root) {
     this.filePath = filePath;
     this.platform = platform;
     this.root = fix_munge(root || {});
 }
 
-PlatformJson.load = function(plugins_dir, platform) {
+PlatformJson.load = function (plugins_dir, platform) {
     var filePath = path.join(plugins_dir, platform + '.json');
     var root = null;
     if (fs.existsSync(filePath)) {
@@ -37,9 +36,9 @@
     return new PlatformJson(filePath, platform, root);
 };
 
-PlatformJson.prototype.save = function() {
+PlatformJson.prototype.save = function () {
     shelljs.mkdir('-p', path.dirname(this.filePath));
-    fs.writeFileSync(this.filePath, JSON.stringify(this.root, null, 4), 'utf-8');
+    fs.writeFileSync(this.filePath, JSON.stringify(this.root, null, 2), 'utf-8');
 };
 
 /**
@@ -49,7 +48,7 @@
  * @param  {String} pluginId A plugin id to check for.
  * @return {Boolean} true if plugin installed as top-level, otherwise false.
  */
-PlatformJson.prototype.isPluginTopLevel = function(pluginId) {
+PlatformJson.prototype.isPluginTopLevel = function (pluginId) {
     var installedPlugins = this.root.installed_plugins;
     return installedPlugins[pluginId] ||
         installedPlugins[pluginMappernto[pluginId]] ||
@@ -63,7 +62,7 @@
  * @param  {String} pluginId A plugin id to check for.
  * @return {Boolean} true if plugin installed as a dependency, otherwise false.
  */
-PlatformJson.prototype.isPluginDependent = function(pluginId) {
+PlatformJson.prototype.isPluginDependent = function (pluginId) {
     var dependentPlugins = this.root.dependent_plugins;
     return dependentPlugins[pluginId] ||
         dependentPlugins[pluginMappernto[pluginId]] ||
@@ -76,12 +75,12 @@
  * @param  {String} pluginId A plugin id to check for.
  * @return {Boolean} true if plugin installed, otherwise false.
  */
-PlatformJson.prototype.isPluginInstalled = function(pluginId) {
+PlatformJson.prototype.isPluginInstalled = function (pluginId) {
     return this.isPluginTopLevel(pluginId) ||
         this.isPluginDependent(pluginId);
 };
 
-PlatformJson.prototype.addPlugin = function(pluginId, variables, isTopLevel) {
+PlatformJson.prototype.addPlugin = function (pluginId, variables, isTopLevel) {
     var pluginsList = isTopLevel ?
         this.root.installed_plugins :
         this.root.dependent_plugins;
@@ -107,13 +106,13 @@
     });
 
     var modulesToInstall = pluginInfo.getJsModules(this.platform)
-    .map(function (module) {
-        return new ModuleMetadata(pluginInfo.id, module);
-    })
-    .filter(function (metadata) {
-        // Filter out modules which are already added to metadata
-        return installedPaths.indexOf(metadata.file) === -1;
-    });
+        .map(function (module) {
+            return new ModuleMetadata(pluginInfo.id, module);
+        })
+        .filter(function (metadata) {
+            // Filter out modules which are already added to metadata
+            return installedPaths.indexOf(metadata.file) === -1;
+        });
 
     this.root.modules = installedModules.concat(modulesToInstall);
 
@@ -123,7 +122,7 @@
     return this;
 };
 
-PlatformJson.prototype.removePlugin = function(pluginId, isTopLevel) {
+PlatformJson.prototype.removePlugin = function (pluginId, isTopLevel) {
     var pluginsList = isTopLevel ?
         this.root.installed_plugins :
         this.root.dependent_plugins;
@@ -144,16 +143,16 @@
  */
 PlatformJson.prototype.removePluginMetadata = function (pluginInfo) {
     var modulesToRemove = pluginInfo.getJsModules(this.platform)
-    .map(function (jsModule) {
-        return  ['plugins', pluginInfo.id, jsModule.src].join('/');
-    });
+        .map(function (jsModule) {
+            return ['plugins', pluginInfo.id, jsModule.src].join('/');
+        });
 
     var installedModules = this.root.modules || [];
     this.root.modules = installedModules
-    .filter(function (installedModule) {
-        // Leave only those metadatas which 'file' is not in removed modules
-        return (modulesToRemove.indexOf(installedModule.file) === -1);
-    });
+        .filter(function (installedModule) {
+            // Leave only those metadatas which 'file' is not in removed modules
+            return (modulesToRemove.indexOf(installedModule.file) === -1);
+        });
 
     if (this.root.plugin_metadata) {
         delete this.root.plugin_metadata[pluginInfo.id];
@@ -162,12 +161,12 @@
     return this;
 };
 
-PlatformJson.prototype.addInstalledPluginToPrepareQueue = function(pluginDirName, vars, is_top_level, force) {
-    this.root.prepare_queue.installed.push({'plugin':pluginDirName, 'vars':vars, 'topLevel':is_top_level, 'force':force});
+PlatformJson.prototype.addInstalledPluginToPrepareQueue = function (pluginDirName, vars, is_top_level, force) {
+    this.root.prepare_queue.installed.push({'plugin': pluginDirName, 'vars': vars, 'topLevel': is_top_level, 'force': force});
 };
 
-PlatformJson.prototype.addUninstalledPluginToPrepareQueue = function(pluginId, is_top_level) {
-    this.root.prepare_queue.uninstalled.push({'plugin':pluginId, 'id':pluginId, 'topLevel':is_top_level});
+PlatformJson.prototype.addUninstalledPluginToPrepareQueue = function (pluginId, is_top_level) {
+    this.root.prepare_queue.uninstalled.push({'plugin': pluginId, 'id': pluginId, 'topLevel': is_top_level});
 };
 
 /**
@@ -177,7 +176,7 @@
  * @param  {String} pluginId A plugin id to make top-level.
  * @return {PlatformJson} PlatformJson instance.
  */
-PlatformJson.prototype.makeTopLevel = function(pluginId) {
+PlatformJson.prototype.makeTopLevel = function (pluginId) {
     var plugin = this.root.dependent_plugins[pluginId];
     if (plugin) {
         delete this.root.dependent_plugins[pluginId];
@@ -195,10 +194,10 @@
 PlatformJson.prototype.generateMetadata = function () {
     return [
         'cordova.define(\'cordova/plugin_list\', function(require, exports, module) {',
-        'module.exports = ' + JSON.stringify(this.root.modules, null, 4) + ';',
+        'module.exports = ' + JSON.stringify(this.root.modules, null, 2) + ';',
         'module.exports.metadata = ',
         '// TOP OF METADATA',
-        JSON.stringify(this.root.plugin_metadata, null, 4) + ';',
+        JSON.stringify(this.root.plugin_metadata, null, 2) + ';',
         '// BOTTOM OF METADATA',
         '});' // Close cordova.define.
     ].join('\n');
@@ -220,8 +219,8 @@
 };
 
 // convert a munge from the old format ([file][parent][xml] = count) to the current one
-function fix_munge(root) {
-    root.prepare_queue = root.prepare_queue || {installed:[], uninstalled:[]};
+function fix_munge (root) {
+    root.prepare_queue = root.prepare_queue || {installed: [], uninstalled: []};
     root.config_munge = root.config_munge || {files: {}};
     root.installed_plugins = root.installed_plugins || {};
     root.dependent_plugins = root.dependent_plugins || {};
@@ -260,15 +259,15 @@
     if (!pluginId) throw new TypeError('pluginId argument must be a valid plugin id');
     if (!jsModule.src && !jsModule.name) throw new TypeError('jsModule argument must contain src or/and name properties');
 
-    this.id  = pluginId + '.' + ( jsModule.name || jsModule.src.match(/([^\/]+)\.js/)[1] );
+    this.id = pluginId + '.' + (jsModule.name || jsModule.src.match(/([^\/]+)\.js/)[1]); /* eslint no-useless-escape: 0 */
     this.file = ['plugins', pluginId, jsModule.src].join('/');
     this.pluginId = pluginId;
 
     if (jsModule.clobbers && jsModule.clobbers.length > 0) {
-        this.clobbers = jsModule.clobbers.map(function(o) { return o.target; });
+        this.clobbers = jsModule.clobbers.map(function (o) { return o.target; });
     }
     if (jsModule.merges && jsModule.merges.length > 0) {
-        this.merges = jsModule.merges.map(function(o) { return o.target; });
+        this.merges = jsModule.merges.map(function (o) { return o.target; });
     }
     if (jsModule.runs) {
         this.runs = true;
diff --git a/node_modules/cordova-common/src/PluginInfo/PluginInfo.js b/node_modules/cordova-common/src/PluginInfo/PluginInfo.js
index 4817470..7e9754d 100644
--- a/node_modules/cordova-common/src/PluginInfo/PluginInfo.js
+++ b/node_modules/cordova-common/src/PluginInfo/PluginInfo.js
@@ -17,8 +17,6 @@
     under the License.
 */
 
-/* jshint sub:true, laxcomma:true, laxbreak:true */
-
 /*
 A class for holidng the information currently stored in plugin.xml
 It should also be able to answer questions like whether the plugin
@@ -27,14 +25,12 @@
 TODO (kamrik): refactor this to not use sync functions and return promises.
 */
 
+var path = require('path');
+var fs = require('fs');
+var xml_helpers = require('../util/xml-helpers');
+var CordovaError = require('../CordovaError/CordovaError');
 
-var path = require('path')
-  , fs = require('fs')
-  , xml_helpers = require('../util/xml-helpers')
-  , CordovaError = require('../CordovaError/CordovaError')
-  ;
-
-function PluginInfo(dirname) {
+function PluginInfo (dirname) {
     var self = this;
 
     // METHODS
@@ -45,15 +41,15 @@
     // Used to require a variable to be specified via --variable when installing the plugin.
     // returns { key : default | null}
     self.getPreferences = getPreferences;
-    function getPreferences(platform) {
+    function getPreferences (platform) {
         return _getTags(self._et, 'preference', platform, _parsePreference)
-        .reduce(function (preferences, pref) {
-            preferences[pref.preference] = pref.default;
-            return preferences;
-        }, {});
+            .reduce(function (preferences, pref) {
+                preferences[pref.preference] = pref.default;
+                return preferences;
+            }, {});
     }
 
-    function _parsePreference(prefTag) {
+    function _parsePreference (prefTag) {
         var name = prefTag.attrib.name.toUpperCase();
         var def = prefTag.attrib.default || null;
         return {preference: name, default: def};
@@ -61,16 +57,16 @@
 
     // <asset>
     self.getAssets = getAssets;
-    function getAssets(platform) {
+    function getAssets (platform) {
         var assets = _getTags(self._et, 'asset', platform, _parseAsset);
         return assets;
     }
 
-    function _parseAsset(tag) {
+    function _parseAsset (tag) {
         var src = tag.attrib.src;
         var target = tag.attrib.target;
 
-        if ( !src || !target) {
+        if (!src || !target) {
             var msg =
                 'Malformed <asset> tag. Both "src" and "target" attributes'
                 + 'must be specified in\n'
@@ -87,7 +83,6 @@
         return asset;
     }
 
-
     // <dependency>
     // Example:
     // <dependency id="com.plugin.id"
@@ -95,28 +90,28 @@
     //     commit="428931ada3891801"
     //     subdir="some/path/here" />
     self.getDependencies = getDependencies;
-    function getDependencies(platform) {
+    function getDependencies (platform) {
         var deps = _getTags(
-                self._et,
-                'dependency',
-                platform,
-                _parseDependency
+            self._et,
+            'dependency',
+            platform,
+            _parseDependency
         );
         return deps;
     }
 
-    function _parseDependency(tag) {
+    function _parseDependency (tag) {
         var dep =
-            { id : tag.attrib.id
-            , version: tag.attrib.version || ''
-            , url : tag.attrib.url || ''
-            , subdir : tag.attrib.subdir || ''
-            , commit : tag.attrib.commit
+            { id: tag.attrib.id,
+                version: tag.attrib.version || '',
+                url: tag.attrib.url || '',
+                subdir: tag.attrib.subdir || '',
+                commit: tag.attrib.commit
             };
 
         dep.git_ref = dep.commit;
 
-        if ( !dep.id ) {
+        if (!dep.id) {
             var msg =
                 '<dependency> tag is missing id attribute in '
                 + self.filepath
@@ -126,52 +121,51 @@
         return dep;
     }
 
-
     // <config-file> tag
     self.getConfigFiles = getConfigFiles;
-    function getConfigFiles(platform) {
+    function getConfigFiles (platform) {
         var configFiles = _getTags(self._et, 'config-file', platform, _parseConfigFile);
         return configFiles;
     }
 
-    function _parseConfigFile(tag) {
+    function _parseConfigFile (tag) {
         var configFile =
-            { target : tag.attrib['target']
-            , parent : tag.attrib['parent']
-            , after : tag.attrib['after']
-            , xmls : tag.getchildren()
-            // To support demuxing via versions
-            , versions : tag.attrib['versions']
-            , deviceTarget: tag.attrib['device-target']
+            { target: tag.attrib['target'],
+                parent: tag.attrib['parent'],
+                after: tag.attrib['after'],
+                xmls: tag.getchildren(),
+                // To support demuxing via versions
+                versions: tag.attrib['versions'],
+                deviceTarget: tag.attrib['device-target']
             };
         return configFile;
     }
 
     self.getEditConfigs = getEditConfigs;
-    function getEditConfigs(platform) {
+    function getEditConfigs (platform) {
         var editConfigs = _getTags(self._et, 'edit-config', platform, _parseEditConfigs);
         return editConfigs;
     }
 
-    function _parseEditConfigs(tag) {
+    function _parseEditConfigs (tag) {
         var editConfig =
-        { file : tag.attrib['file']
-        , target : tag.attrib['target']
-        , mode : tag.attrib['mode']
-        , xmls : tag.getchildren()
-        };
+            { file: tag.attrib['file'],
+                target: tag.attrib['target'],
+                mode: tag.attrib['mode'],
+                xmls: tag.getchildren()
+            };
         return editConfig;
     }
 
     // <info> tags, both global and within a <platform>
     // TODO (kamrik): Do we ever use <info> under <platform>? Example wanted.
     self.getInfo = getInfo;
-    function getInfo(platform) {
+    function getInfo (platform) {
         var infos = _getTags(
-                self._et,
-                'info',
-                platform,
-                function(elem) { return elem.text; }
+            self._et,
+            'info',
+            platform,
+            function (elem) { return elem.text; }
         );
         // Filter out any undefined or empty strings.
         infos = infos.filter(Boolean);
@@ -183,12 +177,12 @@
     // <source-file src="src/ios/someLib.a" framework="true" />
     // <source-file src="src/ios/someLib.a" compiler-flags="-fno-objc-arc" />
     self.getSourceFiles = getSourceFiles;
-    function getSourceFiles(platform) {
+    function getSourceFiles (platform) {
         var sourceFiles = _getTagsInPlatform(self._et, 'source-file', platform, _parseSourceFile);
         return sourceFiles;
     }
 
-    function _parseSourceFile(tag) {
+    function _parseSourceFile (tag) {
         return {
             itemType: 'source-file',
             src: tag.attrib.src,
@@ -203,8 +197,8 @@
     // Example:
     // <header-file src="CDVFoo.h" />
     self.getHeaderFiles = getHeaderFiles;
-    function getHeaderFiles(platform) {
-        var headerFiles = _getTagsInPlatform(self._et, 'header-file', platform, function(tag) {
+    function getHeaderFiles (platform) {
+        var headerFiles = _getTagsInPlatform(self._et, 'header-file', platform, function (tag) {
             return {
                 itemType: 'header-file',
                 src: tag.attrib.src,
@@ -218,8 +212,8 @@
     // Example:
     // <resource-file src="FooPluginStrings.xml" target="res/values/FooPluginStrings.xml" device-target="win" arch="x86" versions="&gt;=8.1" />
     self.getResourceFiles = getResourceFiles;
-    function getResourceFiles(platform) {
-        var resourceFiles = _getTagsInPlatform(self._et, 'resource-file', platform, function(tag) {
+    function getResourceFiles (platform) {
+        var resourceFiles = _getTagsInPlatform(self._et, 'resource-file', platform, function (tag) {
             return {
                 itemType: 'resource-file',
                 src: tag.attrib.src,
@@ -237,8 +231,8 @@
     // Example:
     // <lib-file src="src/BlackBerry10/native/device/libfoo.so" arch="device" />
     self.getLibFiles = getLibFiles;
-    function getLibFiles(platform) {
-        var libFiles = _getTagsInPlatform(self._et, 'lib-file', platform, function(tag) {
+    function getLibFiles (platform) {
+        var libFiles = _getTagsInPlatform(self._et, 'lib-file', platform, function (tag) {
             return {
                 itemType: 'lib-file',
                 src: tag.attrib.src,
@@ -255,16 +249,16 @@
     // Example:
     // <hook type="before_build" src="scripts/beforeBuild.js" />
     self.getHookScripts = getHookScripts;
-    function getHookScripts(hook, platforms) {
-        var scriptElements =  self._et.findall('./hook');
+    function getHookScripts (hook, platforms) {
+        var scriptElements = self._et.findall('./hook');
 
-        if(platforms) {
+        if (platforms) {
             platforms.forEach(function (platform) {
                 scriptElements = scriptElements.concat(self._et.findall('./platform[@name="' + platform + '"]/hook'));
             });
         }
 
-        function filterScriptByHookType(el) {
+        function filterScriptByHookType (el) {
             return el.attrib.src && el.attrib.type && el.attrib.type.toLowerCase() === hook;
         }
 
@@ -272,26 +266,26 @@
     }
 
     self.getJsModules = getJsModules;
-    function getJsModules(platform) {
+    function getJsModules (platform) {
         var modules = _getTags(self._et, 'js-module', platform, _parseJsModule);
         return modules;
     }
 
-    function _parseJsModule(tag) {
+    function _parseJsModule (tag) {
         var ret = {
             itemType: 'js-module',
             name: tag.attrib.name,
             src: tag.attrib.src,
-            clobbers: tag.findall('clobbers').map(function(tag) { return { target: tag.attrib.target }; }),
-            merges: tag.findall('merges').map(function(tag) { return { target: tag.attrib.target }; }),
+            clobbers: tag.findall('clobbers').map(function (tag) { return { target: tag.attrib.target }; }),
+            merges: tag.findall('merges').map(function (tag) { return { target: tag.attrib.target }; }),
             runs: tag.findall('runs').length > 0
         };
 
         return ret;
     }
 
-    self.getEngines = function() {
-        return self._et.findall('engines/engine').map(function(n) {
+    self.getEngines = function () {
+        return self._et.findall('engines/engine').map(function (n) {
             return {
                 name: n.attrib.name,
                 version: n.attrib.version,
@@ -301,26 +295,45 @@
         });
     };
 
-    self.getPlatforms = function() {
-        return self._et.findall('platform').map(function(n) {
+    self.getPlatforms = function () {
+        return self._et.findall('platform').map(function (n) {
             return { name: n.attrib.name };
         });
     };
 
-    self.getPlatformsArray = function() {
-        return self._et.findall('platform').map(function(n) {
+    self.getPlatformsArray = function () {
+        return self._et.findall('platform').map(function (n) {
             return n.attrib.name;
         });
     };
-    self.getFrameworks = function(platform) {
-        return _getTags(self._et, 'framework', platform, function(el) {
+
+    self.getFrameworks = function (platform, options) {
+        return _getTags(self._et, 'framework', platform, function (el) {
+            var src = el.attrib.src;
+            if (options) {
+                var vars = options.cli_variables || {};
+
+                if (Object.keys(vars).length === 0) {
+                    // get variable defaults from plugin.xml for removal
+                    vars = self.getPreferences(platform);
+                }
+                var regExp;
+                // Iterate over plugin variables.
+                // Replace them in framework src if they exist
+                Object.keys(vars).forEach(function (name) {
+                    if (vars[name]) {
+                        regExp = new RegExp('\\$' + name, 'g');
+                        src = src.replace(regExp, vars[name]);
+                    }
+                });
+            }
             var ret = {
                 itemType: 'framework',
                 type: el.attrib.type,
                 parent: el.attrib.parent,
                 custom: isStrTrue(el.attrib.custom),
                 embed: isStrTrue(el.attrib.embed),
-                src: el.attrib.src,
+                src: src,
                 spec: el.attrib.spec,
                 weak: isStrTrue(el.attrib.weak),
                 versions: el.attrib.versions,
@@ -334,22 +347,21 @@
     };
 
     self.getFilesAndFrameworks = getFilesAndFrameworks;
-    function getFilesAndFrameworks(platform) {
+    function getFilesAndFrameworks (platform, options) {
         // Please avoid changing the order of the calls below, files will be
         // installed in this order.
         var items = [].concat(
             self.getSourceFiles(platform),
             self.getHeaderFiles(platform),
             self.getResourceFiles(platform),
-            self.getFrameworks(platform),
+            self.getFrameworks(platform, options),
             self.getLibFiles(platform)
         );
         return items;
     }
-    ///// End of PluginInfo methods /////
+    /// // End of PluginInfo methods /////
 
-
-    ///// PluginInfo Constructor logic  /////
+    /// // PluginInfo Constructor logic  /////
     self.filepath = path.join(dirname, 'plugin.xml');
     if (!fs.existsSync(self.filepath)) {
         throw new CordovaError('Cannot find plugin.xml for plugin "' + path.basename(dirname) + '". Please try adding it again.');
@@ -370,18 +382,18 @@
     self.keywords = pelem.findtext('keywords');
     self.info = pelem.findtext('info');
     if (self.keywords) {
-        self.keywords = self.keywords.split(',').map( function(s) { return s.trim(); } );
+        self.keywords = self.keywords.split(',').map(function (s) { return s.trim(); });
     }
     self.getKeywordsAndPlatforms = function () {
         var ret = self.keywords || [];
         return ret.concat('ecosystem:cordova').concat(addCordova(self.getPlatformsArray()));
     };
-}  // End of PluginInfo constructor.
+} // End of PluginInfo constructor.
 
 // Helper function used to prefix every element of an array with cordova-
 // Useful when we want to modify platforms to be cordova-platform
-function addCordova(someArray) {
-    var newArray = someArray.map(function(element) {
+function addCordova (someArray) {
+    var newArray = someArray.map(function (element) {
         return 'cordova-' + element;
     });
     return newArray;
@@ -391,37 +403,37 @@
 // Get all elements of a given name. Both in root and in platform sections
 // for the given platform. If transform is given and is a function, it is
 // applied to each element.
-function _getTags(pelem, tag, platform, transform) {
+function _getTags (pelem, tag, platform, transform) {
     var platformTag = pelem.find('./platform[@name="' + platform + '"]');
     var tagsInRoot = pelem.findall(tag);
     tagsInRoot = tagsInRoot || [];
     var tagsInPlatform = platformTag ? platformTag.findall(tag) : [];
     var tags = tagsInRoot.concat(tagsInPlatform);
-    if ( typeof transform === 'function' ) {
+    if (typeof transform === 'function') {
         tags = tags.map(transform);
     }
     return tags;
 }
 
 // Same as _getTags() but only looks inside a platform section.
-function _getTagsInPlatform(pelem, tag, platform, transform) {
+function _getTagsInPlatform (pelem, tag, platform, transform) {
     var platformTag = pelem.find('./platform[@name="' + platform + '"]');
     var tags = platformTag ? platformTag.findall(tag) : [];
-    if ( typeof transform === 'function' ) {
+    if (typeof transform === 'function') {
         tags = tags.map(transform);
     }
     return tags;
 }
 
 // Check if x is a string 'true'.
-function isStrTrue(x) {
-    return String(x).toLowerCase() == 'true';
+function isStrTrue (x) {
+    return String(x).toLowerCase() === 'true';
 }
 
 module.exports = PluginInfo;
 // Backwards compat:
 PluginInfo.PluginInfo = PluginInfo;
-PluginInfo.loadPluginsDir = function(dir) {
+PluginInfo.loadPluginsDir = function (dir) {
     var PluginInfoProvider = require('./PluginInfoProvider');
     return new PluginInfoProvider().getAllWithinSearchPath(dir);
 };
diff --git a/node_modules/cordova-common/src/PluginInfo/PluginInfoProvider.js b/node_modules/cordova-common/src/PluginInfo/PluginInfoProvider.js
index 6240119..5d3f329 100644
--- a/node_modules/cordova-common/src/PluginInfo/PluginInfoProvider.js
+++ b/node_modules/cordova-common/src/PluginInfo/PluginInfoProvider.js
@@ -24,12 +24,12 @@
 var PluginInfo = require('./PluginInfo');
 var events = require('../events');
 
-function PluginInfoProvider() {
+function PluginInfoProvider () {
     this._cache = {};
     this._getAllCache = {};
 }
 
-PluginInfoProvider.prototype.get = function(dirName) {
+PluginInfoProvider.prototype.get = function (dirName) {
     var absPath = path.resolve(dirName);
     if (!this._cache[absPath]) {
         this._cache[absPath] = new PluginInfo(dirName);
@@ -39,7 +39,7 @@
 
 // Normally you don't need to put() entries, but it's used
 // when copying plugins, and in unit tests.
-PluginInfoProvider.prototype.put = function(pluginInfo) {
+PluginInfoProvider.prototype.put = function (pluginInfo) {
     var absPath = path.resolve(pluginInfo.dir);
     this._cache[absPath] = pluginInfo;
 };
@@ -48,7 +48,7 @@
 // Given a dir containing multiple plugins, create a PluginInfo object for
 // each of them and return as array.
 // Should load them all in parallel and return a promise, but not yet.
-PluginInfoProvider.prototype.getAllWithinSearchPath = function(dirName) {
+PluginInfoProvider.prototype.getAllWithinSearchPath = function (dirName) {
     var absPath = path.resolve(dirName);
     if (!this._getAllCache[absPath]) {
         this._getAllCache[absPath] = getAllHelper(absPath, this);
@@ -56,8 +56,8 @@
     return this._getAllCache[absPath];
 };
 
-function getAllHelper(absPath, provider) {
-    if (!fs.existsSync(absPath)){
+function getAllHelper (absPath, provider) {
+    if (!fs.existsSync(absPath)) {
         return [];
     }
     // If dir itself is a plugin, return it in an array with one element.
@@ -66,7 +66,7 @@
     }
     var subdirs = fs.readdirSync(absPath);
     var plugins = [];
-    subdirs.forEach(function(subdir) {
+    subdirs.forEach(function (subdir) {
         var d = path.join(absPath, subdir);
         if (fs.existsSync(path.join(d, 'plugin.xml'))) {
             try {
diff --git a/node_modules/cordova-common/src/PluginManager.js b/node_modules/cordova-common/src/PluginManager.js
index e8968f1..0097db4 100644
--- a/node_modules/cordova-common/src/PluginManager.js
+++ b/node_modules/cordova-common/src/PluginManager.js
@@ -36,7 +36,7 @@
  * @param {Object} locations - Platform files and directories
  * @param {IDEProject} ideProject The IDE project to add/remove plugin changes to/from
  */
-function PluginManager(platform, locations, ideProject) {
+function PluginManager (platform, locations, ideProject) {
     this.platform = platform;
     this.locations = locations;
     this.project = ideProject;
@@ -45,7 +45,6 @@
     this.munger = new PlatformMunger(platform, locations.root, platformJson, new PluginInfoProvider());
 }
 
-
 /**
  * @constructs PluginManager
  * A convenience shortcut to new PluginManager(...)
@@ -55,7 +54,7 @@
  * @param {IDEProject} ideProject The IDE project to add/remove plugin changes to/from
  * @returns new PluginManager instance
  */
-PluginManager.get = function(platform, locations, ideProject) {
+PluginManager.get = function (platform, locations, ideProject) {
     return new PluginManager(platform, locations, ideProject);
 };
 
@@ -82,11 +81,9 @@
  * @returns {Promise} Returns a Q promise, either resolved in case of success, rejected otherwise.
  */
 PluginManager.prototype.doOperation = function (operation, plugin, options) {
-    if (operation !== PluginManager.INSTALL && operation !== PluginManager.UNINSTALL)
-        return Q.reject(new CordovaError('The parameter is incorrect. The opeation must be either "add" or "remove"'));
+    if (operation !== PluginManager.INSTALL && operation !== PluginManager.UNINSTALL) { return Q.reject(new CordovaError('The parameter is incorrect. The opeation must be either "add" or "remove"')); }
 
-    if (!plugin || plugin.constructor.name !== 'PluginInfo')
-        return Q.reject(new CordovaError('The parameter is incorrect. The first parameter should be a PluginInfo instance'));
+    if (!plugin || plugin.constructor.name !== 'PluginInfo') { return Q.reject(new CordovaError('The parameter is incorrect. The first parameter should be a PluginInfo instance')); }
 
     // Set default to empty object to play safe when accesing properties
     options = options || {};
@@ -95,52 +92,52 @@
     var actions = new ActionStack();
 
     // gather all files need to be handled during operation ...
-    plugin.getFilesAndFrameworks(this.platform)
+    plugin.getFilesAndFrameworks(this.platform, options)
         .concat(plugin.getAssets(this.platform))
         .concat(plugin.getJsModules(this.platform))
-    // ... put them into stack ...
-    .forEach(function(item) {
-        var installer = self.project.getInstaller(item.itemType);
-        var uninstaller = self.project.getUninstaller(item.itemType);
-        var actionArgs = [item, plugin, self.project, options];
+        // ... put them into stack ...
+        .forEach(function (item) {
+            var installer = self.project.getInstaller(item.itemType);
+            var uninstaller = self.project.getUninstaller(item.itemType);
+            var actionArgs = [item, plugin, self.project, options];
 
-        var action;
-        if (operation === PluginManager.INSTALL) {
-            action = actions.createAction.apply(actions, [installer, actionArgs, uninstaller, actionArgs]);
-        } else /* op === PluginManager.UNINSTALL */{
-            action = actions.createAction.apply(actions, [uninstaller, actionArgs, installer, actionArgs]);
-        }
-        actions.push(action);
-    });
+            var action;
+            if (operation === PluginManager.INSTALL) {
+                action = actions.createAction.apply(actions, [installer, actionArgs, uninstaller, actionArgs]); /* eslint no-useless-call: 0 */
+            } else /* op === PluginManager.UNINSTALL */{
+                action = actions.createAction.apply(actions, [uninstaller, actionArgs, installer, actionArgs]); /* eslint no-useless-call: 0 */
+            }
+            actions.push(action);
+        });
 
     // ... and run through the action stack
     return actions.process(this.platform)
-    .then(function () {
-        if (self.project.write) {
-            self.project.write();
-        }
+        .then(function () {
+            if (self.project.write) {
+                self.project.write();
+            }
 
-        if (operation === PluginManager.INSTALL) {
-            // Ignore passed `is_top_level` option since platform itself doesn't know
-            // anything about managing dependencies - it's responsibility of caller.
-            self.munger.add_plugin_changes(plugin, options.variables, /*is_top_level=*/true, /*should_increment=*/true, options.force);
-            self.munger.platformJson.addPluginMetadata(plugin);
-        } else {
-            self.munger.remove_plugin_changes(plugin, /*is_top_level=*/true);
-            self.munger.platformJson.removePluginMetadata(plugin);
-        }
+            if (operation === PluginManager.INSTALL) {
+                // Ignore passed `is_top_level` option since platform itself doesn't know
+                // anything about managing dependencies - it's responsibility of caller.
+                self.munger.add_plugin_changes(plugin, options.variables, /* is_top_level= */true, /* should_increment= */true, options.force);
+                self.munger.platformJson.addPluginMetadata(plugin);
+            } else {
+                self.munger.remove_plugin_changes(plugin, /* is_top_level= */true);
+                self.munger.platformJson.removePluginMetadata(plugin);
+            }
 
-        // Save everything (munge and plugin/modules metadata)
-        self.munger.save_all();
+            // Save everything (munge and plugin/modules metadata)
+            self.munger.save_all();
 
-        var metadata = self.munger.platformJson.generateMetadata();
-        fs.writeFileSync(path.join(self.locations.www, 'cordova_plugins.js'), metadata, 'utf-8');
+            var metadata = self.munger.platformJson.generateMetadata();
+            fs.writeFileSync(path.join(self.locations.www, 'cordova_plugins.js'), metadata, 'utf-8');
 
-        // CB-11022 save plugin metadata to both www and platform_www if options.usePlatformWww is specified
-        if (options.usePlatformWww) {
-            fs.writeFileSync(path.join(self.locations.platformWww, 'cordova_plugins.js'), metadata, 'utf-8');
-        }
-    });
+            // CB-11022 save plugin metadata to both www and platform_www if options.usePlatformWww is specified
+            if (options.usePlatformWww) {
+                fs.writeFileSync(path.join(self.locations.platformWww, 'cordova_plugins.js'), metadata, 'utf-8');
+            }
+        });
 };
 
 PluginManager.prototype.addPlugin = function (plugin, installOptions) {
diff --git a/node_modules/cordova-common/src/events.js b/node_modules/cordova-common/src/events.js
index 3080416..7038643 100644
--- a/node_modules/cordova-common/src/events.js
+++ b/node_modules/cordova-common/src/events.js
@@ -40,8 +40,7 @@
         return;
     }
 
-    if (!(eventEmitter instanceof EventEmitter))
-        throw new Error('Cordova events can be redirected to another EventEmitter instance only');
+    if (!(eventEmitter instanceof EventEmitter)) { throw new Error('Cordova events can be redirected to another EventEmitter instance only'); }
 
     // CB-10940 Skipping forwarding to self to avoid infinite recursion.
     // This is the case when the modules are npm-linked.
diff --git a/node_modules/cordova-common/src/superspawn.js b/node_modules/cordova-common/src/superspawn.js
index 96ec09d..424934e 100644
--- a/node_modules/cordova-common/src/superspawn.js
+++ b/node_modules/cordova-common/src/superspawn.js
@@ -24,12 +24,12 @@
 var Q = require('q');
 var shell = require('shelljs');
 var events = require('./events');
-var iswin32 = process.platform == 'win32';
+var iswin32 = process.platform === 'win32';
 
 // On Windows, spawn() for batch files requires absolute path & having the extension.
-function resolveWindowsExe(cmd) {
+function resolveWindowsExe (cmd) {
     var winExtensions = ['.exe', '.bat', '.cmd', '.js', '.vbs'];
-    function isValidExe(c) {
+    function isValidExe (c) {
         return winExtensions.indexOf(path.extname(c)) !== -1 && fs.existsSync(c);
     }
     if (isValidExe(cmd)) {
@@ -37,7 +37,7 @@
     }
     cmd = shell.which(cmd) || cmd;
     if (!isValidExe(cmd)) {
-        winExtensions.some(function(ext) {
+        winExtensions.some(function (ext) {
             if (fs.existsSync(cmd + ext)) {
                 cmd = cmd + ext;
                 return true;
@@ -47,7 +47,7 @@
     return cmd;
 }
 
-function maybeQuote(a) {
+function maybeQuote (a) {
     if (/^[^"].*[ &].*[^"]/.test(a)) return '"' + a + '"';
     return a;
 }
@@ -85,7 +85,7 @@
  *       'stderr': ...
  *   }
  */
-exports.spawn = function(cmd, args, opts) {
+exports.spawn = function (cmd, args, opts) {
     args = args || [];
     opts = opts || {};
     var spawnOpts = {};
@@ -95,7 +95,7 @@
         cmd = resolveWindowsExe(cmd);
         // If we couldn't find the file, likely we'll end up failing,
         // but for things like "del", cmd will do the trick.
-        if (path.extname(cmd) != '.exe') {
+        if (path.extname(cmd) !== '.exe') {
             var cmdArgs = '"' + [cmd].concat(args).map(maybeQuote).join(' ') + '"';
             // We need to use /s to ensure that spaces are parsed properly with cmd spawned content
             args = [['/s', '/c', cmdArgs].join(' ')];
@@ -137,7 +137,7 @@
 
     if (child.stdout) {
         child.stdout.setEncoding('utf8');
-        child.stdout.on('data', function(data) {
+        child.stdout.on('data', function (data) {
             capturedOut += data;
             d.notify({'stdout': data});
         });
@@ -145,7 +145,7 @@
 
     if (child.stderr) {
         child.stderr.setEncoding('utf8');
-        child.stderr.on('data', function(data) {
+        child.stderr.on('data', function (data) {
             capturedErr += data;
             d.notify({'stderr': data});
         });
@@ -153,10 +153,10 @@
 
     child.on('close', whenDone);
     child.on('error', whenDone);
-    function whenDone(arg) {
+    function whenDone (arg) {
         child.removeListener('close', whenDone);
         child.removeListener('error', whenDone);
-        var code = typeof arg == 'number' ? arg : arg && arg.code;
+        var code = typeof arg === 'number' ? arg : arg && arg.code;
 
         events.emit('verbose', 'Command finished with error code ' + code + ': ' + cmd + ' ' + args);
         if (code === 0) {
@@ -181,10 +181,9 @@
     return d.promise;
 };
 
-exports.maybeSpawn = function(cmd, args, opts) {
+exports.maybeSpawn = function (cmd, args, opts) {
     if (fs.existsSync(cmd)) {
         return exports.spawn(cmd, args, opts);
     }
     return Q(null);
 };
-
diff --git a/node_modules/cordova-common/src/util/addProperty.js b/node_modules/cordova-common/src/util/addProperty.js
index 7dc4dc1..3e48174 100644
--- a/node_modules/cordova-common/src/util/addProperty.js
+++ b/node_modules/cordova-common/src/util/addProperty.js
@@ -17,8 +17,8 @@
        under the License.
 */
 
-module.exports = function addProperty(module, property, modulePath, obj) {
-    
+module.exports = function addProperty (module, property, modulePath, obj) {
+
     obj = obj || module.exports;
     // Add properties as getter to delay load the modules on first invocation
     Object.defineProperty(obj, property, {
diff --git a/node_modules/cordova-common/src/util/plist-helpers.js b/node_modules/cordova-common/src/util/plist-helpers.js
index 38eb31b..5ec4c1d 100644
--- a/node_modules/cordova-common/src/util/plist-helpers.js
+++ b/node_modules/cordova-common/src/util/plist-helpers.js
@@ -15,32 +15,32 @@
     KIND, either express or implied.  See the License for the
     specific language governing permissions and limitations
     under the License.
-*/ 
+*/
+/* eslint no-useless-escape: 0 */
 
 // contains PLIST utility functions
-var __     = require('underscore');
+var __ = require('underscore');
 var plist = require('plist');
 
 // adds node to doc at selector
 module.exports.graftPLIST = graftPLIST;
-function graftPLIST(doc, xml, selector) {
-    var obj = plist.parse('<plist>'+xml+'</plist>');
+function graftPLIST (doc, xml, selector) {
+    var obj = plist.parse('<plist>' + xml + '</plist>');
 
     var node = doc[selector];
-    if (node && Array.isArray(node) && Array.isArray(obj)){
+    if (node && Array.isArray(node) && Array.isArray(obj)) {
         node = node.concat(obj);
-        for (var i =0;i<node.length; i++){
-            for (var j=i+1; j<node.length; ++j) {
-              if (nodeEqual(node[i], node[j]))
-                    node.splice(j--,1);
+        for (var i = 0; i < node.length; i++) {
+            for (var j = i + 1; j < node.length; ++j) {
+                if (nodeEqual(node[i], node[j])) { node.splice(j--, 1); }
             }
         }
         doc[selector] = node;
     } else {
-        //plist uses objects for <dict>. If we have two dicts we merge them instead of
+        // plist uses objects for <dict>. If we have two dicts we merge them instead of
         // overriding the old one. See CB-6472
-        if (node && __.isObject(node) && __.isObject(obj) && !__.isDate(node) && !__.isDate(obj)){//arrays checked above
-            __.extend(obj,node);
+        if (node && __.isObject(node) && __.isObject(obj) && !__.isDate(node) && !__.isDate(obj)) { // arrays checked above
+            __.extend(obj, node);
         }
         doc[selector] = obj;
     }
@@ -50,15 +50,15 @@
 
 // removes node from doc at selector
 module.exports.prunePLIST = prunePLIST;
-function prunePLIST(doc, xml, selector) {
-    var obj = plist.parse('<plist>'+xml+'</plist>');
+function prunePLIST (doc, xml, selector) {
+    var obj = plist.parse('<plist>' + xml + '</plist>');
 
     pruneOBJECT(doc, selector, obj);
 
     return true;
 }
 
-function pruneOBJECT(doc, selector, fragment) {
+function pruneOBJECT (doc, selector, fragment) {
     if (Array.isArray(fragment) && Array.isArray(doc[selector])) {
         var empty = true;
         for (var i in fragment) {
@@ -66,13 +66,11 @@
                 empty = pruneOBJECT(doc[selector], j, fragment[i]) && empty;
             }
         }
-        if (empty)
-        {
+        if (empty) {
             delete doc[selector];
             return true;
         }
-    }
-    else if (nodeEqual(doc[selector], fragment)) {
+    } else if (nodeEqual(doc[selector], fragment)) {
         delete doc[selector];
         return true;
     }
@@ -80,14 +78,11 @@
     return false;
 }
 
-function nodeEqual(node1, node2) {
-    if (typeof node1 != typeof node2)
-        return false;
-    else if (typeof node1 == 'string') {
-        node2 = escapeRE(node2).replace(new RegExp('\\$[a-zA-Z0-9-_]+','gm'),'(.*?)');
+function nodeEqual (node1, node2) {
+    if (typeof node1 !== typeof node2) { return false; } else if (typeof node1 === 'string') {
+        node2 = escapeRE(node2).replace(/\\\$\S+/gm, '(.*?)');
         return new RegExp('^' + node2 + '$').test(node1);
-    }
-    else {
+    } else {
         for (var key in node2) {
             if (!nodeEqual(node1[key], node2[key])) return false;
         }
@@ -96,6 +91,6 @@
 }
 
 // escape string for use in regex
-function escapeRE(str) {
-    return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '$&');
+function escapeRE (str) {
+    return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
 }
diff --git a/node_modules/cordova-common/src/util/xml-helpers.js b/node_modules/cordova-common/src/util/xml-helpers.js
index cc2eb0f..e2c8fd3 100644
--- a/node_modules/cordova-common/src/util/xml-helpers.js
+++ b/node_modules/cordova-common/src/util/xml-helpers.js
@@ -15,32 +15,31 @@
     KIND, either express or implied.  See the License for the
     specific language governing permissions and limitations
     under the License.
-*/ 
-
-/* jshint sub:true, laxcomma:true */
+*/
 
 /**
  * contains XML utility functions, some of which are specific to elementtree
  */
 
-var fs = require('fs')
-  , path = require('path')
-  , _ = require('underscore')
-  , et = require('elementtree')
-  ;
+var fs = require('fs');
+var path = require('path');
+var _ = require('underscore');
+var et = require('elementtree');
 
-  var ROOT = /^\/([^\/]*)/,
-      ABSOLUTE = /^\/([^\/]*)\/(.*)/;
+/* eslint-disable no-useless-escape */
+var ROOT = /^\/([^\/]*)/;
+var ABSOLUTE = /^\/([^\/]*)\/(.*)/;
+/* eslint-enable no-useless-escape */
 
 module.exports = {
     // compare two et.XML nodes, see if they match
     // compares tagName, text, attributes and children (recursively)
-    equalNodes: function(one, two) {
-        if (one.tag != two.tag) {
+    equalNodes: function (one, two) {
+        if (one.tag !== two.tag) {
             return false;
-        } else if (one.text.trim() != two.text.trim()) {
+        } else if (one.text.trim() !== two.text.trim()) {
             return false;
-        } else if (one._children.length != two._children.length) {
+        } else if (one._children.length !== two._children.length) {
             return false;
         }
 
@@ -56,13 +55,13 @@
     },
 
     // adds node to doc at selector, creating parent if it doesn't exist
-    graftXML: function(doc, nodes, selector, after) {
+    graftXML: function (doc, nodes, selector, after) {
         var parent = module.exports.resolveParent(doc, selector);
         if (!parent) {
-            //Try to create the parent recursively if necessary
+            // Try to create the parent recursively if necessary
             try {
-                var parentToCreate = et.XML('<' + path.basename(selector) + '>'),
-                    parentSelector = path.dirname(selector);
+                var parentToCreate = et.XML('<' + path.basename(selector) + '>');
+                var parentSelector = path.dirname(selector);
 
                 this.graftXML(doc, [parentToCreate], parentSelector);
             } catch (e) {
@@ -78,7 +77,7 @@
                 var children = parent.getchildren();
                 var insertIdx = after ? findInsertIdx(children, after) : children.length;
 
-                //TODO: replace with parent.insert after the bug in ElementTree is fixed
+                // TODO: replace with parent.insert after the bug in ElementTree is fixed
                 parent.getchildren().splice(insertIdx, 0, node);
             }
         });
@@ -88,7 +87,7 @@
 
     // adds new attributes to doc at selector
     // Will only merge if attribute has not been modified already or --force is used
-    graftXMLMerge: function(doc, nodes, selector, xml) {
+    graftXMLMerge: function (doc, nodes, selector, xml) {
         var target = module.exports.resolveParent(doc, selector);
         if (!target) return false;
 
@@ -107,7 +106,7 @@
 
     // overwrite all attributes to doc at selector with new attributes
     // Will only overwrite if attribute has not been modified already or --force is used
-    graftXMLOverwrite: function(doc, nodes, selector, xml) {
+    graftXMLOverwrite: function (doc, nodes, selector, xml) {
         var target = module.exports.resolveParent(doc, selector);
         if (!target) return false;
 
@@ -132,7 +131,7 @@
     },
 
     // removes node from doc at selector
-    pruneXML: function(doc, nodes, selector) {
+    pruneXML: function (doc, nodes, selector) {
         var parent = module.exports.resolveParent(doc, selector);
         if (!parent) return false;
 
@@ -149,7 +148,7 @@
     },
 
     // restores attributes from doc at selector
-    pruneXMLRestore: function(doc, selector, xml) {
+    pruneXMLRestore: function (doc, selector, xml) {
         var target = module.exports.resolveParent(doc, selector);
         if (!target) return false;
 
@@ -160,7 +159,7 @@
         return true;
     },
 
-    pruneXMLRemove: function(doc, selector, nodes) {
+    pruneXMLRemove: function (doc, selector, nodes) {
         var target = module.exports.resolveParent(doc, selector);
         if (!target) return false;
 
@@ -177,11 +176,10 @@
 
     },
 
-
     parseElementtreeSync: function (filename) {
         var contents = fs.readFileSync(filename, 'utf-8');
-        if(contents) {
-            //Windows is the BOM. Skip the Byte Order Mark.
+        if (contents) {
+            // Windows is the BOM. Skip the Byte Order Mark.
             contents = contents.substring(contents.indexOf('<'));
         }
         return new et.ElementTree(et.XML(contents));
@@ -194,7 +192,7 @@
         if (ROOT.test(selector)) {
             tagName = selector.match(ROOT)[1];
             // test for wildcard "any-tag" root selector
-            if (tagName == '*' || tagName === doc._root.tag) {
+            if (tagName === '*' || tagName === doc._root.tag) {
                 parent = doc._root;
 
                 // could be an absolute path, but not selecting the root
@@ -212,11 +210,12 @@
     }
 };
 
-function findChild(node, parent) {
-    var matchingKids = parent.findall(node.tag)
-      , i, j;
+function findChild (node, parent) {
+    var matchingKids = parent.findall(node.tag);
+    var i;
+    var j;
 
-    for (i = 0, j = matchingKids.length ; i < j ; i++) {
+    for (i = 0, j = matchingKids.length; i < j; i++) {
         if (module.exports.equalNodes(node, matchingKids[i])) {
             return matchingKids[i];
         }
@@ -224,13 +223,13 @@
     return null;
 }
 
-function uniqueChild(node, parent) {
-    var matchingKids = parent.findall(node.tag)
-      , i = 0;
+function uniqueChild (node, parent) {
+    var matchingKids = parent.findall(node.tag);
+    var i = 0;
 
     if (matchingKids.length === 0) {
         return true;
-    } else  {
+    } else {
         for (i; i < matchingKids.length; i++) {
             if (module.exports.equalNodes(node, matchingKids[i])) {
                 return false;
@@ -244,51 +243,51 @@
 // of tags after which the insertion should be made. E.g. If we need to
 // insert an element C, and the rule is that the order of children has to be
 // As, Bs, Cs. After will be equal to "C;B;A".
-function findInsertIdx(children, after) {
-    var childrenTags = children.map(function(child) { return child.tag; });
+function findInsertIdx (children, after) {
+    var childrenTags = children.map(function (child) { return child.tag; });
     var afters = after.split(';');
-    var afterIndexes = afters.map(function(current) { return childrenTags.lastIndexOf(current); });
-    var foundIndex = _.find(afterIndexes, function(index) { return index != -1; });
+    var afterIndexes = afters.map(function (current) { return childrenTags.lastIndexOf(current); });
+    var foundIndex = _.find(afterIndexes, function (index) { return index !== -1; });
 
-    //add to the beginning if no matching nodes are found
-    return typeof foundIndex === 'undefined' ? 0 : foundIndex+1;
+    // add to the beginning if no matching nodes are found
+    return typeof foundIndex === 'undefined' ? 0 : foundIndex + 1;
 }
 
-var BLACKLIST = ['platform', 'feature','plugin','engine'];
+var BLACKLIST = ['platform', 'feature', 'plugin', 'engine'];
 var SINGLETONS = ['content', 'author', 'name'];
-function mergeXml(src, dest, platform, clobber) {
+function mergeXml (src, dest, platform, clobber) {
     // Do nothing for blacklisted tags.
-    if (BLACKLIST.indexOf(src.tag) != -1) return;
+    if (BLACKLIST.indexOf(src.tag) !== -1) return;
 
-    //Handle attributes
+    // Handle attributes
     Object.getOwnPropertyNames(src.attrib).forEach(function (attribute) {
         if (clobber || !dest.attrib[attribute]) {
             dest.attrib[attribute] = src.attrib[attribute];
         }
     });
-    //Handle text
+    // Handle text
     if (src.text && (clobber || !dest.text)) {
         dest.text = src.text;
     }
-    //Handle children
+    // Handle children
     src.getchildren().forEach(mergeChild);
 
-    //Handle platform
+    // Handle platform
     if (platform) {
         src.findall('platform[@name="' + platform + '"]').forEach(function (platformElement) {
             platformElement.getchildren().forEach(mergeChild);
         });
     }
 
-    //Handle duplicate preference tags (by name attribute)
+    // Handle duplicate preference tags (by name attribute)
     removeDuplicatePreferences(dest);
 
     function mergeChild (srcChild) {
-        var srcTag = srcChild.tag,
-            destChild = new et.Element(srcTag),
-            foundChild,
-            query = srcTag + '',
-            shouldMerge = true;
+        var srcTag = srcChild.tag;
+        var destChild = new et.Element(srcTag);
+        var foundChild;
+        var query = srcTag + '';
+        var shouldMerge = true;
 
         if (BLACKLIST.indexOf(srcTag) !== -1) return;
 
@@ -299,11 +298,11 @@
                 dest.remove(destChild);
             }
         } else {
-            //Check for an exact match and if you find one don't add
+            // Check for an exact match and if you find one don't add
             var mergeCandidates = dest.findall(query)
-            .filter(function (foundChild) {
-                return foundChild && textMatch(srcChild, foundChild) && attribMatch(srcChild, foundChild);
-            });
+                .filter(function (foundChild) {
+                    return foundChild && textMatch(srcChild, foundChild) && attribMatch(srcChild, foundChild);
+                });
 
             if (mergeCandidates.length > 0) {
                 destChild = mergeCandidates[0];
@@ -316,20 +315,20 @@
         dest.append(destChild);
     }
 
-    function removeDuplicatePreferences(xml) {
+    function removeDuplicatePreferences (xml) {
         // reduce preference tags to a hashtable to remove dupes
-        var prefHash = xml.findall('preference[@name][@value]').reduce(function(previousValue, currentValue) {
+        var prefHash = xml.findall('preference[@name][@value]').reduce(function (previousValue, currentValue) {
             previousValue[ currentValue.attrib.name ] = currentValue.attrib.value;
             return previousValue;
         }, {});
 
         // remove all preferences
-        xml.findall('preference[@name][@value]').forEach(function(pref) {
+        xml.findall('preference[@name][@value]').forEach(function (pref) {
             xml.remove(pref);
         });
 
         // write new preferences
-        Object.keys(prefHash).forEach(function(key, index) {
+        Object.keys(prefHash).forEach(function (key, index) {
             var element = et.SubElement(xml, 'preference');
             element.set('name', key);
             element.set('value', this[key]);
@@ -340,24 +339,24 @@
 // Expose for testing.
 module.exports.mergeXml = mergeXml;
 
-function textMatch(elm1, elm2) {
-    var text1 = elm1.text ? elm1.text.replace(/\s+/, '') : '',
-        text2 = elm2.text ? elm2.text.replace(/\s+/, '') : '';
+function textMatch (elm1, elm2) {
+    var text1 = elm1.text ? elm1.text.replace(/\s+/, '') : '';
+    var text2 = elm2.text ? elm2.text.replace(/\s+/, '') : '';
     return (text1 === '' || text1 === text2);
 }
 
-function attribMatch(one, two) {
+function attribMatch (one, two) {
     var oneAttribKeys = Object.keys(one.attrib);
     var twoAttribKeys = Object.keys(two.attrib);
 
-    if (oneAttribKeys.length != twoAttribKeys.length) {
+    if (oneAttribKeys.length !== twoAttribKeys.length) {
         return false;
     }
 
     for (var i = 0; i < oneAttribKeys.length; i++) {
         var attribName = oneAttribKeys[i];
 
-        if (one.attrib[attribName] != two.attrib[attribName]) {
+        if (one.attrib[attribName] !== two.attrib[attribName]) {
             return false;
         }
     }
diff --git a/node_modules/cordova-serve/package.json b/node_modules/cordova-serve/package.json
index f9a9729..c2d697a 100644
--- a/node_modules/cordova-serve/package.json
+++ b/node_modules/cordova-serve/package.json
@@ -2,56 +2,48 @@
   "_args": [
     [
       {
-        "raw": "cordova-serve@git+https://github.com/apache/cordova-serve.git#2.0.0",
+        "raw": "cordova-serve@^2.0.0",
         "scope": null,
         "escapedName": "cordova-serve",
         "name": "cordova-serve",
-        "rawSpec": "git+https://github.com/apache/cordova-serve.git#2.0.0",
-        "spec": "git+https://github.com/apache/cordova-serve.git#2.0.0",
-        "type": "hosted",
-        "hosted": {
-          "type": "github",
-          "ssh": "git@github.com:apache/cordova-serve.git#2.0.0",
-          "sshUrl": "git+ssh://git@github.com/apache/cordova-serve.git#2.0.0",
-          "httpsUrl": "git+https://github.com/apache/cordova-serve.git#2.0.0",
-          "gitUrl": "git://github.com/apache/cordova-serve.git#2.0.0",
-          "shortcut": "github:apache/cordova-serve#2.0.0",
-          "directUrl": "https://raw.githubusercontent.com/apache/cordova-serve/2.0.0/package.json"
-        }
+        "rawSpec": "^2.0.0",
+        "spec": ">=2.0.0 <3.0.0",
+        "type": "range"
       },
       "/Users/steveng/repo/cordova/cordova-browser"
     ]
   ],
-  "_from": "git+https://github.com/apache/cordova-serve.git#2.0.0",
+  "_from": "cordova-serve@>=2.0.0 <3.0.0",
   "_id": "cordova-serve@2.0.0",
   "_inCache": true,
   "_location": "/cordova-serve",
+  "_nodeVersion": "6.6.0",
+  "_npmOperationalInternal": {
+    "host": "s3://npm-registry-packages",
+    "tmp": "tmp/cordova-serve-2.0.0.tgz_1504051489694_0.8920979660470039"
+  },
+  "_npmUser": {
+    "name": "stevegill",
+    "email": "stevengill97@gmail.com"
+  },
+  "_npmVersion": "4.6.1",
   "_phantomChildren": {},
   "_requested": {
-    "raw": "cordova-serve@git+https://github.com/apache/cordova-serve.git#2.0.0",
+    "raw": "cordova-serve@^2.0.0",
     "scope": null,
     "escapedName": "cordova-serve",
     "name": "cordova-serve",
-    "rawSpec": "git+https://github.com/apache/cordova-serve.git#2.0.0",
-    "spec": "git+https://github.com/apache/cordova-serve.git#2.0.0",
-    "type": "hosted",
-    "hosted": {
-      "type": "github",
-      "ssh": "git@github.com:apache/cordova-serve.git#2.0.0",
-      "sshUrl": "git+ssh://git@github.com/apache/cordova-serve.git#2.0.0",
-      "httpsUrl": "git+https://github.com/apache/cordova-serve.git#2.0.0",
-      "gitUrl": "git://github.com/apache/cordova-serve.git#2.0.0",
-      "shortcut": "github:apache/cordova-serve#2.0.0",
-      "directUrl": "https://raw.githubusercontent.com/apache/cordova-serve/2.0.0/package.json"
-    }
+    "rawSpec": "^2.0.0",
+    "spec": ">=2.0.0 <3.0.0",
+    "type": "range"
   },
   "_requiredBy": [
     "/"
   ],
-  "_resolved": "git+https://github.com/apache/cordova-serve.git#4ad258947c0e347ad5c0f20d3b48e3125eb24111",
-  "_shasum": "38ed22d1b308272109a6ef6d1235356200ca7efe",
+  "_resolved": "file:tools/cordova-serve-2.0.0.tgz",
+  "_shasum": "d7834b83b186607e2b8f1943e073c0633360ea43",
   "_shrinkwrap": null,
-  "_spec": "cordova-serve@git+https://github.com/apache/cordova-serve.git#2.0.0",
+  "_spec": "cordova-serve@^2.0.0",
   "_where": "/Users/steveng/repo/cordova/cordova-browser",
   "author": {
     "name": "Apache Software Foundation"
@@ -79,11 +71,15 @@
     "jasmine": "^2.5.2",
     "rewire": "^2.5.2"
   },
+  "directories": {},
+  "dist": {
+    "shasum": "d7834b83b186607e2b8f1943e073c0633360ea43",
+    "tarball": "https://registry.npmjs.org/cordova-serve/-/cordova-serve-2.0.0.tgz"
+  },
   "engines": {
     "node": ">=4.0.0",
     "npm": ">= 2.5.1"
   },
-  "gitHead": "4ad258947c0e347ad5c0f20d3b48e3125eb24111",
   "homepage": "https://github.com/apache/cordova-lib#readme",
   "keywords": [
     "cordova",
@@ -92,6 +88,32 @@
   ],
   "license": "Apache-2.0",
   "main": "src/main.js",
+  "maintainers": [
+    {
+      "name": "bowserj",
+      "email": "bowserj@apache.org"
+    },
+    {
+      "name": "filmaj",
+      "email": "maj.fil@gmail.com"
+    },
+    {
+      "name": "purplecabbage",
+      "email": "purplecabbage@gmail.com"
+    },
+    {
+      "name": "shazron",
+      "email": "shazron@gmail.com"
+    },
+    {
+      "name": "stevegill",
+      "email": "stevengill97@gmail.com"
+    },
+    {
+      "name": "timbarham",
+      "email": "npmjs@barhams.info"
+    }
+  ],
   "name": "cordova-serve",
   "optionalDependencies": {},
   "readme": "<!--\n#\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n#  KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n#\n-->\n\n[![Build status](https://ci.appveyor.com/api/projects/status/ewv1mhbvms0bfm26?svg=true)](https://ci.appveyor.com/project/ApacheSoftwareFoundation/cordova-serve/branch/master)\n[![Build Status](https://travis-ci.org/apache/cordova-serve.svg?branch=master)](https://travis-ci.org/apache/cordova-serve)\n[![NPM](https://nodei.co/npm/cordova-serve.png)](https://nodei.co/npm/cordova-serve/)\n\n# cordova-serve\nThis module can be used to serve up a Cordova application in the browser. It has no command-line, but rather is intended\nto be called using the following API:\n\n``` js\nvar cordovaServe = require('cordova-serve')();\ncordovaServe.launchServer(opts);\ncordovaServe.servePlatform(platform, opts);\ncordovaServe.launchBrowser(ops);\n```\n\n## launchServer()\n\n``` js\nvar cordovaServe = require('cordova-serve')();\ncordovaServe.launchServer(opts).then(function () {\n    var server = cordovaServe.server;\n    var root = cordovaServe.root;\n    var port = cordovaServe.port;\n\n    ...\n}, function (error) {\n    console.log('An error occurred: ' + error);\n});\n```\n\nLaunches a server with the specified options. Parameters:\n\n* **opts**: Options, as described below.\n\nReturns a promise that is fulfilled once the server has launched, or rejected if the server fails to launch. Once the\npromise is fulfilled, the following properties are available on the `cordovaServe` object:\n \n * **cordovaServe.serve**: The Node http.Server instance.\n * **cordovaServe.root**: The root that was specified, or cwd if none specified.\n * **cordovaServe.port**: The port that was used (could be the requested port, the default port, or some incremented\n   value if the chosen port was in use).\n\n## servePlatform()\n\n``` js\nvar cordovaServe = require('cordova-serve')();\ncordovaServe.servePlatform(platform, opts).then(function () {\n    var server = cordovaServe.server;\n    var port = cordovaServe.port;\n    var projectRoot = cordovaServe.projectRoot;\n    var platformRoot = cordovaServe.root;\n\n    ...\n}, function (error) {\n    console.log('An error occurred: ' + error);\n});\n```\n\nLaunches a server that serves up any Cordova platform (e.g. `browser`, `android` etc) from the current project.\nParameters:\n\n* **opts**: Options, as described below. Note that for `servePlatform()`, the `root` value should be a Cordova project's\n  root folder, or any folder within it - `servePlatform()` will replace it with the platform's `www_dir` folder. If this\n  value is not specified, the *cwd* will be used.\n\nReturns a promise that is fulfilled once the server has launched, or rejected if the server fails to launch. Once the\npromise is fulfilled, the following properties are available on the `cordovaServe` object:\n \n * **cordovaServe.serve**: The Node http.Server instance.\n * **cordovaServe.root**: The requested platform's `www` folder.\n * **cordovaServe.projectRoot**: The root folder of the Cordova project.\n * **cordovaServe.port**: The port that was used (could be the requested port, the default port, or some incremented\n   value if the chosen port was in use).\n\n## launchBrowser()\n\n``` js\nvar cordovaServe = require('cordova-serve')();\ncordovaServe.launchBrowser(opts).then(function (stdout) {\n    console.log('Browser was launched successfully: ' + stdout);\n}, function (error) {\n    console.log('An error occurred: ' + error);\n});\n```\n\nLaunches a browser window pointing to the specified URL. The single parameter is an options object that supports the\nfollowing values (both optional):\n\n* **url**: The URL to open in the browser.\n* **target**: The name of the browser to launch. Can be any of the following: `chrome`, `chromium`, `firefox`, `ie`,\n  `opera`, `safari`. Defaults to `chrome` if no browser is specified.\n\nReturns a promise that is fulfilled once the browser has been launched, or rejected if an error occurs.\n\n## The *opts* Options Object\nThe opts object passed to `launchServer()` and `servePlatform()` supports the following values (all optional):\n\n* **root**: The file path on the local file system that is used as the root for the server, for default mapping of URL\n  path to local file system path.   \n* **port**: The port for the server. Note that if this port is already in use, it will be incremented until a free port\n  is found.\n* **router**: An `ExpressJS` router. If provided, this will be attached *before* default static handling.\n* **noLogOutput**: If `true`, turns off all log output. \n* **noServerInfo**: If `true`, cordova-serve won't output `Static file server running on...` message.\n* **events**: An `EventEmitter` to use for logging. If provided, logging will be output using `events.emit('log', msg)`.\n  If not provided, `console.log()` will be used. Note that nothing will be output in either case if `noLogOutput` is `true`.\n",
diff --git a/node_modules/debug/CHANGELOG.md b/node_modules/debug/CHANGELOG.md
index a1a270c..eadaa18 100644
--- a/node_modules/debug/CHANGELOG.md
+++ b/node_modules/debug/CHANGELOG.md
@@ -1,4 +1,9 @@
 
+2.6.9 / 2017-09-22
+==================
+
+  * remove ReDoS regexp in %o formatter (#504)
+
 2.6.8 / 2017-05-18
 ==================
 
diff --git a/node_modules/debug/component.json b/node_modules/debug/component.json
index 94cd36d..9de2641 100644
--- a/node_modules/debug/component.json
+++ b/node_modules/debug/component.json
@@ -2,7 +2,7 @@
   "name": "debug",
   "repo": "visionmedia/debug",
   "description": "small debugging utility",
-  "version": "2.6.8",
+  "version": "2.6.9",
   "keywords": [
     "debug",
     "log",
diff --git a/node_modules/debug/package.json b/node_modules/debug/package.json
index 1ab1fa7..c28f179 100644
--- a/node_modules/debug/package.json
+++ b/node_modules/debug/package.json
@@ -2,51 +2,52 @@
   "_args": [
     [
       {
-        "raw": "debug@2.6.8",
+        "raw": "debug@2.6.9",
         "scope": null,
         "escapedName": "debug",
         "name": "debug",
-        "rawSpec": "2.6.8",
-        "spec": "2.6.8",
+        "rawSpec": "2.6.9",
+        "spec": "2.6.9",
         "type": "version"
       },
       "/Users/steveng/repo/cordova/cordova-browser/node_modules/compression"
     ]
   ],
-  "_from": "debug@2.6.8",
-  "_id": "debug@2.6.8",
+  "_from": "debug@2.6.9",
+  "_id": "debug@2.6.9",
   "_inCache": true,
   "_location": "/debug",
-  "_nodeVersion": "7.10.0",
+  "_nodeVersion": "8.4.0",
   "_npmOperationalInternal": {
-    "host": "packages-12-west.internal.npmjs.com",
-    "tmp": "tmp/debug-2.6.8.tgz_1495138020906_0.5965513256378472"
+    "host": "s3://npm-registry-packages",
+    "tmp": "tmp/debug-2.6.9.tgz_1506087154503_0.5196126794908196"
   },
   "_npmUser": {
     "name": "tootallnate",
     "email": "nathan@tootallnate.net"
   },
-  "_npmVersion": "4.2.0",
+  "_npmVersion": "5.3.0",
   "_phantomChildren": {},
   "_requested": {
-    "raw": "debug@2.6.8",
+    "raw": "debug@2.6.9",
     "scope": null,
     "escapedName": "debug",
     "name": "debug",
-    "rawSpec": "2.6.8",
-    "spec": "2.6.8",
+    "rawSpec": "2.6.9",
+    "spec": "2.6.9",
     "type": "version"
   },
   "_requiredBy": [
+    "/body-parser",
     "/compression",
     "/express",
     "/finalhandler",
     "/send"
   ],
-  "_resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
-  "_shasum": "e731531ca2ede27d188222427da17821d68ff4fc",
+  "_resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+  "_shasum": "5d128515df134ff327e90a4c93f4e077a536341f",
   "_shrinkwrap": null,
-  "_spec": "debug@2.6.8",
+  "_spec": "debug@2.6.9",
   "_where": "/Users/steveng/repo/cordova/cordova-browser/node_modules/compression",
   "author": {
     "name": "TJ Holowaychuk",
@@ -97,10 +98,11 @@
   },
   "directories": {},
   "dist": {
-    "shasum": "e731531ca2ede27d188222427da17821d68ff4fc",
-    "tarball": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz"
+    "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+    "shasum": "5d128515df134ff327e90a4c93f4e077a536341f",
+    "tarball": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
   },
-  "gitHead": "52e1f21284322f167839e5d3a60f635c8b2dc842",
+  "gitHead": "13abeae468fea297d0dccc50bc55590809241083",
   "homepage": "https://github.com/visionmedia/debug#readme",
   "keywords": [
     "debug",
@@ -113,6 +115,18 @@
     {
       "name": "thebigredgeek",
       "email": "rhyneandrew@gmail.com"
+    },
+    {
+      "name": "kolban",
+      "email": "kolban1@kolban.com"
+    },
+    {
+      "name": "tootallnate",
+      "email": "nathan@tootallnate.net"
+    },
+    {
+      "name": "tjholowaychuk",
+      "email": "tj@vision-media.ca"
     }
   ],
   "name": "debug",
@@ -123,6 +137,5 @@
     "type": "git",
     "url": "git://github.com/visionmedia/debug.git"
   },
-  "scripts": {},
-  "version": "2.6.8"
+  "version": "2.6.9"
 }
diff --git a/node_modules/debug/src/inspector-log.js b/node_modules/debug/src/inspector-log.js
new file mode 100644
index 0000000..60ea6c0
--- /dev/null
+++ b/node_modules/debug/src/inspector-log.js
@@ -0,0 +1,15 @@
+module.exports = inspectorLog;
+
+// black hole
+const nullStream = new (require('stream').Writable)();
+nullStream._write = () => {};
+
+/**
+ * Outputs a `console.log()` to the Node.js Inspector console *only*.
+ */
+function inspectorLog() {
+  const stdout = console._stdout;
+  console._stdout = nullStream;
+  console.log.apply(console, arguments);
+  console._stdout = stdout;
+}
diff --git a/node_modules/debug/src/node.js b/node_modules/debug/src/node.js
index af61297..b15109c 100644
--- a/node_modules/debug/src/node.js
+++ b/node_modules/debug/src/node.js
@@ -85,7 +85,9 @@
 exports.formatters.o = function(v) {
   this.inspectOpts.colors = this.useColors;
   return util.inspect(v, this.inspectOpts)
-    .replace(/\s*\n\s*/g, ' ');
+    .split('\n').map(function(str) {
+      return str.trim()
+    }).join(' ');
 };
 
 /**
diff --git a/node_modules/depd/package.json b/node_modules/depd/package.json
index 78fdd7e..d2e9660 100644
--- a/node_modules/depd/package.json
+++ b/node_modules/depd/package.json
@@ -38,6 +38,7 @@
     "type": "range"
   },
   "_requiredBy": [
+    "/body-parser",
     "/express",
     "/http-errors",
     "/send"
diff --git a/node_modules/etag/HISTORY.md b/node_modules/etag/HISTORY.md
index 136da8c..222b293 100644
--- a/node_modules/etag/HISTORY.md
+++ b/node_modules/etag/HISTORY.md
@@ -1,3 +1,8 @@
+1.8.1 / 2017-09-12
+==================
+
+  * perf: replace regular expression with substring
+
 1.8.0 / 2017-02-18
 ==================
 
diff --git a/node_modules/etag/README.md b/node_modules/etag/README.md
index 9963a5f..09c2169 100644
--- a/node_modules/etag/README.md
+++ b/node_modules/etag/README.md
@@ -23,7 +23,7 @@
 
 ## API
 
-<!-- eslint-disable no-unused-vars --> 
+<!-- eslint-disable no-unused-vars -->
 
 ```js
 var etag = require('etag')
@@ -36,7 +36,7 @@
 default, a strong ETag is generated except for `fs.Stats`, which will
 generate a weak ETag (this can be overwritten by `options.weak`).
 
-<!-- eslint-disable no-undef --> 
+<!-- eslint-disable no-undef -->
 
 ```js
 res.setHeader('ETag', etag(body))
@@ -63,18 +63,18 @@
 ```bash
 $ npm run-script bench
 
-> etag@1.8.0 bench nodejs-etag
+> etag@1.8.1 bench nodejs-etag
 > node benchmark/index.js
 
   http_parser@2.7.0
-  node@6.9.1
-  v8@5.1.281.84
-  uv@1.9.1
-  zlib@1.2.8
+  node@6.11.1
+  v8@5.1.281.103
+  uv@1.11.0
+  zlib@1.2.11
   ares@1.10.1-DEV
-  icu@57.1
+  icu@58.2
   modules@48
-  openssl@1.0.2j
+  openssl@1.0.2k
 
 > node benchmark/body0-100b.js
 
@@ -82,10 +82,10 @@
 
   4 tests completed.
 
-* buffer - strong x 498,600 ops/sec ±0.82% (191 runs sampled)
-* buffer - weak   x 496,249 ops/sec ±0.59% (179 runs sampled)
-  string - strong x 466,298 ops/sec ±0.88% (186 runs sampled)
-  string - weak   x 464,298 ops/sec ±0.84% (184 runs sampled)
+  buffer - strong x 258,647 ops/sec ±1.07% (180 runs sampled)
+  buffer - weak   x 263,812 ops/sec ±0.61% (184 runs sampled)
+  string - strong x 259,955 ops/sec ±1.19% (185 runs sampled)
+  string - weak   x 264,356 ops/sec ±1.09% (184 runs sampled)
 
 > node benchmark/body1-1kb.js
 
@@ -93,10 +93,10 @@
 
   4 tests completed.
 
-* buffer - strong x 346,535 ops/sec ±0.32% (189 runs sampled)
-* buffer - weak   x 344,958 ops/sec ±0.52% (185 runs sampled)
-  string - strong x 259,672 ops/sec ±0.82% (191 runs sampled)
-  string - weak   x 260,931 ops/sec ±0.76% (190 runs sampled)
+  buffer - strong x 189,018 ops/sec ±1.12% (182 runs sampled)
+  buffer - weak   x 190,586 ops/sec ±0.81% (186 runs sampled)
+  string - strong x 144,272 ops/sec ±0.96% (188 runs sampled)
+  string - weak   x 145,380 ops/sec ±1.43% (187 runs sampled)
 
 > node benchmark/body2-5kb.js
 
@@ -104,10 +104,10 @@
 
   4 tests completed.
 
-* buffer - strong x 136,510 ops/sec ±0.62% (189 runs sampled)
-* buffer - weak   x 136,604 ops/sec ±0.51% (191 runs sampled)
-  string - strong x  80,903 ops/sec ±0.84% (192 runs sampled)
-  string - weak   x  82,785 ops/sec ±0.50% (193 runs sampled)
+  buffer - strong x 92,435 ops/sec ±0.42% (188 runs sampled)
+  buffer - weak   x 92,373 ops/sec ±0.58% (189 runs sampled)
+  string - strong x 48,850 ops/sec ±0.56% (186 runs sampled)
+  string - weak   x 49,380 ops/sec ±0.56% (190 runs sampled)
 
 > node benchmark/body3-10kb.js
 
@@ -115,10 +115,10 @@
 
   4 tests completed.
 
-* buffer - strong x 78,650 ops/sec ±0.31% (193 runs sampled)
-* buffer - weak   x 78,685 ops/sec ±0.41% (193 runs sampled)
-  string - strong x 43,999 ops/sec ±0.43% (193 runs sampled)
-  string - weak   x 44,081 ops/sec ±0.45% (192 runs sampled)
+  buffer - strong x 55,989 ops/sec ±0.93% (188 runs sampled)
+  buffer - weak   x 56,148 ops/sec ±0.55% (190 runs sampled)
+  string - strong x 27,345 ops/sec ±0.43% (188 runs sampled)
+  string - weak   x 27,496 ops/sec ±0.45% (190 runs sampled)
 
 > node benchmark/body4-100kb.js
 
@@ -126,10 +126,10 @@
 
   4 tests completed.
 
-  buffer - strong x 8,860 ops/sec ±0.66% (191 runs sampled)
-* buffer - weak   x 9,030 ops/sec ±0.26% (193 runs sampled)
-  string - strong x 4,838 ops/sec ±0.16% (194 runs sampled)
-  string - weak   x 4,800 ops/sec ±0.52% (192 runs sampled)
+  buffer - strong x 7,083 ops/sec ±0.22% (190 runs sampled)
+  buffer - weak   x 7,115 ops/sec ±0.26% (191 runs sampled)
+  string - strong x 3,068 ops/sec ±0.34% (190 runs sampled)
+  string - weak   x 3,096 ops/sec ±0.35% (190 runs sampled)
 
 > node benchmark/stats.js
 
@@ -137,10 +137,10 @@
 
   4 tests completed.
 
-* real - strong x 1,468,073 ops/sec ±0.32% (191 runs sampled)
-* real - weak   x 1,446,852 ops/sec ±0.64% (190 runs sampled)
-  fake - strong x   635,707 ops/sec ±0.33% (194 runs sampled)
-  fake - weak   x   627,708 ops/sec ±0.36% (192 runs sampled)
+  real - strong x 871,642 ops/sec ±0.34% (189 runs sampled)
+  real - weak   x 867,613 ops/sec ±0.39% (190 runs sampled)
+  fake - strong x 401,051 ops/sec ±0.40% (189 runs sampled)
+  fake - weak   x 400,100 ops/sec ±0.47% (188 runs sampled)
 ```
 
 ## License
diff --git a/node_modules/etag/index.js b/node_modules/etag/index.js
index 607f148..2a585c9 100644
--- a/node_modules/etag/index.js
+++ b/node_modules/etag/index.js
@@ -26,7 +26,6 @@
  * @private
  */
 
-var base64PadCharRegExp = /=+$/
 var toString = Object.prototype.toString
 
 /**
@@ -48,7 +47,7 @@
     .createHash('sha1')
     .update(entity, 'utf8')
     .digest('base64')
-    .replace(base64PadCharRegExp, '')
+    .substring(0, 27)
 
   // compute length of entity
   var len = typeof entity === 'string'
diff --git a/node_modules/etag/package.json b/node_modules/etag/package.json
index be53407..58ce44c 100644
--- a/node_modules/etag/package.json
+++ b/node_modules/etag/package.json
@@ -2,49 +2,49 @@
   "_args": [
     [
       {
-        "raw": "etag@~1.8.0",
+        "raw": "etag@~1.8.1",
         "scope": null,
         "escapedName": "etag",
         "name": "etag",
-        "rawSpec": "~1.8.0",
-        "spec": ">=1.8.0 <1.9.0",
+        "rawSpec": "~1.8.1",
+        "spec": ">=1.8.1 <1.9.0",
         "type": "range"
       },
       "/Users/steveng/repo/cordova/cordova-browser/node_modules/express"
     ]
   ],
-  "_from": "etag@>=1.8.0 <1.9.0",
-  "_id": "etag@1.8.0",
+  "_from": "etag@>=1.8.1 <1.9.0",
+  "_id": "etag@1.8.1",
   "_inCache": true,
   "_location": "/etag",
-  "_nodeVersion": "4.7.3",
+  "_nodeVersion": "6.11.1",
   "_npmOperationalInternal": {
-    "host": "packages-12-west.internal.npmjs.com",
-    "tmp": "tmp/etag-1.8.0.tgz_1487475735517_0.6724899658001959"
+    "host": "s3://npm-registry-packages",
+    "tmp": "tmp/etag-1.8.1.tgz_1505270623443_0.24458415526896715"
   },
   "_npmUser": {
     "name": "dougwilson",
     "email": "doug@somethingdoug.com"
   },
-  "_npmVersion": "2.15.11",
+  "_npmVersion": "3.10.10",
   "_phantomChildren": {},
   "_requested": {
-    "raw": "etag@~1.8.0",
+    "raw": "etag@~1.8.1",
     "scope": null,
     "escapedName": "etag",
     "name": "etag",
-    "rawSpec": "~1.8.0",
-    "spec": ">=1.8.0 <1.9.0",
+    "rawSpec": "~1.8.1",
+    "spec": ">=1.8.1 <1.9.0",
     "type": "range"
   },
   "_requiredBy": [
     "/express",
     "/send"
   ],
-  "_resolved": "http://registry.npmjs.org/etag/-/etag-1.8.0.tgz",
-  "_shasum": "6f631aef336d6c46362b51764044ce216be3c051",
+  "_resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+  "_shasum": "41ae2eeb65efa62268aebfea83ac7d79299b0887",
   "_shrinkwrap": null,
-  "_spec": "etag@~1.8.0",
+  "_spec": "etag@~1.8.1",
   "_where": "/Users/steveng/repo/cordova/cordova-browser/node_modules/express",
   "bugs": {
     "url": "https://github.com/jshttp/etag/issues"
@@ -63,20 +63,23 @@
   "description": "Create simple HTTP ETags",
   "devDependencies": {
     "beautify-benchmark": "0.2.4",
-    "benchmark": "2.1.3",
-    "eslint": "3.15.0",
-    "eslint-config-standard": "6.2.1",
-    "eslint-plugin-markdown": "1.0.0-beta.3",
-    "eslint-plugin-promise": "3.4.2",
-    "eslint-plugin-standard": "2.0.1",
+    "benchmark": "2.1.4",
+    "eslint": "3.19.0",
+    "eslint-config-standard": "10.2.1",
+    "eslint-plugin-import": "2.7.0",
+    "eslint-plugin-markdown": "1.0.0-beta.6",
+    "eslint-plugin-node": "5.1.1",
+    "eslint-plugin-promise": "3.5.0",
+    "eslint-plugin-standard": "3.0.1",
     "istanbul": "0.4.5",
     "mocha": "1.21.5",
-    "seedrandom": "2.4.2"
+    "safe-buffer": "5.1.1",
+    "seedrandom": "2.4.3"
   },
   "directories": {},
   "dist": {
-    "shasum": "6f631aef336d6c46362b51764044ce216be3c051",
-    "tarball": "https://registry.npmjs.org/etag/-/etag-1.8.0.tgz"
+    "shasum": "41ae2eeb65efa62268aebfea83ac7d79299b0887",
+    "tarball": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz"
   },
   "engines": {
     "node": ">= 0.6"
@@ -87,7 +90,7 @@
     "README.md",
     "index.js"
   ],
-  "gitHead": "16979f788efa8c793c8d07543b4d6aef3d2bfff8",
+  "gitHead": "9b1e3e41df31cda4080833c187120b91a7ce8327",
   "homepage": "https://github.com/jshttp/etag#readme",
   "keywords": [
     "etag",
@@ -103,7 +106,7 @@
   ],
   "name": "etag",
   "optionalDependencies": {},
-  "readme": "# etag\n\n[![NPM Version][npm-image]][npm-url]\n[![NPM Downloads][downloads-image]][downloads-url]\n[![Node.js Version][node-version-image]][node-version-url]\n[![Build Status][travis-image]][travis-url]\n[![Test Coverage][coveralls-image]][coveralls-url]\n\nCreate simple HTTP ETags\n\nThis module generates HTTP ETags (as defined in RFC 7232) for use in\nHTTP responses.\n\n## Installation\n\nThis is a [Node.js](https://nodejs.org/en/) module available through the\n[npm registry](https://www.npmjs.com/). Installation is done using the\n[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):\n\n```sh\n$ npm install etag\n```\n\n## API\n\n<!-- eslint-disable no-unused-vars --> \n\n```js\nvar etag = require('etag')\n```\n\n### etag(entity, [options])\n\nGenerate a strong ETag for the given entity. This should be the complete\nbody of the entity. Strings, `Buffer`s, and `fs.Stats` are accepted. By\ndefault, a strong ETag is generated except for `fs.Stats`, which will\ngenerate a weak ETag (this can be overwritten by `options.weak`).\n\n<!-- eslint-disable no-undef --> \n\n```js\nres.setHeader('ETag', etag(body))\n```\n\n#### Options\n\n`etag` accepts these properties in the options object.\n\n##### weak\n\nSpecifies if the generated ETag will include the weak validator mark (that\nis, the leading `W/`). The actual entity tag is the same. The default value\nis `false`, unless the `entity` is `fs.Stats`, in which case it is `true`.\n\n## Testing\n\n```sh\n$ npm test\n```\n\n## Benchmark\n\n```bash\n$ npm run-script bench\n\n> etag@1.8.0 bench nodejs-etag\n> node benchmark/index.js\n\n  http_parser@2.7.0\n  node@6.9.1\n  v8@5.1.281.84\n  uv@1.9.1\n  zlib@1.2.8\n  ares@1.10.1-DEV\n  icu@57.1\n  modules@48\n  openssl@1.0.2j\n\n> node benchmark/body0-100b.js\n\n  100B body\n\n  4 tests completed.\n\n* buffer - strong x 498,600 ops/sec ±0.82% (191 runs sampled)\n* buffer - weak   x 496,249 ops/sec ±0.59% (179 runs sampled)\n  string - strong x 466,298 ops/sec ±0.88% (186 runs sampled)\n  string - weak   x 464,298 ops/sec ±0.84% (184 runs sampled)\n\n> node benchmark/body1-1kb.js\n\n  1KB body\n\n  4 tests completed.\n\n* buffer - strong x 346,535 ops/sec ±0.32% (189 runs sampled)\n* buffer - weak   x 344,958 ops/sec ±0.52% (185 runs sampled)\n  string - strong x 259,672 ops/sec ±0.82% (191 runs sampled)\n  string - weak   x 260,931 ops/sec ±0.76% (190 runs sampled)\n\n> node benchmark/body2-5kb.js\n\n  5KB body\n\n  4 tests completed.\n\n* buffer - strong x 136,510 ops/sec ±0.62% (189 runs sampled)\n* buffer - weak   x 136,604 ops/sec ±0.51% (191 runs sampled)\n  string - strong x  80,903 ops/sec ±0.84% (192 runs sampled)\n  string - weak   x  82,785 ops/sec ±0.50% (193 runs sampled)\n\n> node benchmark/body3-10kb.js\n\n  10KB body\n\n  4 tests completed.\n\n* buffer - strong x 78,650 ops/sec ±0.31% (193 runs sampled)\n* buffer - weak   x 78,685 ops/sec ±0.41% (193 runs sampled)\n  string - strong x 43,999 ops/sec ±0.43% (193 runs sampled)\n  string - weak   x 44,081 ops/sec ±0.45% (192 runs sampled)\n\n> node benchmark/body4-100kb.js\n\n  100KB body\n\n  4 tests completed.\n\n  buffer - strong x 8,860 ops/sec ±0.66% (191 runs sampled)\n* buffer - weak   x 9,030 ops/sec ±0.26% (193 runs sampled)\n  string - strong x 4,838 ops/sec ±0.16% (194 runs sampled)\n  string - weak   x 4,800 ops/sec ±0.52% (192 runs sampled)\n\n> node benchmark/stats.js\n\n  stat\n\n  4 tests completed.\n\n* real - strong x 1,468,073 ops/sec ±0.32% (191 runs sampled)\n* real - weak   x 1,446,852 ops/sec ±0.64% (190 runs sampled)\n  fake - strong x   635,707 ops/sec ±0.33% (194 runs sampled)\n  fake - weak   x   627,708 ops/sec ±0.36% (192 runs sampled)\n```\n\n## License\n\n[MIT](LICENSE)\n\n[npm-image]: https://img.shields.io/npm/v/etag.svg\n[npm-url]: https://npmjs.org/package/etag\n[node-version-image]: https://img.shields.io/node/v/etag.svg\n[node-version-url]: https://nodejs.org/en/download/\n[travis-image]: https://img.shields.io/travis/jshttp/etag/master.svg\n[travis-url]: https://travis-ci.org/jshttp/etag\n[coveralls-image]: https://img.shields.io/coveralls/jshttp/etag/master.svg\n[coveralls-url]: https://coveralls.io/r/jshttp/etag?branch=master\n[downloads-image]: https://img.shields.io/npm/dm/etag.svg\n[downloads-url]: https://npmjs.org/package/etag\n",
+  "readme": "# etag\n\n[![NPM Version][npm-image]][npm-url]\n[![NPM Downloads][downloads-image]][downloads-url]\n[![Node.js Version][node-version-image]][node-version-url]\n[![Build Status][travis-image]][travis-url]\n[![Test Coverage][coveralls-image]][coveralls-url]\n\nCreate simple HTTP ETags\n\nThis module generates HTTP ETags (as defined in RFC 7232) for use in\nHTTP responses.\n\n## Installation\n\nThis is a [Node.js](https://nodejs.org/en/) module available through the\n[npm registry](https://www.npmjs.com/). Installation is done using the\n[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):\n\n```sh\n$ npm install etag\n```\n\n## API\n\n<!-- eslint-disable no-unused-vars -->\n\n```js\nvar etag = require('etag')\n```\n\n### etag(entity, [options])\n\nGenerate a strong ETag for the given entity. This should be the complete\nbody of the entity. Strings, `Buffer`s, and `fs.Stats` are accepted. By\ndefault, a strong ETag is generated except for `fs.Stats`, which will\ngenerate a weak ETag (this can be overwritten by `options.weak`).\n\n<!-- eslint-disable no-undef -->\n\n```js\nres.setHeader('ETag', etag(body))\n```\n\n#### Options\n\n`etag` accepts these properties in the options object.\n\n##### weak\n\nSpecifies if the generated ETag will include the weak validator mark (that\nis, the leading `W/`). The actual entity tag is the same. The default value\nis `false`, unless the `entity` is `fs.Stats`, in which case it is `true`.\n\n## Testing\n\n```sh\n$ npm test\n```\n\n## Benchmark\n\n```bash\n$ npm run-script bench\n\n> etag@1.8.1 bench nodejs-etag\n> node benchmark/index.js\n\n  http_parser@2.7.0\n  node@6.11.1\n  v8@5.1.281.103\n  uv@1.11.0\n  zlib@1.2.11\n  ares@1.10.1-DEV\n  icu@58.2\n  modules@48\n  openssl@1.0.2k\n\n> node benchmark/body0-100b.js\n\n  100B body\n\n  4 tests completed.\n\n  buffer - strong x 258,647 ops/sec ±1.07% (180 runs sampled)\n  buffer - weak   x 263,812 ops/sec ±0.61% (184 runs sampled)\n  string - strong x 259,955 ops/sec ±1.19% (185 runs sampled)\n  string - weak   x 264,356 ops/sec ±1.09% (184 runs sampled)\n\n> node benchmark/body1-1kb.js\n\n  1KB body\n\n  4 tests completed.\n\n  buffer - strong x 189,018 ops/sec ±1.12% (182 runs sampled)\n  buffer - weak   x 190,586 ops/sec ±0.81% (186 runs sampled)\n  string - strong x 144,272 ops/sec ±0.96% (188 runs sampled)\n  string - weak   x 145,380 ops/sec ±1.43% (187 runs sampled)\n\n> node benchmark/body2-5kb.js\n\n  5KB body\n\n  4 tests completed.\n\n  buffer - strong x 92,435 ops/sec ±0.42% (188 runs sampled)\n  buffer - weak   x 92,373 ops/sec ±0.58% (189 runs sampled)\n  string - strong x 48,850 ops/sec ±0.56% (186 runs sampled)\n  string - weak   x 49,380 ops/sec ±0.56% (190 runs sampled)\n\n> node benchmark/body3-10kb.js\n\n  10KB body\n\n  4 tests completed.\n\n  buffer - strong x 55,989 ops/sec ±0.93% (188 runs sampled)\n  buffer - weak   x 56,148 ops/sec ±0.55% (190 runs sampled)\n  string - strong x 27,345 ops/sec ±0.43% (188 runs sampled)\n  string - weak   x 27,496 ops/sec ±0.45% (190 runs sampled)\n\n> node benchmark/body4-100kb.js\n\n  100KB body\n\n  4 tests completed.\n\n  buffer - strong x 7,083 ops/sec ±0.22% (190 runs sampled)\n  buffer - weak   x 7,115 ops/sec ±0.26% (191 runs sampled)\n  string - strong x 3,068 ops/sec ±0.34% (190 runs sampled)\n  string - weak   x 3,096 ops/sec ±0.35% (190 runs sampled)\n\n> node benchmark/stats.js\n\n  stat\n\n  4 tests completed.\n\n  real - strong x 871,642 ops/sec ±0.34% (189 runs sampled)\n  real - weak   x 867,613 ops/sec ±0.39% (190 runs sampled)\n  fake - strong x 401,051 ops/sec ±0.40% (189 runs sampled)\n  fake - weak   x 400,100 ops/sec ±0.47% (188 runs sampled)\n```\n\n## License\n\n[MIT](LICENSE)\n\n[npm-image]: https://img.shields.io/npm/v/etag.svg\n[npm-url]: https://npmjs.org/package/etag\n[node-version-image]: https://img.shields.io/node/v/etag.svg\n[node-version-url]: https://nodejs.org/en/download/\n[travis-image]: https://img.shields.io/travis/jshttp/etag/master.svg\n[travis-url]: https://travis-ci.org/jshttp/etag\n[coveralls-image]: https://img.shields.io/coveralls/jshttp/etag/master.svg\n[coveralls-url]: https://coveralls.io/r/jshttp/etag?branch=master\n[downloads-image]: https://img.shields.io/npm/dm/etag.svg\n[downloads-url]: https://npmjs.org/package/etag\n",
   "readmeFilename": "README.md",
   "repository": {
     "type": "git",
@@ -116,5 +119,5 @@
     "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
     "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
   },
-  "version": "1.8.0"
+  "version": "1.8.1"
 }
diff --git a/node_modules/express/History.md b/node_modules/express/History.md
index f297e3b..fbf59a2 100644
--- a/node_modules/express/History.md
+++ b/node_modules/express/History.md
@@ -1,3 +1,88 @@
+4.16.2 / 2017-10-09
+===================
+
+  * Fix `TypeError` in `res.send` when given `Buffer` and `ETag` header set
+  * perf: skip parsing of entire `X-Forwarded-Proto` header
+
+4.16.1 / 2017-09-29
+===================
+
+  * deps: send@0.16.1
+  * deps: serve-static@1.13.1
+    - Fix regression when `root` is incorrectly set to a file
+    - deps: send@0.16.1
+
+4.16.0 / 2017-09-28
+===================
+
+  * Add `"json escape"` setting for `res.json` and `res.jsonp`
+  * Add `express.json` and `express.urlencoded` to parse bodies
+  * Add `options` argument to `res.download`
+  * Improve error message when autoloading invalid view engine
+  * Improve error messages when non-function provided as middleware
+  * Skip `Buffer` encoding when not generating ETag for small response
+  * Use `safe-buffer` for improved Buffer API
+  * deps: accepts@~1.3.4
+    - deps: mime-types@~2.1.16
+  * deps: content-type@~1.0.4
+    - perf: remove argument reassignment
+    - perf: skip parameter parsing when no parameters
+  * deps: etag@~1.8.1
+    - perf: replace regular expression with substring
+  * deps: finalhandler@1.1.0
+    - Use `res.headersSent` when available
+  * deps: parseurl@~1.3.2
+    - perf: reduce overhead for full URLs
+    - perf: unroll the "fast-path" `RegExp`
+  * deps: proxy-addr@~2.0.2
+    - Fix trimming leading / trailing OWS in `X-Forwarded-For`
+    - deps: forwarded@~0.1.2
+    - deps: ipaddr.js@1.5.2
+    - perf: reduce overhead when no `X-Forwarded-For` header
+  * deps: qs@6.5.1
+    - Fix parsing & compacting very deep objects
+  * deps: send@0.16.0
+    - Add 70 new types for file extensions
+    - Add `immutable` option
+    - Fix missing `</html>` in default error & redirects
+    - Set charset as "UTF-8" for .js and .json
+    - Use instance methods on steam to check for listeners
+    - deps: mime@1.4.1
+    - perf: improve path validation speed
+  * deps: serve-static@1.13.0
+    - Add 70 new types for file extensions
+    - Add `immutable` option
+    - Set charset as "UTF-8" for .js and .json
+    - deps: send@0.16.0
+  * deps: setprototypeof@1.1.0
+  * deps: utils-merge@1.0.1
+  * deps: vary@~1.1.2
+    - perf: improve header token parsing speed
+  * perf: re-use options object when generating ETags
+  * perf: remove dead `.charset` set in `res.jsonp`
+
+4.15.5 / 2017-09-24
+===================
+
+  * deps: debug@2.6.9
+  * deps: finalhandler@~1.0.6
+    - deps: debug@2.6.9
+    - deps: parseurl@~1.3.2
+  * deps: fresh@0.5.2
+    - Fix handling of modified headers with invalid dates
+    - perf: improve ETag match loop
+    - perf: improve `If-None-Match` token parsing
+  * deps: send@0.15.6
+    - Fix handling of modified headers with invalid dates
+    - deps: debug@2.6.9
+    - deps: etag@~1.8.1
+    - deps: fresh@0.5.2
+    - perf: improve `If-Match` token parsing
+  * deps: serve-static@1.12.6
+    - deps: parseurl@~1.3.2
+    - deps: send@0.15.6
+    - perf: improve slash collapsing
+
 4.15.4 / 2017-08-06
 ===================
 
diff --git a/node_modules/express/Readme.md b/node_modules/express/Readme.md
index 1732661..3cd2203 100644
--- a/node_modules/express/Readme.md
+++ b/node_modules/express/Readme.md
@@ -21,10 +21,22 @@
 
 ## Installation
 
+This is a [Node.js](https://nodejs.org/en/) module available through the
+[npm registry](https://www.npmjs.com/).
+
+Before installing, [download and install Node.js](https://nodejs.org/en/download/).
+Node.js 0.10 or higher is required.
+
+Installation is done using the
+[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
+
 ```bash
 $ npm install express
 ```
 
+Follow [our installing guide](http://expressjs.com/en/starter/installing.html)
+for more information.
+
 ## Features
 
   * Robust routing
diff --git a/node_modules/express/lib/application.js b/node_modules/express/lib/application.js
index 1abe8d0..91f77d2 100644
--- a/node_modules/express/lib/application.js
+++ b/node_modules/express/lib/application.js
@@ -207,7 +207,7 @@
   var fns = flatten(slice.call(arguments, offset));
 
   if (fns.length === 0) {
-    throw new TypeError('app.use() requires middleware functions');
+    throw new TypeError('app.use() requires a middleware function')
   }
 
   // setup router
@@ -338,7 +338,7 @@
  * Assign `setting` to `val`, or return `setting`'s value.
  *
  *    app.set('foo', 'bar');
- *    app.get('foo');
+ *    app.set('foo');
  *    // => "bar"
  *
  * Mounted servers inherit their parent server's settings.
diff --git a/node_modules/express/lib/express.js b/node_modules/express/lib/express.js
index 187e4e2..485a8fc 100644
--- a/node_modules/express/lib/express.js
+++ b/node_modules/express/lib/express.js
@@ -12,6 +12,7 @@
  * Module dependencies.
  */
 
+var bodyParser = require('body-parser')
 var EventEmitter = require('events').EventEmitter;
 var mixin = require('merge-descriptors');
 var proto = require('./application');
@@ -74,16 +75,16 @@
  * Expose middleware
  */
 
+exports.json = bodyParser.json
 exports.query = require('./middleware/query');
 exports.static = require('serve-static');
+exports.urlencoded = bodyParser.urlencoded
 
 /**
  * Replace removed middleware with an appropriate error message.
  */
 
-[
-  'json',
-  'urlencoded',
+;[
   'bodyParser',
   'compress',
   'cookieSession',
diff --git a/node_modules/express/lib/request.js b/node_modules/express/lib/request.js
index 3432e67..8bb86a9 100644
--- a/node_modules/express/lib/request.js
+++ b/node_modules/express/lib/request.js
@@ -315,8 +315,12 @@
 
   // Note: X-Forwarded-Proto is normally only ever a
   //       single value, but this is to be safe.
-  proto = this.get('X-Forwarded-Proto') || proto;
-  return proto.split(/\s*,\s*/)[0];
+  var header = this.get('X-Forwarded-Proto') || proto
+  var index = header.indexOf(',')
+
+  return index !== -1
+    ? header.substring(0, index).trim()
+    : header.trim()
 });
 
 /**
diff --git a/node_modules/express/lib/response.js b/node_modules/express/lib/response.js
index b852a60..9c1796d 100644
--- a/node_modules/express/lib/response.js
+++ b/node_modules/express/lib/response.js
@@ -12,6 +12,7 @@
  * @private
  */
 
+var Buffer = require('safe-buffer').Buffer
 var contentDisposition = require('content-disposition');
 var deprecate = require('depd')('express');
 var encodeUrl = require('encodeurl');
@@ -95,7 +96,7 @@
  *
  * Examples:
  *
- *     res.send(new Buffer('wahoo'));
+ *     res.send(Buffer.from('wahoo'));
  *     res.send({ some: 'json' });
  *     res.send('<p>some html</p>');
  *
@@ -106,7 +107,6 @@
 res.send = function send(body) {
   var chunk = body;
   var encoding;
-  var len;
   var req = this.req;
   var type;
 
@@ -171,23 +171,33 @@
     }
   }
 
+  // determine if ETag should be generated
+  var etagFn = app.get('etag fn')
+  var generateETag = !this.get('ETag') && typeof etagFn === 'function'
+
   // populate Content-Length
+  var len
   if (chunk !== undefined) {
-    if (!Buffer.isBuffer(chunk)) {
-      // convert chunk to Buffer; saves later double conversions
-      chunk = new Buffer(chunk, encoding);
+    if (Buffer.isBuffer(chunk)) {
+      // get length of Buffer
+      len = chunk.length
+    } else if (!generateETag && chunk.length < 1000) {
+      // just calculate length when no ETag + small chunk
+      len = Buffer.byteLength(chunk, encoding)
+    } else {
+      // convert chunk to Buffer and calculate
+      chunk = Buffer.from(chunk, encoding)
       encoding = undefined;
+      len = chunk.length
     }
 
-    len = chunk.length;
     this.set('Content-Length', len);
   }
 
   // populate ETag
   var etag;
-  var generateETag = len !== undefined && app.get('etag fn');
-  if (typeof generateETag === 'function' && !this.get('ETag')) {
-    if ((etag = generateETag(chunk, encoding))) {
+  if (generateETag && len !== undefined) {
+    if ((etag = etagFn(chunk, encoding))) {
       this.set('ETag', etag);
     }
   }
@@ -244,9 +254,10 @@
 
   // settings
   var app = this.app;
+  var escape = app.get('json escape')
   var replacer = app.get('json replacer');
   var spaces = app.get('json spaces');
-  var body = stringify(val, replacer, spaces);
+  var body = stringify(val, replacer, spaces, escape)
 
   // content-type
   if (!this.get('Content-Type')) {
@@ -286,9 +297,10 @@
 
   // settings
   var app = this.app;
+  var escape = app.get('json escape')
   var replacer = app.get('json replacer');
   var spaces = app.get('json spaces');
-  var body = stringify(val, replacer, spaces);
+  var body = stringify(val, replacer, spaces, escape)
   var callback = this.req.query[app.get('jsonp callback name')];
 
   // content-type
@@ -304,7 +316,6 @@
 
   // jsonp
   if (typeof callback === 'string' && callback.length !== 0) {
-    this.charset = 'utf-8';
     this.set('X-Content-Type-Options', 'nosniff');
     this.set('Content-Type', 'text/javascript');
 
@@ -506,19 +517,29 @@
  * when the data transfer is complete, or when an error has
  * ocurred. Be sure to check `res.headersSent` if you plan to respond.
  *
- * This method uses `res.sendfile()`.
+ * Optionally providing an `options` object to use with `res.sendFile()`.
+ * This function will set the `Content-Disposition` header, overriding
+ * any `Content-Disposition` header passed as header options in order
+ * to set the attachment and filename.
+ *
+ * This method uses `res.sendFile()`.
  *
  * @public
  */
 
-res.download = function download(path, filename, callback) {
+res.download = function download (path, filename, options, callback) {
   var done = callback;
   var name = filename;
+  var opts = options || null
 
-  // support function as second arg
+  // support function as second or third arg
   if (typeof filename === 'function') {
     done = filename;
     name = null;
+    opts = null
+  } else if (typeof options === 'function') {
+    done = options
+    opts = null
   }
 
   // set Content-Disposition when file is sent
@@ -526,10 +547,26 @@
     'Content-Disposition': contentDisposition(name || path)
   };
 
+  // merge user-provided headers
+  if (opts && opts.headers) {
+    var keys = Object.keys(opts.headers)
+    for (var i = 0; i < keys.length; i++) {
+      var key = keys[i]
+      if (key.toLowerCase() !== 'content-disposition') {
+        headers[key] = opts.headers[key]
+      }
+    }
+  }
+
+  // merge user-provided options
+  opts = Object.create(opts)
+  opts.headers = headers
+
   // Resolve the full path for sendFile
   var fullPath = resolve(path);
 
-  return this.sendFile(fullPath, { headers: headers }, done);
+  // send file
+  return this.sendFile(fullPath, opts, done)
 };
 
 /**
@@ -1063,14 +1100,38 @@
 }
 
 /**
- * Stringify JSON, like JSON.stringify, but v8 optimized.
+ * Stringify JSON, like JSON.stringify, but v8 optimized, with the
+ * ability to escape characters that can trigger HTML sniffing.
+ *
+ * @param {*} value
+ * @param {function} replaces
+ * @param {number} spaces
+ * @param {boolean} escape
+ * @returns {string}
  * @private
  */
 
-function stringify(value, replacer, spaces) {
+function stringify (value, replacer, spaces, escape) {
   // v8 checks arguments.length for optimizing simple call
   // https://bugs.chromium.org/p/v8/issues/detail?id=4730
-  return replacer || spaces
+  var json = replacer || spaces
     ? JSON.stringify(value, replacer, spaces)
     : JSON.stringify(value);
+
+  if (escape) {
+    json = json.replace(/[<>&]/g, function (c) {
+      switch (c.charCodeAt(0)) {
+        case 0x3c:
+          return '\\u003c'
+        case 0x3e:
+          return '\\u003e'
+        case 0x26:
+          return '\\u0026'
+        default:
+          return c
+      }
+    })
+  }
+
+  return json
 }
diff --git a/node_modules/express/lib/router/index.js b/node_modules/express/lib/router/index.js
index 51db4c2..60727ed 100644
--- a/node_modules/express/lib/router/index.js
+++ b/node_modules/express/lib/router/index.js
@@ -448,14 +448,14 @@
   var callbacks = flatten(slice.call(arguments, offset));
 
   if (callbacks.length === 0) {
-    throw new TypeError('Router.use() requires middleware functions');
+    throw new TypeError('Router.use() requires a middleware function')
   }
 
   for (var i = 0; i < callbacks.length; i++) {
     var fn = callbacks[i];
 
     if (typeof fn !== 'function') {
-      throw new TypeError('Router.use() requires middleware function but got a ' + gettype(fn));
+      throw new TypeError('Router.use() requires a middleware function but got a ' + gettype(fn))
     }
 
     // add the middleware
diff --git a/node_modules/express/lib/router/route.js b/node_modules/express/lib/router/route.js
index ea82ed2..178df0d 100644
--- a/node_modules/express/lib/router/route.js
+++ b/node_modules/express/lib/router/route.js
@@ -175,7 +175,7 @@
 
     if (typeof handle !== 'function') {
       var type = toString.call(handle);
-      var msg = 'Route.all() requires callback functions but got a ' + type;
+      var msg = 'Route.all() requires a callback function but got a ' + type
       throw new TypeError(msg);
     }
 
@@ -198,7 +198,7 @@
 
       if (typeof handle !== 'function') {
         var type = toString.call(handle);
-        var msg = 'Route.' + method + '() requires callback functions but got a ' + type;
+        var msg = 'Route.' + method + '() requires a callback function but got a ' + type
         throw new Error(msg);
       }
 
diff --git a/node_modules/express/lib/utils.js b/node_modules/express/lib/utils.js
index ae2a7f8..bd81ac7 100644
--- a/node_modules/express/lib/utils.js
+++ b/node_modules/express/lib/utils.js
@@ -12,6 +12,7 @@
  * @api private
  */
 
+var Buffer = require('safe-buffer').Buffer
 var contentDisposition = require('content-disposition');
 var contentType = require('content-type');
 var deprecate = require('depd')('express');
@@ -31,13 +32,7 @@
  * @api private
  */
 
-exports.etag = function (body, encoding) {
-  var buf = !Buffer.isBuffer(body)
-    ? new Buffer(body, encoding)
-    : body;
-
-  return etag(buf, {weak: false});
-};
+exports.etag = createETagGenerator({ weak: false })
 
 /**
  * Return weak ETag for `body`.
@@ -48,13 +43,7 @@
  * @api private
  */
 
-exports.wetag = function wetag(body, encoding){
-  var buf = !Buffer.isBuffer(body)
-    ? new Buffer(body, encoding)
-    : body;
-
-  return etag(buf, {weak: true});
-};
+exports.wetag = createETagGenerator({ weak: true })
 
 /**
  * Check if `path` looks absolute.
@@ -274,6 +263,25 @@
 };
 
 /**
+ * Create an ETag generator function, generating ETags with
+ * the given options.
+ *
+ * @param {object} options
+ * @return {function}
+ * @private
+ */
+
+function createETagGenerator (options) {
+  return function generateETag (body, encoding) {
+    var buf = !Buffer.isBuffer(body)
+      ? Buffer.from(body, encoding)
+      : body
+
+    return etag(buf, options)
+  }
+}
+
+/**
  * Parse an extended query string with qs.
  *
  * @return {Object}
diff --git a/node_modules/express/lib/view.js b/node_modules/express/lib/view.js
index 99d5aed..cf101ca 100644
--- a/node_modules/express/lib/view.js
+++ b/node_modules/express/lib/view.js
@@ -76,7 +76,15 @@
     // load engine
     var mod = this.ext.substr(1)
     debug('require "%s"', mod)
-    opts.engines[this.ext] = require(mod).__express
+
+    // default engine export
+    var fn = require(mod).__express
+
+    if (typeof fn !== 'function') {
+      throw new Error('Module "' + mod + '" does not provide a view engine.')
+    }
+
+    opts.engines[this.ext] = fn
   }
 
   // store loaded engine
diff --git a/node_modules/express/package.json b/node_modules/express/package.json
index d9756ff..cfcb721 100644
--- a/node_modules/express/package.json
+++ b/node_modules/express/package.json
@@ -14,13 +14,13 @@
     ]
   ],
   "_from": "express@>=4.13.3 <5.0.0",
-  "_id": "express@4.15.4",
+  "_id": "express@4.16.2",
   "_inCache": true,
   "_location": "/express",
   "_nodeVersion": "6.11.1",
   "_npmOperationalInternal": {
     "host": "s3://npm-registry-packages",
-    "tmp": "tmp/express-4.15.4.tgz_1502071931644_0.23451056680642068"
+    "tmp": "tmp/express-4.16.2.tgz_1507605225187_0.6328138182871044"
   },
   "_npmUser": {
     "name": "dougwilson",
@@ -40,8 +40,8 @@
   "_requiredBy": [
     "/cordova-serve"
   ],
-  "_resolved": "https://registry.npmjs.org/express/-/express-4.15.4.tgz",
-  "_shasum": "032e2253489cf8fce02666beca3d11ed7a2daed1",
+  "_resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz",
+  "_shasum": "e35c6dfe2d64b7dca0a5cd4f21781be3299e076c",
   "_shrinkwrap": null,
   "_spec": "express@^4.13.3",
   "_where": "/Users/steveng/repo/cordova/cordova-browser/node_modules/cordova-serve",
@@ -83,61 +83,62 @@
     }
   ],
   "dependencies": {
-    "accepts": "~1.3.3",
+    "accepts": "~1.3.4",
     "array-flatten": "1.1.1",
+    "body-parser": "1.18.2",
     "content-disposition": "0.5.2",
-    "content-type": "~1.0.2",
+    "content-type": "~1.0.4",
     "cookie": "0.3.1",
     "cookie-signature": "1.0.6",
-    "debug": "2.6.8",
+    "debug": "2.6.9",
     "depd": "~1.1.1",
     "encodeurl": "~1.0.1",
     "escape-html": "~1.0.3",
-    "etag": "~1.8.0",
-    "finalhandler": "~1.0.4",
-    "fresh": "0.5.0",
+    "etag": "~1.8.1",
+    "finalhandler": "1.1.0",
+    "fresh": "0.5.2",
     "merge-descriptors": "1.0.1",
     "methods": "~1.1.2",
     "on-finished": "~2.3.0",
-    "parseurl": "~1.3.1",
+    "parseurl": "~1.3.2",
     "path-to-regexp": "0.1.7",
-    "proxy-addr": "~1.1.5",
-    "qs": "6.5.0",
+    "proxy-addr": "~2.0.2",
+    "qs": "6.5.1",
     "range-parser": "~1.2.0",
-    "send": "0.15.4",
-    "serve-static": "1.12.4",
-    "setprototypeof": "1.0.3",
+    "safe-buffer": "5.1.1",
+    "send": "0.16.1",
+    "serve-static": "1.13.1",
+    "setprototypeof": "1.1.0",
     "statuses": "~1.3.1",
     "type-is": "~1.6.15",
-    "utils-merge": "1.0.0",
-    "vary": "~1.1.1"
+    "utils-merge": "1.0.1",
+    "vary": "~1.1.2"
   },
   "description": "Fast, unopinionated, minimalist web framework",
   "devDependencies": {
     "after": "0.8.2",
-    "body-parser": "1.17.2",
     "connect-redis": "~2.4.1",
     "cookie-parser": "~1.4.3",
-    "cookie-session": "1.3.0",
+    "cookie-session": "1.3.2",
     "ejs": "2.5.7",
     "eslint": "2.13.1",
-    "express-session": "1.15.5",
+    "express-session": "1.15.6",
     "hbs": "4.0.1",
     "istanbul": "0.4.5",
     "marked": "0.3.6",
-    "method-override": "2.3.9",
-    "mocha": "3.5.0",
-    "morgan": "1.8.2",
+    "method-override": "2.3.10",
+    "mocha": "3.5.3",
+    "morgan": "1.9.0",
     "multiparty": "4.1.3",
     "pbkdf2-password": "1.2.1",
-    "should": "11.2.1",
+    "should": "13.1.0",
     "supertest": "1.2.0",
     "vhost": "~3.0.2"
   },
   "directories": {},
   "dist": {
-    "shasum": "032e2253489cf8fce02666beca3d11ed7a2daed1",
-    "tarball": "https://registry.npmjs.org/express/-/express-4.15.4.tgz"
+    "shasum": "e35c6dfe2d64b7dca0a5cd4f21781be3299e076c",
+    "tarball": "https://registry.npmjs.org/express/-/express-4.16.2.tgz"
   },
   "engines": {
     "node": ">= 0.10.0"
@@ -149,7 +150,7 @@
     "index.js",
     "lib/"
   ],
-  "gitHead": "a4bd4373b2c3b2521ee4c499cb8e90e98f78bfa5",
+  "gitHead": "351396f971280ab79faddcf9782ea50f4e88358d",
   "homepage": "http://expressjs.com/",
   "keywords": [
     "express",
@@ -183,7 +184,7 @@
   ],
   "name": "express",
   "optionalDependencies": {},
-  "readme": "[![Express Logo](https://i.cloudup.com/zfY6lL7eFa-3000x3000.png)](http://expressjs.com/)\n\n  Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).\n\n  [![NPM Version][npm-image]][npm-url]\n  [![NPM Downloads][downloads-image]][downloads-url]\n  [![Linux Build][travis-image]][travis-url]\n  [![Windows Build][appveyor-image]][appveyor-url]\n  [![Test Coverage][coveralls-image]][coveralls-url]\n\n```js\nvar express = require('express')\nvar app = express()\n\napp.get('/', function (req, res) {\n  res.send('Hello World')\n})\n\napp.listen(3000)\n```\n\n## Installation\n\n```bash\n$ npm install express\n```\n\n## Features\n\n  * Robust routing\n  * Focus on high performance\n  * Super-high test coverage\n  * HTTP helpers (redirection, caching, etc)\n  * View system supporting 14+ template engines\n  * Content negotiation\n  * Executable for generating applications quickly\n\n## Docs & Community\n\n  * [Website and Documentation](http://expressjs.com/) - [[website repo](https://github.com/expressjs/expressjs.com)]\n  * [#express](https://webchat.freenode.net/?channels=express) on freenode IRC\n  * [GitHub Organization](https://github.com/expressjs) for Official Middleware & Modules\n  * Visit the [Wiki](https://github.com/expressjs/express/wiki)\n  * [Google Group](https://groups.google.com/group/express-js) for discussion\n  * [Gitter](https://gitter.im/expressjs/express) for support and discussion\n\n**PROTIP** Be sure to read [Migrating from 3.x to 4.x](https://github.com/expressjs/express/wiki/Migrating-from-3.x-to-4.x) as well as [New features in 4.x](https://github.com/expressjs/express/wiki/New-features-in-4.x).\n\n### Security Issues\n\nIf you discover a security vulnerability in Express, please see [Security Policies and Procedures](Security.md).\n\n## Quick Start\n\n  The quickest way to get started with express is to utilize the executable [`express(1)`](https://github.com/expressjs/generator) to generate an application as shown below:\n\n  Install the executable. The executable's major version will match Express's:\n\n```bash\n$ npm install -g express-generator@4\n```\n\n  Create the app:\n\n```bash\n$ express /tmp/foo && cd /tmp/foo\n```\n\n  Install dependencies:\n\n```bash\n$ npm install\n```\n\n  Start the server:\n\n```bash\n$ npm start\n```\n\n## Philosophy\n\n  The Express philosophy is to provide small, robust tooling for HTTP servers, making\n  it a great solution for single page applications, web sites, hybrids, or public\n  HTTP APIs.\n\n  Express does not force you to use any specific ORM or template engine. With support for over\n  14 template engines via [Consolidate.js](https://github.com/tj/consolidate.js),\n  you can quickly craft your perfect framework.\n\n## Examples\n\n  To view the examples, clone the Express repo and install the dependencies:\n\n```bash\n$ git clone git://github.com/expressjs/express.git --depth 1\n$ cd express\n$ npm install\n```\n\n  Then run whichever example you want:\n\n```bash\n$ node examples/content-negotiation\n```\n\n## Tests\n\n  To run the test suite, first install the dependencies, then run `npm test`:\n\n```bash\n$ npm install\n$ npm test\n```\n\n## People\n\nThe original author of Express is [TJ Holowaychuk](https://github.com/tj) [![TJ's Gratipay][gratipay-image-visionmedia]][gratipay-url-visionmedia]\n\nThe current lead maintainer is [Douglas Christopher Wilson](https://github.com/dougwilson) [![Doug's Gratipay][gratipay-image-dougwilson]][gratipay-url-dougwilson]\n\n[List of all contributors](https://github.com/expressjs/express/graphs/contributors)\n\n## License\n\n  [MIT](LICENSE)\n\n[npm-image]: https://img.shields.io/npm/v/express.svg\n[npm-url]: https://npmjs.org/package/express\n[downloads-image]: https://img.shields.io/npm/dm/express.svg\n[downloads-url]: https://npmjs.org/package/express\n[travis-image]: https://img.shields.io/travis/expressjs/express/master.svg?label=linux\n[travis-url]: https://travis-ci.org/expressjs/express\n[appveyor-image]: https://img.shields.io/appveyor/ci/dougwilson/express/master.svg?label=windows\n[appveyor-url]: https://ci.appveyor.com/project/dougwilson/express\n[coveralls-image]: https://img.shields.io/coveralls/expressjs/express/master.svg\n[coveralls-url]: https://coveralls.io/r/expressjs/express?branch=master\n[gratipay-image-visionmedia]: https://img.shields.io/gratipay/visionmedia.svg\n[gratipay-url-visionmedia]: https://gratipay.com/visionmedia/\n[gratipay-image-dougwilson]: https://img.shields.io/gratipay/dougwilson.svg\n[gratipay-url-dougwilson]: https://gratipay.com/dougwilson/\n",
+  "readme": "[![Express Logo](https://i.cloudup.com/zfY6lL7eFa-3000x3000.png)](http://expressjs.com/)\n\n  Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).\n\n  [![NPM Version][npm-image]][npm-url]\n  [![NPM Downloads][downloads-image]][downloads-url]\n  [![Linux Build][travis-image]][travis-url]\n  [![Windows Build][appveyor-image]][appveyor-url]\n  [![Test Coverage][coveralls-image]][coveralls-url]\n\n```js\nvar express = require('express')\nvar app = express()\n\napp.get('/', function (req, res) {\n  res.send('Hello World')\n})\n\napp.listen(3000)\n```\n\n## Installation\n\nThis is a [Node.js](https://nodejs.org/en/) module available through the\n[npm registry](https://www.npmjs.com/).\n\nBefore installing, [download and install Node.js](https://nodejs.org/en/download/).\nNode.js 0.10 or higher is required.\n\nInstallation is done using the\n[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):\n\n```bash\n$ npm install express\n```\n\nFollow [our installing guide](http://expressjs.com/en/starter/installing.html)\nfor more information.\n\n## Features\n\n  * Robust routing\n  * Focus on high performance\n  * Super-high test coverage\n  * HTTP helpers (redirection, caching, etc)\n  * View system supporting 14+ template engines\n  * Content negotiation\n  * Executable for generating applications quickly\n\n## Docs & Community\n\n  * [Website and Documentation](http://expressjs.com/) - [[website repo](https://github.com/expressjs/expressjs.com)]\n  * [#express](https://webchat.freenode.net/?channels=express) on freenode IRC\n  * [GitHub Organization](https://github.com/expressjs) for Official Middleware & Modules\n  * Visit the [Wiki](https://github.com/expressjs/express/wiki)\n  * [Google Group](https://groups.google.com/group/express-js) for discussion\n  * [Gitter](https://gitter.im/expressjs/express) for support and discussion\n\n**PROTIP** Be sure to read [Migrating from 3.x to 4.x](https://github.com/expressjs/express/wiki/Migrating-from-3.x-to-4.x) as well as [New features in 4.x](https://github.com/expressjs/express/wiki/New-features-in-4.x).\n\n### Security Issues\n\nIf you discover a security vulnerability in Express, please see [Security Policies and Procedures](Security.md).\n\n## Quick Start\n\n  The quickest way to get started with express is to utilize the executable [`express(1)`](https://github.com/expressjs/generator) to generate an application as shown below:\n\n  Install the executable. The executable's major version will match Express's:\n\n```bash\n$ npm install -g express-generator@4\n```\n\n  Create the app:\n\n```bash\n$ express /tmp/foo && cd /tmp/foo\n```\n\n  Install dependencies:\n\n```bash\n$ npm install\n```\n\n  Start the server:\n\n```bash\n$ npm start\n```\n\n## Philosophy\n\n  The Express philosophy is to provide small, robust tooling for HTTP servers, making\n  it a great solution for single page applications, web sites, hybrids, or public\n  HTTP APIs.\n\n  Express does not force you to use any specific ORM or template engine. With support for over\n  14 template engines via [Consolidate.js](https://github.com/tj/consolidate.js),\n  you can quickly craft your perfect framework.\n\n## Examples\n\n  To view the examples, clone the Express repo and install the dependencies:\n\n```bash\n$ git clone git://github.com/expressjs/express.git --depth 1\n$ cd express\n$ npm install\n```\n\n  Then run whichever example you want:\n\n```bash\n$ node examples/content-negotiation\n```\n\n## Tests\n\n  To run the test suite, first install the dependencies, then run `npm test`:\n\n```bash\n$ npm install\n$ npm test\n```\n\n## People\n\nThe original author of Express is [TJ Holowaychuk](https://github.com/tj) [![TJ's Gratipay][gratipay-image-visionmedia]][gratipay-url-visionmedia]\n\nThe current lead maintainer is [Douglas Christopher Wilson](https://github.com/dougwilson) [![Doug's Gratipay][gratipay-image-dougwilson]][gratipay-url-dougwilson]\n\n[List of all contributors](https://github.com/expressjs/express/graphs/contributors)\n\n## License\n\n  [MIT](LICENSE)\n\n[npm-image]: https://img.shields.io/npm/v/express.svg\n[npm-url]: https://npmjs.org/package/express\n[downloads-image]: https://img.shields.io/npm/dm/express.svg\n[downloads-url]: https://npmjs.org/package/express\n[travis-image]: https://img.shields.io/travis/expressjs/express/master.svg?label=linux\n[travis-url]: https://travis-ci.org/expressjs/express\n[appveyor-image]: https://img.shields.io/appveyor/ci/dougwilson/express/master.svg?label=windows\n[appveyor-url]: https://ci.appveyor.com/project/dougwilson/express\n[coveralls-image]: https://img.shields.io/coveralls/expressjs/express/master.svg\n[coveralls-url]: https://coveralls.io/r/expressjs/express?branch=master\n[gratipay-image-visionmedia]: https://img.shields.io/gratipay/visionmedia.svg\n[gratipay-url-visionmedia]: https://gratipay.com/visionmedia/\n[gratipay-image-dougwilson]: https://img.shields.io/gratipay/dougwilson.svg\n[gratipay-url-dougwilson]: https://gratipay.com/dougwilson/\n",
   "readmeFilename": "Readme.md",
   "repository": {
     "type": "git",
@@ -191,10 +192,10 @@
   },
   "scripts": {
     "lint": "eslint .",
-    "test": "mocha --require test/support/env --reporter spec --bail --check-leaks test/ test/acceptance/",
-    "test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks test/ test/acceptance/",
-    "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks test/ test/acceptance/",
-    "test-tap": "mocha --require test/support/env --reporter tap --check-leaks test/ test/acceptance/"
+    "test": "mocha --require test/support/env --reporter spec --bail --check-leaks --no-exit test/ test/acceptance/",
+    "test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks --no-exit test/ test/acceptance/",
+    "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks --no-exit test/ test/acceptance/",
+    "test-tap": "mocha --require test/support/env --reporter tap --check-leaks --no-exit test/ test/acceptance/"
   },
-  "version": "4.15.4"
+  "version": "4.16.2"
 }
diff --git a/node_modules/finalhandler/HISTORY.md b/node_modules/finalhandler/HISTORY.md
index 4118f58..4f7244d 100644
--- a/node_modules/finalhandler/HISTORY.md
+++ b/node_modules/finalhandler/HISTORY.md
@@ -1,3 +1,20 @@
+1.1.0 / 2017-09-24
+==================
+
+  * Use `res.headersSent` when available
+
+1.0.6 / 2017-09-22
+==================
+
+  * deps: debug@2.6.9
+
+1.0.5 / 2017-09-15
+==================
+
+  * deps: parseurl@~1.3.2
+    - perf: reduce overhead for full URLs
+    - perf: unroll the "fast-path" `RegExp`
+
 1.0.4 / 2017-08-03
 ==================
 
diff --git a/node_modules/finalhandler/README.md b/node_modules/finalhandler/README.md
index 84c3d2a..6756f0c 100644
--- a/node_modules/finalhandler/README.md
+++ b/node_modules/finalhandler/README.md
@@ -20,7 +20,9 @@
 
 ## API
 
-```
+<!-- eslint-disable no-unused-vars -->
+
+```js
 var finalhandler = require('finalhandler')
 ```
 
diff --git a/node_modules/finalhandler/index.js b/node_modules/finalhandler/index.js
index 87974ca..42f0f74 100644
--- a/node_modules/finalhandler/index.js
+++ b/node_modules/finalhandler/index.js
@@ -89,7 +89,7 @@
     var status
 
     // ignore 404 on in-flight response
-    if (!err && res._header) {
+    if (!err && headersSent(res)) {
       debug('cannot 404 after headers sent')
       return
     }
@@ -125,7 +125,7 @@
     }
 
     // cannot actually respond
-    if (res._header) {
+    if (headersSent(res)) {
       debug('cannot %d after headers sent', status)
       req.socket.destroy()
       return
@@ -228,6 +228,20 @@
 }
 
 /**
+ * Determine if the response headers have been sent.
+ *
+ * @param {object} res
+ * @returns {boolean}
+ * @private
+ */
+
+function headersSent (res) {
+  return typeof res.headersSent !== 'boolean'
+    ? Boolean(res._header)
+    : res.headersSent
+}
+
+/**
  * Send response.
  *
  * @param {IncomingMessage} req
diff --git a/node_modules/finalhandler/package.json b/node_modules/finalhandler/package.json
index d225150..d0344b9 100644
--- a/node_modules/finalhandler/package.json
+++ b/node_modules/finalhandler/package.json
@@ -2,48 +2,48 @@
   "_args": [
     [
       {
-        "raw": "finalhandler@~1.0.4",
+        "raw": "finalhandler@1.1.0",
         "scope": null,
         "escapedName": "finalhandler",
         "name": "finalhandler",
-        "rawSpec": "~1.0.4",
-        "spec": ">=1.0.4 <1.1.0",
-        "type": "range"
+        "rawSpec": "1.1.0",
+        "spec": "1.1.0",
+        "type": "version"
       },
       "/Users/steveng/repo/cordova/cordova-browser/node_modules/express"
     ]
   ],
-  "_from": "finalhandler@>=1.0.4 <1.1.0",
-  "_id": "finalhandler@1.0.4",
+  "_from": "finalhandler@1.1.0",
+  "_id": "finalhandler@1.1.0",
   "_inCache": true,
   "_location": "/finalhandler",
   "_nodeVersion": "6.11.1",
   "_npmOperationalInternal": {
     "host": "s3://npm-registry-packages",
-    "tmp": "tmp/finalhandler-1.0.4.tgz_1501819287831_0.5680490005761385"
+    "tmp": "tmp/finalhandler-1.1.0.tgz_1506311584388_0.4006447312422097"
   },
   "_npmUser": {
     "name": "dougwilson",
     "email": "doug@somethingdoug.com"
   },
-  "_npmVersion": "5.3.0",
+  "_npmVersion": "3.10.10",
   "_phantomChildren": {},
   "_requested": {
-    "raw": "finalhandler@~1.0.4",
+    "raw": "finalhandler@1.1.0",
     "scope": null,
     "escapedName": "finalhandler",
     "name": "finalhandler",
-    "rawSpec": "~1.0.4",
-    "spec": ">=1.0.4 <1.1.0",
-    "type": "range"
+    "rawSpec": "1.1.0",
+    "spec": "1.1.0",
+    "type": "version"
   },
   "_requiredBy": [
     "/express"
   ],
-  "_resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.4.tgz",
-  "_shasum": "18574f2e7c4b98b8ae3b230c21f201f31bdb3fb7",
+  "_resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz",
+  "_shasum": "ce0b6855b45853e791b2fcc680046d88253dd7f5",
   "_shrinkwrap": null,
-  "_spec": "finalhandler@~1.0.4",
+  "_spec": "finalhandler@1.1.0",
   "_where": "/Users/steveng/repo/cordova/cordova-browser/node_modules/express",
   "author": {
     "name": "Douglas Christopher Wilson",
@@ -53,11 +53,11 @@
     "url": "https://github.com/pillarjs/finalhandler/issues"
   },
   "dependencies": {
-    "debug": "2.6.8",
+    "debug": "2.6.9",
     "encodeurl": "~1.0.1",
     "escape-html": "~1.0.3",
     "on-finished": "~2.3.0",
-    "parseurl": "~1.3.1",
+    "parseurl": "~1.3.2",
     "statuses": "~1.3.1",
     "unpipe": "~1.0.0"
   },
@@ -78,9 +78,8 @@
   },
   "directories": {},
   "dist": {
-    "integrity": "sha512-16l/r8RgzlXKmFOhZpHBztvye+lAhC5SU7hXavnerC9UfZqZxxXl3BzL8MhffPT3kF61lj9Oav2LKEzh0ei7tg==",
-    "shasum": "18574f2e7c4b98b8ae3b230c21f201f31bdb3fb7",
-    "tarball": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.4.tgz"
+    "shasum": "ce0b6855b45853e791b2fcc680046d88253dd7f5",
+    "tarball": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz"
   },
   "engines": {
     "node": ">= 0.8"
@@ -90,7 +89,7 @@
     "HISTORY.md",
     "index.js"
   ],
-  "gitHead": "85049f83c5eca2ce6f41700ab3ea7b1bfc64e18f",
+  "gitHead": "a49efb83a3363d895f8c2a4cad07ccfc9e90b8ef",
   "homepage": "https://github.com/pillarjs/finalhandler#readme",
   "license": "MIT",
   "maintainers": [
@@ -101,7 +100,7 @@
   ],
   "name": "finalhandler",
   "optionalDependencies": {},
-  "readme": "# finalhandler\n\n[![NPM Version][npm-image]][npm-url]\n[![NPM Downloads][downloads-image]][downloads-url]\n[![Node.js Version][node-image]][node-url]\n[![Build Status][travis-image]][travis-url]\n[![Test Coverage][coveralls-image]][coveralls-url]\n\nNode.js function to invoke as the final step to respond to HTTP request.\n\n## Installation\n\nThis is a [Node.js](https://nodejs.org/en/) module available through the\n[npm registry](https://www.npmjs.com/). Installation is done using the\n[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):\n\n```sh\n$ npm install finalhandler\n```\n\n## API\n\n```\nvar finalhandler = require('finalhandler')\n```\n\n### finalhandler(req, res, [options])\n\nReturns function to be invoked as the final step for the given `req` and `res`.\nThis function is to be invoked as `fn(err)`. If `err` is falsy, the handler will\nwrite out a 404 response to the `res`. If it is truthy, an error response will\nbe written out to the `res`.\n\nWhen an error is written, the following information is added to the response:\n\n  * The `res.statusCode` is set from `err.status` (or `err.statusCode`). If\n    this value is outside the 4xx or 5xx range, it will be set to 500.\n  * The `res.statusMessage` is set according to the status code.\n  * The body will be the HTML of the status code message if `env` is\n    `'production'`, otherwise will be `err.stack`.\n  * Any headers specified in an `err.headers` object.\n\nThe final handler will also unpipe anything from `req` when it is invoked.\n\n#### options.env\n\nBy default, the environment is determined by `NODE_ENV` variable, but it can be\noverridden by this option.\n\n#### options.onerror\n\nProvide a function to be called with the `err` when it exists. Can be used for\nwriting errors to a central location without excessive function generation. Called\nas `onerror(err, req, res)`.\n\n## Examples\n\n### always 404\n\n```js\nvar finalhandler = require('finalhandler')\nvar http = require('http')\n\nvar server = http.createServer(function (req, res) {\n  var done = finalhandler(req, res)\n  done()\n})\n\nserver.listen(3000)\n```\n\n### perform simple action\n\n```js\nvar finalhandler = require('finalhandler')\nvar fs = require('fs')\nvar http = require('http')\n\nvar server = http.createServer(function (req, res) {\n  var done = finalhandler(req, res)\n\n  fs.readFile('index.html', function (err, buf) {\n    if (err) return done(err)\n    res.setHeader('Content-Type', 'text/html')\n    res.end(buf)\n  })\n})\n\nserver.listen(3000)\n```\n\n### use with middleware-style functions\n\n```js\nvar finalhandler = require('finalhandler')\nvar http = require('http')\nvar serveStatic = require('serve-static')\n\nvar serve = serveStatic('public')\n\nvar server = http.createServer(function (req, res) {\n  var done = finalhandler(req, res)\n  serve(req, res, done)\n})\n\nserver.listen(3000)\n```\n\n### keep log of all errors\n\n```js\nvar finalhandler = require('finalhandler')\nvar fs = require('fs')\nvar http = require('http')\n\nvar server = http.createServer(function (req, res) {\n  var done = finalhandler(req, res, {onerror: logerror})\n\n  fs.readFile('index.html', function (err, buf) {\n    if (err) return done(err)\n    res.setHeader('Content-Type', 'text/html')\n    res.end(buf)\n  })\n})\n\nserver.listen(3000)\n\nfunction logerror (err) {\n  console.error(err.stack || err.toString())\n}\n```\n\n## License\n\n[MIT](LICENSE)\n\n[npm-image]: https://img.shields.io/npm/v/finalhandler.svg\n[npm-url]: https://npmjs.org/package/finalhandler\n[node-image]: https://img.shields.io/node/v/finalhandler.svg\n[node-url]: https://nodejs.org/en/download\n[travis-image]: https://img.shields.io/travis/pillarjs/finalhandler.svg\n[travis-url]: https://travis-ci.org/pillarjs/finalhandler\n[coveralls-image]: https://img.shields.io/coveralls/pillarjs/finalhandler.svg\n[coveralls-url]: https://coveralls.io/r/pillarjs/finalhandler?branch=master\n[downloads-image]: https://img.shields.io/npm/dm/finalhandler.svg\n[downloads-url]: https://npmjs.org/package/finalhandler\n",
+  "readme": "# finalhandler\n\n[![NPM Version][npm-image]][npm-url]\n[![NPM Downloads][downloads-image]][downloads-url]\n[![Node.js Version][node-image]][node-url]\n[![Build Status][travis-image]][travis-url]\n[![Test Coverage][coveralls-image]][coveralls-url]\n\nNode.js function to invoke as the final step to respond to HTTP request.\n\n## Installation\n\nThis is a [Node.js](https://nodejs.org/en/) module available through the\n[npm registry](https://www.npmjs.com/). Installation is done using the\n[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):\n\n```sh\n$ npm install finalhandler\n```\n\n## API\n\n<!-- eslint-disable no-unused-vars -->\n\n```js\nvar finalhandler = require('finalhandler')\n```\n\n### finalhandler(req, res, [options])\n\nReturns function to be invoked as the final step for the given `req` and `res`.\nThis function is to be invoked as `fn(err)`. If `err` is falsy, the handler will\nwrite out a 404 response to the `res`. If it is truthy, an error response will\nbe written out to the `res`.\n\nWhen an error is written, the following information is added to the response:\n\n  * The `res.statusCode` is set from `err.status` (or `err.statusCode`). If\n    this value is outside the 4xx or 5xx range, it will be set to 500.\n  * The `res.statusMessage` is set according to the status code.\n  * The body will be the HTML of the status code message if `env` is\n    `'production'`, otherwise will be `err.stack`.\n  * Any headers specified in an `err.headers` object.\n\nThe final handler will also unpipe anything from `req` when it is invoked.\n\n#### options.env\n\nBy default, the environment is determined by `NODE_ENV` variable, but it can be\noverridden by this option.\n\n#### options.onerror\n\nProvide a function to be called with the `err` when it exists. Can be used for\nwriting errors to a central location without excessive function generation. Called\nas `onerror(err, req, res)`.\n\n## Examples\n\n### always 404\n\n```js\nvar finalhandler = require('finalhandler')\nvar http = require('http')\n\nvar server = http.createServer(function (req, res) {\n  var done = finalhandler(req, res)\n  done()\n})\n\nserver.listen(3000)\n```\n\n### perform simple action\n\n```js\nvar finalhandler = require('finalhandler')\nvar fs = require('fs')\nvar http = require('http')\n\nvar server = http.createServer(function (req, res) {\n  var done = finalhandler(req, res)\n\n  fs.readFile('index.html', function (err, buf) {\n    if (err) return done(err)\n    res.setHeader('Content-Type', 'text/html')\n    res.end(buf)\n  })\n})\n\nserver.listen(3000)\n```\n\n### use with middleware-style functions\n\n```js\nvar finalhandler = require('finalhandler')\nvar http = require('http')\nvar serveStatic = require('serve-static')\n\nvar serve = serveStatic('public')\n\nvar server = http.createServer(function (req, res) {\n  var done = finalhandler(req, res)\n  serve(req, res, done)\n})\n\nserver.listen(3000)\n```\n\n### keep log of all errors\n\n```js\nvar finalhandler = require('finalhandler')\nvar fs = require('fs')\nvar http = require('http')\n\nvar server = http.createServer(function (req, res) {\n  var done = finalhandler(req, res, {onerror: logerror})\n\n  fs.readFile('index.html', function (err, buf) {\n    if (err) return done(err)\n    res.setHeader('Content-Type', 'text/html')\n    res.end(buf)\n  })\n})\n\nserver.listen(3000)\n\nfunction logerror (err) {\n  console.error(err.stack || err.toString())\n}\n```\n\n## License\n\n[MIT](LICENSE)\n\n[npm-image]: https://img.shields.io/npm/v/finalhandler.svg\n[npm-url]: https://npmjs.org/package/finalhandler\n[node-image]: https://img.shields.io/node/v/finalhandler.svg\n[node-url]: https://nodejs.