diff --git a/changelog/17086.txt b/changelog/17086.txt
new file mode 100644
index 0000000000..ce221ad32c
--- /dev/null
+++ b/changelog/17086.txt
@@ -0,0 +1,3 @@
+```release-note:change
+ui: Upgrade Ember to version 4.4.0
+```
\ No newline at end of file
diff --git a/ui/.ember-cli b/ui/.ember-cli
index 4202ec1b2d..f6e59871ff 100644
--- a/ui/.ember-cli
+++ b/ui/.ember-cli
@@ -6,5 +6,11 @@
     Setting `disableAnalytics` to true will prevent any data from being sent.
   */
   "disableAnalytics": true,
-  "output-path": "../http/web_ui"
+  "output-path": "../http/web_ui",
+
+  /**
+  Setting `isTypeScriptProject` to true will force the blueprint generators to generate TypeScript
+  rather than JavaScript by default, when a TypeScript version of a given blueprint is available.
+  */
+  "isTypeScriptProject": false
 }
diff --git a/ui/.eslintignore b/ui/.eslintignore
index 5bd267e8e9..a292799def 100644
--- a/ui/.eslintignore
+++ b/ui/.eslintignore
@@ -20,6 +20,8 @@
 # ember-try
 /.node_modules.ember-try/
 /bower.json.ember-try
+/npm-shrinkwrap.json.ember-try
 /package.json.ember-try
-
+/package-lock.json.ember-try
+/yarn.lock.ember-try
 /tests/helpers/vault-keys.js
diff --git a/ui/.eslintrc.js b/ui/.eslintrc.js
index 9e626cbc17..8b55732d46 100644
--- a/ui/.eslintrc.js
+++ b/ui/.eslintrc.js
@@ -23,7 +23,7 @@ module.exports = {
     browser: true,
   },
   rules: {
-    'no-console': 'warn',
+    'no-console': 'error',
     'ember/no-mixins': 'warn',
     'ember/no-new-mixins': 'off', // should be warn but then every line of the mixin is green
     // need to be fully glimmerized before these rules can be turned on
@@ -63,7 +63,7 @@ module.exports = {
       },
     },
     {
-      // Test files:
+      // test files
       files: ['tests/**/*-test.{js,ts}'],
       extends: ['plugin:qunit/recommended'],
     },
diff --git a/ui/.github/workflows/ci.yml b/ui/.github/workflows/ci.yml
new file mode 100644
index 0000000000..6287d32644
--- /dev/null
+++ b/ui/.github/workflows/ci.yml
@@ -0,0 +1,45 @@
+name: CI
+
+on:
+  push:
+    branches:
+      - main
+      - master
+  pull_request: {}
+
+concurrency:
+  group: ci-${{ github.head_ref || github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  lint:
+    name: "Lint"
+    runs-on: ubuntu-latest
+
+    steps:
+      - uses: actions/checkout@v3
+      - name: Install Node
+        uses: actions/setup-node@v3
+        with:
+          node-version: 12.x
+          cache: yarn
+      - name: Install Dependencies
+        run: yarn install --frozen-lockfile
+      - name: Lint
+        run: yarn lint
+
+  test:
+    name: "Test"
+    runs-on: ubuntu-latest
+
+    steps:
+      - uses: actions/checkout@v3
+      - name: Install Node
+        uses: actions/setup-node@v3
+        with:
+          node-version: 12.x
+          cache: yarn
+      - name: Install Dependencies
+        run: yarn install --frozen-lockfile
+      - name: Run Tests
+        run: yarn test
diff --git a/ui/.gitignore b/ui/.gitignore
index 0474208ee0..70da8c051d 100644
--- a/ui/.gitignore
+++ b/ui/.gitignore
@@ -22,4 +22,10 @@ package-lock.json
 # ember-try
 /.node_modules.ember-try/
 /bower.json.ember-try
+/npm-shrinkwrap.json.ember-try
 /package.json.ember-try
+/package-lock.json.ember-try
+/yarn.lock.ember-try
+
+# broccoli-debug
+/DEBUG/
diff --git a/ui/.prettierignore b/ui/.prettierignore
index 9221655522..4178fd571e 100644
--- a/ui/.prettierignore
+++ b/ui/.prettierignore
@@ -14,8 +14,12 @@
 /coverage/
 !.*
 .eslintcache
+.lint-todo/
 
 # ember-try
 /.node_modules.ember-try/
 /bower.json.ember-try
+/npm-shrinkwrap.json.ember-try
 /package.json.ember-try
+/package-lock.json.ember-try
+/yarn.lock.ember-try
diff --git a/ui/.template-lintrc.js b/ui/.template-lintrc.js
index f61b165724..e4e51b09aa 100644
--- a/ui/.template-lintrc.js
+++ b/ui/.template-lintrc.js
@@ -29,22 +29,18 @@ try {
     prettier: false,
   };
 } catch (error) {
-  console.log(error);
+  console.log(error); // eslint-disable-line
 }
 
 module.exports = {
   plugins: ['ember-template-lint-plugin-prettier'],
   extends: ['recommended', 'ember-template-lint-plugin-prettier:recommended'],
   rules: {
-    'no-bare-strings': 'off',
     'no-action': 'off',
-    'no-duplicate-landmark-elements': 'warn',
     'no-implicit-this': {
       allow: ['supported-auth-backends'],
     },
     'require-input-label': 'off',
-    'no-down-event-binding': 'warn',
-    'self-closing-void-elements': 'off',
   },
   ignore: ['lib/story-md', 'tests/**'],
   // ember language server vscode extension does not currently respect the ignore field
diff --git a/ui/.yarn/releases/yarn-1.22.19.js b/ui/.yarn/releases/yarn-1.22.19.js
new file mode 100755
index 0000000000..3144d7ffcb
--- /dev/null
+++ b/ui/.yarn/releases/yarn-1.22.19.js
@@ -0,0 +1,175346 @@
+#!/usr/bin/env node
+module.exports = /******/ (function (modules) {
+  // webpackBootstrap
+  /******/ // The module cache
+  /******/ var installedModules = {};
+  /******/
+  /******/ // The require function
+  /******/ function __webpack_require__(moduleId) {
+    /******/
+    /******/ // Check if module is in cache
+    /******/ if (installedModules[moduleId]) {
+      /******/ return installedModules[moduleId].exports;
+      /******/
+    }
+    /******/ // Create a new module (and put it into the cache)
+    /******/ var module = (installedModules[moduleId] = {
+      /******/ i: moduleId,
+      /******/ l: false,
+      /******/ exports: {},
+      /******/
+    });
+    /******/
+    /******/ // Execute the module function
+    /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+    /******/
+    /******/ // Flag the module as loaded
+    /******/ module.l = true;
+    /******/
+    /******/ // Return the exports of the module
+    /******/ return module.exports;
+    /******/
+  }
+  /******/
+  /******/
+  /******/ // expose the modules object (__webpack_modules__)
+  /******/ __webpack_require__.m = modules;
+  /******/
+  /******/ // expose the module cache
+  /******/ __webpack_require__.c = installedModules;
+  /******/
+  /******/ // identity function for calling harmony imports with the correct context
+  /******/ __webpack_require__.i = function (value) {
+    return value;
+  };
+  /******/
+  /******/ // define getter function for harmony exports
+  /******/ __webpack_require__.d = function (exports, name, getter) {
+    /******/ if (!__webpack_require__.o(exports, name)) {
+      /******/ Object.defineProperty(exports, name, {
+        /******/ configurable: false,
+        /******/ enumerable: true,
+        /******/ get: getter,
+        /******/
+      });
+      /******/
+    }
+    /******/
+  };
+  /******/
+  /******/ // getDefaultExport function for compatibility with non-harmony modules
+  /******/ __webpack_require__.n = function (module) {
+    /******/ var getter =
+      module && module.__esModule
+        ? /******/ function getDefault() {
+            return module['default'];
+          }
+        : /******/ function getModuleExports() {
+            return module;
+          };
+    /******/ __webpack_require__.d(getter, 'a', getter);
+    /******/ return getter;
+    /******/
+  };
+  /******/
+  /******/ // Object.prototype.hasOwnProperty.call
+  /******/ __webpack_require__.o = function (object, property) {
+    return Object.prototype.hasOwnProperty.call(object, property);
+  };
+  /******/
+  /******/ // __webpack_public_path__
+  /******/ __webpack_require__.p = '';
+  /******/
+  /******/ // Load entry module and return exports
+  /******/ return __webpack_require__((__webpack_require__.s = 517));
+  /******/
+})(
+  /************************************************************************/
+  /******/ [
+    /* 0 */
+    /***/ function (module, exports) {
+      module.exports = require('path');
+
+      /***/
+    },
+    /* 1 */
+    /***/ function (module, __webpack_exports__, __webpack_require__) {
+      'use strict';
+      /* harmony export (immutable) */ __webpack_exports__['a'] = __extends;
+      /* unused harmony export __assign */
+      /* unused harmony export __rest */
+      /* unused harmony export __decorate */
+      /* unused harmony export __param */
+      /* unused harmony export __metadata */
+      /* unused harmony export __awaiter */
+      /* unused harmony export __generator */
+      /* unused harmony export __exportStar */
+      /* unused harmony export __values */
+      /* unused harmony export __read */
+      /* unused harmony export __spread */
+      /* unused harmony export __await */
+      /* unused harmony export __asyncGenerator */
+      /* unused harmony export __asyncDelegator */
+      /* unused harmony export __asyncValues */
+      /* unused harmony export __makeTemplateObject */
+      /* unused harmony export __importStar */
+      /* unused harmony export __importDefault */
+      /*! *****************************************************************************
+Copyright (c) Microsoft Corporation. All rights reserved.
+Licensed 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
+
+THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
+WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
+MERCHANTABLITY OR NON-INFRINGEMENT.
+
+See the Apache Version 2.0 License for specific language governing permissions
+and limitations under the License.
+***************************************************************************** */
+      /* global Reflect, Promise */
+
+      var extendStatics = function (d, b) {
+        extendStatics =
+          Object.setPrototypeOf ||
+          ({ __proto__: [] } instanceof Array &&
+            function (d, b) {
+              d.__proto__ = b;
+            }) ||
+          function (d, b) {
+            for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+          };
+        return extendStatics(d, b);
+      };
+
+      function __extends(d, b) {
+        extendStatics(d, b);
+        function __() {
+          this.constructor = d;
+        }
+        d.prototype = b === null ? Object.create(b) : ((__.prototype = b.prototype), new __());
+      }
+
+      var __assign = function () {
+        __assign =
+          Object.assign ||
+          function __assign(t) {
+            for (var s, i = 1, n = arguments.length; i < n; i++) {
+              s = arguments[i];
+              for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
+            }
+            return t;
+          };
+        return __assign.apply(this, arguments);
+      };
+
+      function __rest(s, e) {
+        var t = {};
+        for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
+        if (s != null && typeof Object.getOwnPropertySymbols === 'function')
+          for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++)
+            if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]];
+        return t;
+      }
+
+      function __decorate(decorators, target, key, desc) {
+        var c = arguments.length,
+          r = c < 3 ? target : desc === null ? (desc = Object.getOwnPropertyDescriptor(target, key)) : desc,
+          d;
+        if (typeof Reflect === 'object' && typeof Reflect.decorate === 'function')
+          r = Reflect.decorate(decorators, target, key, desc);
+        else
+          for (var i = decorators.length - 1; i >= 0; i--)
+            if ((d = decorators[i])) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+        return c > 3 && r && Object.defineProperty(target, key, r), r;
+      }
+
+      function __param(paramIndex, decorator) {
+        return function (target, key) {
+          decorator(target, key, paramIndex);
+        };
+      }
+
+      function __metadata(metadataKey, metadataValue) {
+        if (typeof Reflect === 'object' && typeof Reflect.metadata === 'function')
+          return Reflect.metadata(metadataKey, metadataValue);
+      }
+
+      function __awaiter(thisArg, _arguments, P, generator) {
+        return new (P || (P = Promise))(function (resolve, reject) {
+          function fulfilled(value) {
+            try {
+              step(generator.next(value));
+            } catch (e) {
+              reject(e);
+            }
+          }
+          function rejected(value) {
+            try {
+              step(generator['throw'](value));
+            } catch (e) {
+              reject(e);
+            }
+          }
+          function step(result) {
+            result.done
+              ? resolve(result.value)
+              : new P(function (resolve) {
+                  resolve(result.value);
+                }).then(fulfilled, rejected);
+          }
+          step((generator = generator.apply(thisArg, _arguments || [])).next());
+        });
+      }
+
+      function __generator(thisArg, body) {
+        var _ = {
+            label: 0,
+            sent: function () {
+              if (t[0] & 1) throw t[1];
+              return t[1];
+            },
+            trys: [],
+            ops: [],
+          },
+          f,
+          y,
+          t,
+          g;
+        return (
+          (g = { next: verb(0), throw: verb(1), return: verb(2) }),
+          typeof Symbol === 'function' &&
+            (g[Symbol.iterator] = function () {
+              return this;
+            }),
+          g
+        );
+        function verb(n) {
+          return function (v) {
+            return step([n, v]);
+          };
+        }
+        function step(op) {
+          if (f) throw new TypeError('Generator is already executing.');
+          while (_)
+            try {
+              if (
+                ((f = 1),
+                y &&
+                  (t =
+                    op[0] & 2
+                      ? y['return']
+                      : op[0]
+                      ? y['throw'] || ((t = y['return']) && t.call(y), 0)
+                      : y.next) &&
+                  !(t = t.call(y, op[1])).done)
+              )
+                return t;
+              if (((y = 0), t)) op = [op[0] & 2, t.value];
+              switch (op[0]) {
+                case 0:
+                case 1:
+                  t = op;
+                  break;
+                case 4:
+                  _.label++;
+                  return { value: op[1], done: false };
+                case 5:
+                  _.label++;
+                  y = op[1];
+                  op = [0];
+                  continue;
+                case 7:
+                  op = _.ops.pop();
+                  _.trys.pop();
+                  continue;
+                default:
+                  if (
+                    !((t = _.trys), (t = t.length > 0 && t[t.length - 1])) &&
+                    (op[0] === 6 || op[0] === 2)
+                  ) {
+                    _ = 0;
+                    continue;
+                  }
+                  if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) {
+                    _.label = op[1];
+                    break;
+                  }
+                  if (op[0] === 6 && _.label < t[1]) {
+                    _.label = t[1];
+                    t = op;
+                    break;
+                  }
+                  if (t && _.label < t[2]) {
+                    _.label = t[2];
+                    _.ops.push(op);
+                    break;
+                  }
+                  if (t[2]) _.ops.pop();
+                  _.trys.pop();
+                  continue;
+              }
+              op = body.call(thisArg, _);
+            } catch (e) {
+              op = [6, e];
+              y = 0;
+            } finally {
+              f = t = 0;
+            }
+          if (op[0] & 5) throw op[1];
+          return { value: op[0] ? op[1] : void 0, done: true };
+        }
+      }
+
+      function __exportStar(m, exports) {
+        for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
+      }
+
+      function __values(o) {
+        var m = typeof Symbol === 'function' && o[Symbol.iterator],
+          i = 0;
+        if (m) return m.call(o);
+        return {
+          next: function () {
+            if (o && i >= o.length) o = void 0;
+            return { value: o && o[i++], done: !o };
+          },
+        };
+      }
+
+      function __read(o, n) {
+        var m = typeof Symbol === 'function' && o[Symbol.iterator];
+        if (!m) return o;
+        var i = m.call(o),
+          r,
+          ar = [],
+          e;
+        try {
+          while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
+        } catch (error) {
+          e = { error: error };
+        } finally {
+          try {
+            if (r && !r.done && (m = i['return'])) m.call(i);
+          } finally {
+            if (e) throw e.error;
+          }
+        }
+        return ar;
+      }
+
+      function __spread() {
+        for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
+        return ar;
+      }
+
+      function __await(v) {
+        return this instanceof __await ? ((this.v = v), this) : new __await(v);
+      }
+
+      function __asyncGenerator(thisArg, _arguments, generator) {
+        if (!Symbol.asyncIterator) throw new TypeError('Symbol.asyncIterator is not defined.');
+        var g = generator.apply(thisArg, _arguments || []),
+          i,
+          q = [];
+        return (
+          (i = {}),
+          verb('next'),
+          verb('throw'),
+          verb('return'),
+          (i[Symbol.asyncIterator] = function () {
+            return this;
+          }),
+          i
+        );
+        function verb(n) {
+          if (g[n])
+            i[n] = function (v) {
+              return new Promise(function (a, b) {
+                q.push([n, v, a, b]) > 1 || resume(n, v);
+              });
+            };
+        }
+        function resume(n, v) {
+          try {
+            step(g[n](v));
+          } catch (e) {
+            settle(q[0][3], e);
+          }
+        }
+        function step(r) {
+          r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r);
+        }
+        function fulfill(value) {
+          resume('next', value);
+        }
+        function reject(value) {
+          resume('throw', value);
+        }
+        function settle(f, v) {
+          if ((f(v), q.shift(), q.length)) resume(q[0][0], q[0][1]);
+        }
+      }
+
+      function __asyncDelegator(o) {
+        var i, p;
+        return (
+          (i = {}),
+          verb('next'),
+          verb('throw', function (e) {
+            throw e;
+          }),
+          verb('return'),
+          (i[Symbol.iterator] = function () {
+            return this;
+          }),
+          i
+        );
+        function verb(n, f) {
+          i[n] = o[n]
+            ? function (v) {
+                return (p = !p) ? { value: __await(o[n](v)), done: n === 'return' } : f ? f(v) : v;
+              }
+            : f;
+        }
+      }
+
+      function __asyncValues(o) {
+        if (!Symbol.asyncIterator) throw new TypeError('Symbol.asyncIterator is not defined.');
+        var m = o[Symbol.asyncIterator],
+          i;
+        return m
+          ? m.call(o)
+          : ((o = typeof __values === 'function' ? __values(o) : o[Symbol.iterator]()),
+            (i = {}),
+            verb('next'),
+            verb('throw'),
+            verb('return'),
+            (i[Symbol.asyncIterator] = function () {
+              return this;
+            }),
+            i);
+        function verb(n) {
+          i[n] =
+            o[n] &&
+            function (v) {
+              return new Promise(function (resolve, reject) {
+                (v = o[n](v)), settle(resolve, reject, v.done, v.value);
+              });
+            };
+        }
+        function settle(resolve, reject, d, v) {
+          Promise.resolve(v).then(function (v) {
+            resolve({ value: v, done: d });
+          }, reject);
+        }
+      }
+
+      function __makeTemplateObject(cooked, raw) {
+        if (Object.defineProperty) {
+          Object.defineProperty(cooked, 'raw', { value: raw });
+        } else {
+          cooked.raw = raw;
+        }
+        return cooked;
+      }
+
+      function __importStar(mod) {
+        if (mod && mod.__esModule) return mod;
+        var result = {};
+        if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
+        result.default = mod;
+        return result;
+      }
+
+      function __importDefault(mod) {
+        return mod && mod.__esModule ? mod : { default: mod };
+      }
+
+      /***/
+    },
+    /* 2 */
+    /***/ function (module, exports, __webpack_require__) {
+      'use strict';
+
+      exports.__esModule = true;
+
+      var _promise = __webpack_require__(224);
+
+      var _promise2 = _interopRequireDefault(_promise);
+
+      function _interopRequireDefault(obj) {
+        return obj && obj.__esModule ? obj : { default: obj };
+      }
+
+      exports.default = function (fn) {
+        return function () {
+          var gen = fn.apply(this, arguments);
+          return new _promise2.default(function (resolve, reject) {
+            function step(key, arg) {
+              try {
+                var info = gen[key](arg);
+                var value = info.value;
+              } catch (error) {
+                reject(error);
+                return;
+              }
+
+              if (info.done) {
+                resolve(value);
+              } else {
+                return _promise2.default.resolve(value).then(
+                  function (value) {
+                    step('next', value);
+                  },
+                  function (err) {
+                    step('throw', err);
+                  }
+                );
+              }
+            }
+
+            return step('next');
+          });
+        };
+      };
+
+      /***/
+    },
+    /* 3 */
+    /***/ function (module, exports) {
+      module.exports = require('util');
+
+      /***/
+    },
+    /* 4 */
+    /***/ function (module, exports) {
+      module.exports = require('fs');
+
+      /***/
+    },
+    /* 5 */
+    /***/ function (module, exports, __webpack_require__) {
+      'use strict';
+
+      Object.defineProperty(exports, '__esModule', {
+        value: true,
+      });
+      exports.getFirstSuitableFolder =
+        exports.readFirstAvailableStream =
+        exports.makeTempDir =
+        exports.hardlinksWork =
+        exports.writeFilePreservingEol =
+        exports.getFileSizeOnDisk =
+        exports.walk =
+        exports.symlink =
+        exports.find =
+        exports.readJsonAndFile =
+        exports.readJson =
+        exports.readFileAny =
+        exports.hardlinkBulk =
+        exports.copyBulk =
+        exports.unlink =
+        exports.glob =
+        exports.link =
+        exports.chmod =
+        exports.lstat =
+        exports.exists =
+        exports.mkdirp =
+        exports.stat =
+        exports.access =
+        exports.rename =
+        exports.readdir =
+        exports.realpath =
+        exports.readlink =
+        exports.writeFile =
+        exports.open =
+        exports.readFileBuffer =
+        exports.lockQueue =
+        exports.constants =
+          undefined;
+
+      var _asyncToGenerator2;
+
+      function _load_asyncToGenerator() {
+        return (_asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)));
+      }
+
+      let buildActionsForCopy = (() => {
+        var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (
+          queue,
+          events,
+          possibleExtraneous,
+          reporter
+        ) {
+          //
+          let build = (() => {
+            var _ref5 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) {
+              const src = data.src,
+                dest = data.dest,
+                type = data.type;
+
+              const onFresh = data.onFresh || noop;
+              const onDone = data.onDone || noop;
+
+              // TODO https://github.com/yarnpkg/yarn/issues/3751
+              // related to bundled dependencies handling
+              if (files.has(dest.toLowerCase())) {
+                reporter.verbose(
+                  `The case-insensitive file ${dest} shouldn't be copied twice in one bulk copy`
+                );
+              } else {
+                files.add(dest.toLowerCase());
+              }
+
+              if (type === 'symlink') {
+                yield mkdirp((_path || _load_path()).default.dirname(dest));
+                onFresh();
+                actions.symlink.push({
+                  dest,
+                  linkname: src,
+                });
+                onDone();
+                return;
+              }
+
+              if (events.ignoreBasenames.indexOf((_path || _load_path()).default.basename(src)) >= 0) {
+                // ignored file
+                return;
+              }
+
+              const srcStat = yield lstat(src);
+              let srcFiles;
+
+              if (srcStat.isDirectory()) {
+                srcFiles = yield readdir(src);
+              }
+
+              let destStat;
+              try {
+                // try accessing the destination
+                destStat = yield lstat(dest);
+              } catch (e) {
+                // proceed if destination doesn't exist, otherwise error
+                if (e.code !== 'ENOENT') {
+                  throw e;
+                }
+              }
+
+              // if destination exists
+              if (destStat) {
+                const bothSymlinks = srcStat.isSymbolicLink() && destStat.isSymbolicLink();
+                const bothFolders = srcStat.isDirectory() && destStat.isDirectory();
+                const bothFiles = srcStat.isFile() && destStat.isFile();
+
+                // EINVAL access errors sometimes happen which shouldn't because node shouldn't be giving
+                // us modes that aren't valid. investigate this, it's generally safe to proceed.
+
+                /* if (srcStat.mode !== destStat.mode) {
+            try {
+              await access(dest, srcStat.mode);
+            } catch (err) {}
+          } */
+
+                if (bothFiles && artifactFiles.has(dest)) {
+                  // this file gets changed during build, likely by a custom install script. Don't bother checking it.
+                  onDone();
+                  reporter.verbose(reporter.lang('verboseFileSkipArtifact', src));
+                  return;
+                }
+
+                if (
+                  bothFiles &&
+                  srcStat.size === destStat.size &&
+                  (0, (_fsNormalized || _load_fsNormalized()).fileDatesEqual)(srcStat.mtime, destStat.mtime)
+                ) {
+                  // we can safely assume this is the same file
+                  onDone();
+                  reporter.verbose(reporter.lang('verboseFileSkip', src, dest, srcStat.size, +srcStat.mtime));
+                  return;
+                }
+
+                if (bothSymlinks) {
+                  const srcReallink = yield readlink(src);
+                  if (srcReallink === (yield readlink(dest))) {
+                    // if both symlinks are the same then we can continue on
+                    onDone();
+                    reporter.verbose(reporter.lang('verboseFileSkipSymlink', src, dest, srcReallink));
+                    return;
+                  }
+                }
+
+                if (bothFolders) {
+                  // mark files that aren't in this folder as possibly extraneous
+                  const destFiles = yield readdir(dest);
+                  invariant(srcFiles, 'src files not initialised');
+
+                  for (
+                    var _iterator4 = destFiles,
+                      _isArray4 = Array.isArray(_iterator4),
+                      _i4 = 0,
+                      _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();
+                    ;
+
+                  ) {
+                    var _ref6;
+
+                    if (_isArray4) {
+                      if (_i4 >= _iterator4.length) break;
+                      _ref6 = _iterator4[_i4++];
+                    } else {
+                      _i4 = _iterator4.next();
+                      if (_i4.done) break;
+                      _ref6 = _i4.value;
+                    }
+
+                    const file = _ref6;
+
+                    if (srcFiles.indexOf(file) < 0) {
+                      const loc = (_path || _load_path()).default.join(dest, file);
+                      possibleExtraneous.add(loc);
+
+                      if ((yield lstat(loc)).isDirectory()) {
+                        for (
+                          var _iterator5 = yield readdir(loc),
+                            _isArray5 = Array.isArray(_iterator5),
+                            _i5 = 0,
+                            _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();
+                          ;
+
+                        ) {
+                          var _ref7;
+
+                          if (_isArray5) {
+                            if (_i5 >= _iterator5.length) break;
+                            _ref7 = _iterator5[_i5++];
+                          } else {
+                            _i5 = _iterator5.next();
+                            if (_i5.done) break;
+                            _ref7 = _i5.value;
+                          }
+
+                          const file = _ref7;
+
+                          possibleExtraneous.add((_path || _load_path()).default.join(loc, file));
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+
+              if (destStat && destStat.isSymbolicLink()) {
+                yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(dest);
+                destStat = null;
+              }
+
+              if (srcStat.isSymbolicLink()) {
+                onFresh();
+                const linkname = yield readlink(src);
+                actions.symlink.push({
+                  dest,
+                  linkname,
+                });
+                onDone();
+              } else if (srcStat.isDirectory()) {
+                if (!destStat) {
+                  reporter.verbose(reporter.lang('verboseFileFolder', dest));
+                  yield mkdirp(dest);
+                }
+
+                const destParts = dest.split((_path || _load_path()).default.sep);
+                while (destParts.length) {
+                  files.add(destParts.join((_path || _load_path()).default.sep).toLowerCase());
+                  destParts.pop();
+                }
+
+                // push all files to queue
+                invariant(srcFiles, 'src files not initialised');
+                let remaining = srcFiles.length;
+                if (!remaining) {
+                  onDone();
+                }
+                for (
+                  var _iterator6 = srcFiles,
+                    _isArray6 = Array.isArray(_iterator6),
+                    _i6 = 0,
+                    _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();
+                  ;
+
+                ) {
+                  var _ref8;
+
+                  if (_isArray6) {
+                    if (_i6 >= _iterator6.length) break;
+                    _ref8 = _iterator6[_i6++];
+                  } else {
+                    _i6 = _iterator6.next();
+                    if (_i6.done) break;
+                    _ref8 = _i6.value;
+                  }
+
+                  const file = _ref8;
+
+                  queue.push({
+                    dest: (_path || _load_path()).default.join(dest, file),
+                    onFresh,
+                    onDone: (function (_onDone) {
+                      function onDone() {
+                        return _onDone.apply(this, arguments);
+                      }
+
+                      onDone.toString = function () {
+                        return _onDone.toString();
+                      };
+
+                      return onDone;
+                    })(function () {
+                      if (--remaining === 0) {
+                        onDone();
+                      }
+                    }),
+                    src: (_path || _load_path()).default.join(src, file),
+                  });
+                }
+              } else if (srcStat.isFile()) {
+                onFresh();
+                actions.file.push({
+                  src,
+                  dest,
+                  atime: srcStat.atime,
+                  mtime: srcStat.mtime,
+                  mode: srcStat.mode,
+                });
+                onDone();
+              } else {
+                throw new Error(`unsure how to copy this: ${src}`);
+              }
+            });
+
+            return function build(_x5) {
+              return _ref5.apply(this, arguments);
+            };
+          })();
+
+          const artifactFiles = new Set(events.artifactFiles || []);
+          const files = new Set();
+
+          // initialise events
+          for (
+            var _iterator = queue,
+              _isArray = Array.isArray(_iterator),
+              _i = 0,
+              _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();
+            ;
+
+          ) {
+            var _ref2;
+
+            if (_isArray) {
+              if (_i >= _iterator.length) break;
+              _ref2 = _iterator[_i++];
+            } else {
+              _i = _iterator.next();
+              if (_i.done) break;
+              _ref2 = _i.value;
+            }
+
+            const item = _ref2;
+
+            const onDone = item.onDone;
+            item.onDone = function () {
+              events.onProgress(item.dest);
+              if (onDone) {
+                onDone();
+              }
+            };
+          }
+          events.onStart(queue.length);
+
+          // start building actions
+          const actions = {
+            file: [],
+            symlink: [],
+            link: [],
+          };
+
+          // custom concurrency logic as we're always executing stacks of CONCURRENT_QUEUE_ITEMS queue items
+          // at a time due to the requirement to push items onto the queue
+          while (queue.length) {
+            const items = queue.splice(0, CONCURRENT_QUEUE_ITEMS);
+            yield Promise.all(items.map(build));
+          }
+
+          // simulate the existence of some files to prevent considering them extraneous
+          for (
+            var _iterator2 = artifactFiles,
+              _isArray2 = Array.isArray(_iterator2),
+              _i2 = 0,
+              _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();
+            ;
+
+          ) {
+            var _ref3;
+
+            if (_isArray2) {
+              if (_i2 >= _iterator2.length) break;
+              _ref3 = _iterator2[_i2++];
+            } else {
+              _i2 = _iterator2.next();
+              if (_i2.done) break;
+              _ref3 = _i2.value;
+            }
+
+            const file = _ref3;
+
+            if (possibleExtraneous.has(file)) {
+              reporter.verbose(reporter.lang('verboseFilePhantomExtraneous', file));
+              possibleExtraneous.delete(file);
+            }
+          }
+
+          for (
+            var _iterator3 = possibleExtraneous,
+              _isArray3 = Array.isArray(_iterator3),
+              _i3 = 0,
+              _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();
+            ;
+
+          ) {
+            var _ref4;
+
+            if (_isArray3) {
+              if (_i3 >= _iterator3.length) break;
+              _ref4 = _iterator3[_i3++];
+            } else {
+              _i3 = _iterator3.next();
+              if (_i3.done) break;
+              _ref4 = _i3.value;
+            }
+
+            const loc = _ref4;
+
+            if (files.has(loc.toLowerCase())) {
+              possibleExtraneous.delete(loc);
+            }
+          }
+
+          return actions;
+        });
+
+        return function buildActionsForCopy(_x, _x2, _x3, _x4) {
+          return _ref.apply(this, arguments);
+        };
+      })();
+
+      let buildActionsForHardlink = (() => {
+        var _ref9 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (
+          queue,
+          events,
+          possibleExtraneous,
+          reporter
+        ) {
+          //
+          let build = (() => {
+            var _ref13 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) {
+              const src = data.src,
+                dest = data.dest;
+
+              const onFresh = data.onFresh || noop;
+              const onDone = data.onDone || noop;
+              if (files.has(dest.toLowerCase())) {
+                // Fixes issue https://github.com/yarnpkg/yarn/issues/2734
+                // When bulk hardlinking we have A -> B structure that we want to hardlink to A1 -> B1,
+                // package-linker passes that modules A1 and B1 need to be hardlinked,
+                // the recursive linking algorithm of A1 ends up scheduling files in B1 to be linked twice which will case
+                // an exception.
+                onDone();
+                return;
+              }
+              files.add(dest.toLowerCase());
+
+              if (events.ignoreBasenames.indexOf((_path || _load_path()).default.basename(src)) >= 0) {
+                // ignored file
+                return;
+              }
+
+              const srcStat = yield lstat(src);
+              let srcFiles;
+
+              if (srcStat.isDirectory()) {
+                srcFiles = yield readdir(src);
+              }
+
+              const destExists = yield exists(dest);
+              if (destExists) {
+                const destStat = yield lstat(dest);
+
+                const bothSymlinks = srcStat.isSymbolicLink() && destStat.isSymbolicLink();
+                const bothFolders = srcStat.isDirectory() && destStat.isDirectory();
+                const bothFiles = srcStat.isFile() && destStat.isFile();
+
+                if (srcStat.mode !== destStat.mode) {
+                  try {
+                    yield access(dest, srcStat.mode);
+                  } catch (err) {
+                    // EINVAL access errors sometimes happen which shouldn't because node shouldn't be giving
+                    // us modes that aren't valid. investigate this, it's generally safe to proceed.
+                    reporter.verbose(err);
+                  }
+                }
+
+                if (bothFiles && artifactFiles.has(dest)) {
+                  // this file gets changed during build, likely by a custom install script. Don't bother checking it.
+                  onDone();
+                  reporter.verbose(reporter.lang('verboseFileSkipArtifact', src));
+                  return;
+                }
+
+                // correct hardlink
+                if (bothFiles && srcStat.ino !== null && srcStat.ino === destStat.ino) {
+                  onDone();
+                  reporter.verbose(reporter.lang('verboseFileSkip', src, dest, srcStat.ino));
+                  return;
+                }
+
+                if (bothSymlinks) {
+                  const srcReallink = yield readlink(src);
+                  if (srcReallink === (yield readlink(dest))) {
+                    // if both symlinks are the same then we can continue on
+                    onDone();
+                    reporter.verbose(reporter.lang('verboseFileSkipSymlink', src, dest, srcReallink));
+                    return;
+                  }
+                }
+
+                if (bothFolders) {
+                  // mark files that aren't in this folder as possibly extraneous
+                  const destFiles = yield readdir(dest);
+                  invariant(srcFiles, 'src files not initialised');
+
+                  for (
+                    var _iterator10 = destFiles,
+                      _isArray10 = Array.isArray(_iterator10),
+                      _i10 = 0,
+                      _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();
+                    ;
+
+                  ) {
+                    var _ref14;
+
+                    if (_isArray10) {
+                      if (_i10 >= _iterator10.length) break;
+                      _ref14 = _iterator10[_i10++];
+                    } else {
+                      _i10 = _iterator10.next();
+                      if (_i10.done) break;
+                      _ref14 = _i10.value;
+                    }
+
+                    const file = _ref14;
+
+                    if (srcFiles.indexOf(file) < 0) {
+                      const loc = (_path || _load_path()).default.join(dest, file);
+                      possibleExtraneous.add(loc);
+
+                      if ((yield lstat(loc)).isDirectory()) {
+                        for (
+                          var _iterator11 = yield readdir(loc),
+                            _isArray11 = Array.isArray(_iterator11),
+                            _i11 = 0,
+                            _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();
+                          ;
+
+                        ) {
+                          var _ref15;
+
+                          if (_isArray11) {
+                            if (_i11 >= _iterator11.length) break;
+                            _ref15 = _iterator11[_i11++];
+                          } else {
+                            _i11 = _iterator11.next();
+                            if (_i11.done) break;
+                            _ref15 = _i11.value;
+                          }
+
+                          const file = _ref15;
+
+                          possibleExtraneous.add((_path || _load_path()).default.join(loc, file));
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+
+              if (srcStat.isSymbolicLink()) {
+                onFresh();
+                const linkname = yield readlink(src);
+                actions.symlink.push({
+                  dest,
+                  linkname,
+                });
+                onDone();
+              } else if (srcStat.isDirectory()) {
+                reporter.verbose(reporter.lang('verboseFileFolder', dest));
+                yield mkdirp(dest);
+
+                const destParts = dest.split((_path || _load_path()).default.sep);
+                while (destParts.length) {
+                  files.add(destParts.join((_path || _load_path()).default.sep).toLowerCase());
+                  destParts.pop();
+                }
+
+                // push all files to queue
+                invariant(srcFiles, 'src files not initialised');
+                let remaining = srcFiles.length;
+                if (!remaining) {
+                  onDone();
+                }
+                for (
+                  var _iterator12 = srcFiles,
+                    _isArray12 = Array.isArray(_iterator12),
+                    _i12 = 0,
+                    _iterator12 = _isArray12 ? _iterator12 : _iterator12[Symbol.iterator]();
+                  ;
+
+                ) {
+                  var _ref16;
+
+                  if (_isArray12) {
+                    if (_i12 >= _iterator12.length) break;
+                    _ref16 = _iterator12[_i12++];
+                  } else {
+                    _i12 = _iterator12.next();
+                    if (_i12.done) break;
+                    _ref16 = _i12.value;
+                  }
+
+                  const file = _ref16;
+
+                  queue.push({
+                    onFresh,
+                    src: (_path || _load_path()).default.join(src, file),
+                    dest: (_path || _load_path()).default.join(dest, file),
+                    onDone: (function (_onDone2) {
+                      function onDone() {
+                        return _onDone2.apply(this, arguments);
+                      }
+
+                      onDone.toString = function () {
+                        return _onDone2.toString();
+                      };
+
+                      return onDone;
+                    })(function () {
+                      if (--remaining === 0) {
+                        onDone();
+                      }
+                    }),
+                  });
+                }
+              } else if (srcStat.isFile()) {
+                onFresh();
+                actions.link.push({
+                  src,
+                  dest,
+                  removeDest: destExists,
+                });
+                onDone();
+              } else {
+                throw new Error(`unsure how to copy this: ${src}`);
+              }
+            });
+
+            return function build(_x10) {
+              return _ref13.apply(this, arguments);
+            };
+          })();
+
+          const artifactFiles = new Set(events.artifactFiles || []);
+          const files = new Set();
+
+          // initialise events
+          for (
+            var _iterator7 = queue,
+              _isArray7 = Array.isArray(_iterator7),
+              _i7 = 0,
+              _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();
+            ;
+
+          ) {
+            var _ref10;
+
+            if (_isArray7) {
+              if (_i7 >= _iterator7.length) break;
+              _ref10 = _iterator7[_i7++];
+            } else {
+              _i7 = _iterator7.next();
+              if (_i7.done) break;
+              _ref10 = _i7.value;
+            }
+
+            const item = _ref10;
+
+            const onDone = item.onDone || noop;
+            item.onDone = function () {
+              events.onProgress(item.dest);
+              onDone();
+            };
+          }
+          events.onStart(queue.length);
+
+          // start building actions
+          const actions = {
+            file: [],
+            symlink: [],
+            link: [],
+          };
+
+          // custom concurrency logic as we're always executing stacks of CONCURRENT_QUEUE_ITEMS queue items
+          // at a time due to the requirement to push items onto the queue
+          while (queue.length) {
+            const items = queue.splice(0, CONCURRENT_QUEUE_ITEMS);
+            yield Promise.all(items.map(build));
+          }
+
+          // simulate the existence of some files to prevent considering them extraneous
+          for (
+            var _iterator8 = artifactFiles,
+              _isArray8 = Array.isArray(_iterator8),
+              _i8 = 0,
+              _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();
+            ;
+
+          ) {
+            var _ref11;
+
+            if (_isArray8) {
+              if (_i8 >= _iterator8.length) break;
+              _ref11 = _iterator8[_i8++];
+            } else {
+              _i8 = _iterator8.next();
+              if (_i8.done) break;
+              _ref11 = _i8.value;
+            }
+
+            const file = _ref11;
+
+            if (possibleExtraneous.has(file)) {
+              reporter.verbose(reporter.lang('verboseFilePhantomExtraneous', file));
+              possibleExtraneous.delete(file);
+            }
+          }
+
+          for (
+            var _iterator9 = possibleExtraneous,
+              _isArray9 = Array.isArray(_iterator9),
+              _i9 = 0,
+              _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();
+            ;
+
+          ) {
+            var _ref12;
+
+            if (_isArray9) {
+              if (_i9 >= _iterator9.length) break;
+              _ref12 = _iterator9[_i9++];
+            } else {
+              _i9 = _iterator9.next();
+              if (_i9.done) break;
+              _ref12 = _i9.value;
+            }
+
+            const loc = _ref12;
+
+            if (files.has(loc.toLowerCase())) {
+              possibleExtraneous.delete(loc);
+            }
+          }
+
+          return actions;
+        });
+
+        return function buildActionsForHardlink(_x6, _x7, _x8, _x9) {
+          return _ref9.apply(this, arguments);
+        };
+      })();
+
+      let copyBulk = (exports.copyBulk = (() => {
+        var _ref17 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (
+          queue,
+          reporter,
+          _events
+        ) {
+          const events = {
+            onStart: (_events && _events.onStart) || noop,
+            onProgress: (_events && _events.onProgress) || noop,
+            possibleExtraneous: _events ? _events.possibleExtraneous : new Set(),
+            ignoreBasenames: (_events && _events.ignoreBasenames) || [],
+            artifactFiles: (_events && _events.artifactFiles) || [],
+          };
+
+          const actions = yield buildActionsForCopy(queue, events, events.possibleExtraneous, reporter);
+          events.onStart(actions.file.length + actions.symlink.length + actions.link.length);
+
+          const fileActions = actions.file;
+
+          const currentlyWriting = new Map();
+
+          yield (_promise || _load_promise()).queue(
+            fileActions,
+            (() => {
+              var _ref18 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) {
+                let writePromise;
+                while ((writePromise = currentlyWriting.get(data.dest))) {
+                  yield writePromise;
+                }
+
+                reporter.verbose(reporter.lang('verboseFileCopy', data.src, data.dest));
+                const copier = (0, (_fsNormalized || _load_fsNormalized()).copyFile)(data, function () {
+                  return currentlyWriting.delete(data.dest);
+                });
+                currentlyWriting.set(data.dest, copier);
+                events.onProgress(data.dest);
+                return copier;
+              });
+
+              return function (_x14) {
+                return _ref18.apply(this, arguments);
+              };
+            })(),
+            CONCURRENT_QUEUE_ITEMS
+          );
+
+          // we need to copy symlinks last as they could reference files we were copying
+          const symlinkActions = actions.symlink;
+          yield (_promise || _load_promise()).queue(symlinkActions, function (data) {
+            const linkname = (_path || _load_path()).default.resolve(
+              (_path || _load_path()).default.dirname(data.dest),
+              data.linkname
+            );
+            reporter.verbose(reporter.lang('verboseFileSymlink', data.dest, linkname));
+            return symlink(linkname, data.dest);
+          });
+        });
+
+        return function copyBulk(_x11, _x12, _x13) {
+          return _ref17.apply(this, arguments);
+        };
+      })());
+
+      let hardlinkBulk = (exports.hardlinkBulk = (() => {
+        var _ref19 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (
+          queue,
+          reporter,
+          _events
+        ) {
+          const events = {
+            onStart: (_events && _events.onStart) || noop,
+            onProgress: (_events && _events.onProgress) || noop,
+            possibleExtraneous: _events ? _events.possibleExtraneous : new Set(),
+            artifactFiles: (_events && _events.artifactFiles) || [],
+            ignoreBasenames: [],
+          };
+
+          const actions = yield buildActionsForHardlink(queue, events, events.possibleExtraneous, reporter);
+          events.onStart(actions.file.length + actions.symlink.length + actions.link.length);
+
+          const fileActions = actions.link;
+
+          yield (_promise || _load_promise()).queue(
+            fileActions,
+            (() => {
+              var _ref20 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) {
+                reporter.verbose(reporter.lang('verboseFileLink', data.src, data.dest));
+                if (data.removeDest) {
+                  yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(data.dest);
+                }
+                yield link(data.src, data.dest);
+              });
+
+              return function (_x18) {
+                return _ref20.apply(this, arguments);
+              };
+            })(),
+            CONCURRENT_QUEUE_ITEMS
+          );
+
+          // we need to copy symlinks last as they could reference files we were copying
+          const symlinkActions = actions.symlink;
+          yield (_promise || _load_promise()).queue(symlinkActions, function (data) {
+            const linkname = (_path || _load_path()).default.resolve(
+              (_path || _load_path()).default.dirname(data.dest),
+              data.linkname
+            );
+            reporter.verbose(reporter.lang('verboseFileSymlink', data.dest, linkname));
+            return symlink(linkname, data.dest);
+          });
+        });
+
+        return function hardlinkBulk(_x15, _x16, _x17) {
+          return _ref19.apply(this, arguments);
+        };
+      })());
+
+      let readFileAny = (exports.readFileAny = (() => {
+        var _ref21 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (files) {
+          for (
+            var _iterator13 = files,
+              _isArray13 = Array.isArray(_iterator13),
+              _i13 = 0,
+              _iterator13 = _isArray13 ? _iterator13 : _iterator13[Symbol.iterator]();
+            ;
+
+          ) {
+            var _ref22;
+
+            if (_isArray13) {
+              if (_i13 >= _iterator13.length) break;
+              _ref22 = _iterator13[_i13++];
+            } else {
+              _i13 = _iterator13.next();
+              if (_i13.done) break;
+              _ref22 = _i13.value;
+            }
+
+            const file = _ref22;
+
+            if (yield exists(file)) {
+              return readFile(file);
+            }
+          }
+          return null;
+        });
+
+        return function readFileAny(_x19) {
+          return _ref21.apply(this, arguments);
+        };
+      })());
+
+      let readJson = (exports.readJson = (() => {
+        var _ref23 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (loc) {
+          return (yield readJsonAndFile(loc)).object;
+        });
+
+        return function readJson(_x20) {
+          return _ref23.apply(this, arguments);
+        };
+      })());
+
+      let readJsonAndFile = (exports.readJsonAndFile = (() => {
+        var _ref24 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (loc) {
+          const file = yield readFile(loc);
+          try {
+            return {
+              object: (0, (_map || _load_map()).default)(JSON.parse(stripBOM(file))),
+              content: file,
+            };
+          } catch (err) {
+            err.message = `${loc}: ${err.message}`;
+            throw err;
+          }
+        });
+
+        return function readJsonAndFile(_x21) {
+          return _ref24.apply(this, arguments);
+        };
+      })());
+
+      let find = (exports.find = (() => {
+        var _ref25 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (filename, dir) {
+          const parts = dir.split((_path || _load_path()).default.sep);
+
+          while (parts.length) {
+            const loc = parts.concat(filename).join((_path || _load_path()).default.sep);
+
+            if (yield exists(loc)) {
+              return loc;
+            } else {
+              parts.pop();
+            }
+          }
+
+          return false;
+        });
+
+        return function find(_x22, _x23) {
+          return _ref25.apply(this, arguments);
+        };
+      })());
+
+      let symlink = (exports.symlink = (() => {
+        var _ref26 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (src, dest) {
+          if (process.platform !== 'win32') {
+            // use relative paths otherwise which will be retained if the directory is moved
+            src = (_path || _load_path()).default.relative(
+              (_path || _load_path()).default.dirname(dest),
+              src
+            );
+            // When path.relative returns an empty string for the current directory, we should instead use
+            // '.', which is a valid fs.symlink target.
+            src = src || '.';
+          }
+
+          try {
+            const stats = yield lstat(dest);
+            if (stats.isSymbolicLink()) {
+              const resolved = dest;
+              if (resolved === src) {
+                return;
+              }
+            }
+          } catch (err) {
+            if (err.code !== 'ENOENT') {
+              throw err;
+            }
+          }
+
+          // We use rimraf for unlink which never throws an ENOENT on missing target
+          yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(dest);
+
+          if (process.platform === 'win32') {
+            // use directory junctions if possible on win32, this requires absolute paths
+            yield fsSymlink(src, dest, 'junction');
+          } else {
+            yield fsSymlink(src, dest);
+          }
+        });
+
+        return function symlink(_x24, _x25) {
+          return _ref26.apply(this, arguments);
+        };
+      })());
+
+      let walk = (exports.walk = (() => {
+        var _ref27 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (
+          dir,
+          relativeDir,
+          ignoreBasenames = new Set()
+        ) {
+          let files = [];
+
+          let filenames = yield readdir(dir);
+          if (ignoreBasenames.size) {
+            filenames = filenames.filter(function (name) {
+              return !ignoreBasenames.has(name);
+            });
+          }
+
+          for (
+            var _iterator14 = filenames,
+              _isArray14 = Array.isArray(_iterator14),
+              _i14 = 0,
+              _iterator14 = _isArray14 ? _iterator14 : _iterator14[Symbol.iterator]();
+            ;
+
+          ) {
+            var _ref28;
+
+            if (_isArray14) {
+              if (_i14 >= _iterator14.length) break;
+              _ref28 = _iterator14[_i14++];
+            } else {
+              _i14 = _iterator14.next();
+              if (_i14.done) break;
+              _ref28 = _i14.value;
+            }
+
+            const name = _ref28;
+
+            const relative = relativeDir ? (_path || _load_path()).default.join(relativeDir, name) : name;
+            const loc = (_path || _load_path()).default.join(dir, name);
+            const stat = yield lstat(loc);
+
+            files.push({
+              relative,
+              basename: name,
+              absolute: loc,
+              mtime: +stat.mtime,
+            });
+
+            if (stat.isDirectory()) {
+              files = files.concat(yield walk(loc, relative, ignoreBasenames));
+            }
+          }
+
+          return files;
+        });
+
+        return function walk(_x26, _x27) {
+          return _ref27.apply(this, arguments);
+        };
+      })());
+
+      let getFileSizeOnDisk = (exports.getFileSizeOnDisk = (() => {
+        var _ref29 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (loc) {
+          const stat = yield lstat(loc);
+          const size = stat.size,
+            blockSize = stat.blksize;
+
+          return Math.ceil(size / blockSize) * blockSize;
+        });
+
+        return function getFileSizeOnDisk(_x28) {
+          return _ref29.apply(this, arguments);
+        };
+      })());
+
+      let getEolFromFile = (() => {
+        var _ref30 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (path) {
+          if (!(yield exists(path))) {
+            return undefined;
+          }
+
+          const buffer = yield readFileBuffer(path);
+
+          for (let i = 0; i < buffer.length; ++i) {
+            if (buffer[i] === cr) {
+              return '\r\n';
+            }
+            if (buffer[i] === lf) {
+              return '\n';
+            }
+          }
+          return undefined;
+        });
+
+        return function getEolFromFile(_x29) {
+          return _ref30.apply(this, arguments);
+        };
+      })();
+
+      let writeFilePreservingEol = (exports.writeFilePreservingEol = (() => {
+        var _ref31 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (path, data) {
+          const eol = (yield getEolFromFile(path)) || (_os || _load_os()).default.EOL;
+          if (eol !== '\n') {
+            data = data.replace(/\n/g, eol);
+          }
+          yield writeFile(path, data);
+        });
+
+        return function writeFilePreservingEol(_x30, _x31) {
+          return _ref31.apply(this, arguments);
+        };
+      })());
+
+      let hardlinksWork = (exports.hardlinksWork = (() => {
+        var _ref32 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (dir) {
+          const filename = 'test-file' + Math.random();
+          const file = (_path || _load_path()).default.join(dir, filename);
+          const fileLink = (_path || _load_path()).default.join(dir, filename + '-link');
+          try {
+            yield writeFile(file, 'test');
+            yield link(file, fileLink);
+          } catch (err) {
+            return false;
+          } finally {
+            yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(file);
+            yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(fileLink);
+          }
+          return true;
+        });
+
+        return function hardlinksWork(_x32) {
+          return _ref32.apply(this, arguments);
+        };
+      })());
+
+      // not a strict polyfill for Node's fs.mkdtemp
+
+      let makeTempDir = (exports.makeTempDir = (() => {
+        var _ref33 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (prefix) {
+          const dir = (_path || _load_path()).default.join(
+            (_os || _load_os()).default.tmpdir(),
+            `yarn-${prefix || ''}-${Date.now()}-${Math.random()}`
+          );
+          yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(dir);
+          yield mkdirp(dir);
+          return dir;
+        });
+
+        return function makeTempDir(_x33) {
+          return _ref33.apply(this, arguments);
+        };
+      })());
+
+      let readFirstAvailableStream = (exports.readFirstAvailableStream = (() => {
+        var _ref34 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (paths) {
+          for (
+            var _iterator15 = paths,
+              _isArray15 = Array.isArray(_iterator15),
+              _i15 = 0,
+              _iterator15 = _isArray15 ? _iterator15 : _iterator15[Symbol.iterator]();
+            ;
+
+          ) {
+            var _ref35;
+
+            if (_isArray15) {
+              if (_i15 >= _iterator15.length) break;
+              _ref35 = _iterator15[_i15++];
+            } else {
+              _i15 = _iterator15.next();
+              if (_i15.done) break;
+              _ref35 = _i15.value;
+            }
+
+            const path = _ref35;
+
+            try {
+              const fd = yield open(path, 'r');
+              return (_fs || _load_fs()).default.createReadStream(path, { fd });
+            } catch (err) {
+              // Try the next one
+            }
+          }
+          return null;
+        });
+
+        return function readFirstAvailableStream(_x34) {
+          return _ref34.apply(this, arguments);
+        };
+      })());
+
+      let getFirstSuitableFolder = (exports.getFirstSuitableFolder = (() => {
+        var _ref36 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (
+          paths,
+          mode = constants.W_OK | constants.X_OK
+        ) {
+          const result = {
+            skipped: [],
+            folder: null,
+          };
+
+          for (
+            var _iterator16 = paths,
+              _isArray16 = Array.isArray(_iterator16),
+              _i16 = 0,
+              _iterator16 = _isArray16 ? _iterator16 : _iterator16[Symbol.iterator]();
+            ;
+
+          ) {
+            var _ref37;
+
+            if (_isArray16) {
+              if (_i16 >= _iterator16.length) break;
+              _ref37 = _iterator16[_i16++];
+            } else {
+              _i16 = _iterator16.next();
+              if (_i16.done) break;
+              _ref37 = _i16.value;
+            }
+
+            const folder = _ref37;
+
+            try {
+              yield mkdirp(folder);
+              yield access(folder, mode);
+
+              result.folder = folder;
+
+              return result;
+            } catch (error) {
+              result.skipped.push({
+                error,
+                folder,
+              });
+            }
+          }
+          return result;
+        });
+
+        return function getFirstSuitableFolder(_x35) {
+          return _ref36.apply(this, arguments);
+        };
+      })());
+
+      exports.copy = copy;
+      exports.readFile = readFile;
+      exports.readFileRaw = readFileRaw;
+      exports.normalizeOS = normalizeOS;
+
+      var _fs;
+
+      function _load_fs() {
+        return (_fs = _interopRequireDefault(__webpack_require__(4)));
+      }
+
+      var _glob;
+
+      function _load_glob() {
+        return (_glob = _interopRequireDefault(__webpack_require__(99)));
+      }
+
+      var _os;
+
+      function _load_os() {
+        return (_os = _interopRequireDefault(__webpack_require__(46)));
+      }
+
+      var _path;
+
+      function _load_path() {
+        return (_path = _interopRequireDefault(__webpack_require__(0)));
+      }
+
+      var _blockingQueue;
+
+      function _load_blockingQueue() {
+        return (_blockingQueue = _interopRequireDefault(__webpack_require__(110)));
+      }
+
+      var _promise;
+
+      function _load_promise() {
+        return (_promise = _interopRequireWildcard(__webpack_require__(51)));
+      }
+
+      var _promise2;
+
+      function _load_promise2() {
+        return (_promise2 = __webpack_require__(51));
+      }
+
+      var _map;
+
+      function _load_map() {
+        return (_map = _interopRequireDefault(__webpack_require__(29)));
+      }
+
+      var _fsNormalized;
+
+      function _load_fsNormalized() {
+        return (_fsNormalized = __webpack_require__(216));
+      }
+
+      function _interopRequireWildcard(obj) {
+        if (obj && obj.__esModule) {
+          return obj;
+        } else {
+          var newObj = {};
+          if (obj != null) {
+            for (var key in obj) {
+              if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key];
+            }
+          }
+          newObj.default = obj;
+          return newObj;
+        }
+      }
+
+      function _interopRequireDefault(obj) {
+        return obj && obj.__esModule ? obj : { default: obj };
+      }
+
+      const constants = (exports.constants =
+        typeof (_fs || _load_fs()).default.constants !== 'undefined'
+          ? (_fs || _load_fs()).default.constants
+          : {
+              R_OK: (_fs || _load_fs()).default.R_OK,
+              W_OK: (_fs || _load_fs()).default.W_OK,
+              X_OK: (_fs || _load_fs()).default.X_OK,
+            });
+
+      const lockQueue = (exports.lockQueue = new (_blockingQueue || _load_blockingQueue()).default(
+        'fs lock'
+      ));
+
+      const readFileBuffer = (exports.readFileBuffer = (0, (_promise2 || _load_promise2()).promisify)(
+        (_fs || _load_fs()).default.readFile
+      ));
+      const open = (exports.open = (0, (_promise2 || _load_promise2()).promisify)(
+        (_fs || _load_fs()).default.open
+      ));
+      const writeFile = (exports.writeFile = (0, (_promise2 || _load_promise2()).promisify)(
+        (_fs || _load_fs()).default.writeFile
+      ));
+      const readlink = (exports.readlink = (0, (_promise2 || _load_promise2()).promisify)(
+        (_fs || _load_fs()).default.readlink
+      ));
+      const realpath = (exports.realpath = (0, (_promise2 || _load_promise2()).promisify)(
+        (_fs || _load_fs()).default.realpath
+      ));
+      const readdir = (exports.readdir = (0, (_promise2 || _load_promise2()).promisify)(
+        (_fs || _load_fs()).default.readdir
+      ));
+      const rename = (exports.rename = (0, (_promise2 || _load_promise2()).promisify)(
+        (_fs || _load_fs()).default.rename
+      ));
+      const access = (exports.access = (0, (_promise2 || _load_promise2()).promisify)(
+        (_fs || _load_fs()).default.access
+      ));
+      const stat = (exports.stat = (0, (_promise2 || _load_promise2()).promisify)(
+        (_fs || _load_fs()).default.stat
+      ));
+      const mkdirp = (exports.mkdirp = (0, (_promise2 || _load_promise2()).promisify)(
+        __webpack_require__(145)
+      ));
+      const exists = (exports.exists = (0, (_promise2 || _load_promise2()).promisify)(
+        (_fs || _load_fs()).default.exists,
+        true
+      ));
+      const lstat = (exports.lstat = (0, (_promise2 || _load_promise2()).promisify)(
+        (_fs || _load_fs()).default.lstat
+      ));
+      const chmod = (exports.chmod = (0, (_promise2 || _load_promise2()).promisify)(
+        (_fs || _load_fs()).default.chmod
+      ));
+      const link = (exports.link = (0, (_promise2 || _load_promise2()).promisify)(
+        (_fs || _load_fs()).default.link
+      ));
+      const glob = (exports.glob = (0, (_promise2 || _load_promise2()).promisify)(
+        (_glob || _load_glob()).default
+      ));
+      exports.unlink = (_fsNormalized || _load_fsNormalized()).unlink;
+
+      // fs.copyFile uses the native file copying instructions on the system, performing much better
+      // than any JS-based solution and consumes fewer resources. Repeated testing to fine tune the
+      // concurrency level revealed 128 as the sweet spot on a quad-core, 16 CPU Intel system with SSD.
+
+      const CONCURRENT_QUEUE_ITEMS = (_fs || _load_fs()).default.copyFile ? 128 : 4;
+
+      const fsSymlink = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.symlink);
+      const invariant = __webpack_require__(9);
+      const stripBOM = __webpack_require__(160);
+
+      const noop = () => {};
+
+      function copy(src, dest, reporter) {
+        return copyBulk([{ src, dest }], reporter);
+      }
+
+      function _readFile(loc, encoding) {
+        return new Promise((resolve, reject) => {
+          (_fs || _load_fs()).default.readFile(loc, encoding, function (err, content) {
+            if (err) {
+              reject(err);
+            } else {
+              resolve(content);
+            }
+          });
+        });
+      }
+
+      function readFile(loc) {
+        return _readFile(loc, 'utf8').then(normalizeOS);
+      }
+
+      function readFileRaw(loc) {
+        return _readFile(loc, 'binary');
+      }
+
+      function normalizeOS(body) {
+        return body.replace(/\r\n/g, '\n');
+      }
+
+      const cr = '\r'.charCodeAt(0);
+      const lf = '\n'.charCodeAt(0);
+
+      /***/
+    },
+    /* 6 */
+    /***/ function (module, exports, __webpack_require__) {
+      'use strict';
+
+      Object.defineProperty(exports, '__esModule', {
+        value: true,
+      });
+      class MessageError extends Error {
+        constructor(msg, code) {
+          super(msg);
+          this.code = code;
+        }
+      }
+
+      exports.MessageError = MessageError;
+      class ProcessSpawnError extends MessageError {
+        constructor(msg, code, process) {
+          super(msg, code);
+          this.process = process;
+        }
+      }
+
+      exports.ProcessSpawnError = ProcessSpawnError;
+      class SecurityError extends MessageError {}
+
+      exports.SecurityError = SecurityError;
+      class ProcessTermError extends MessageError {}
+
+      exports.ProcessTermError = ProcessTermError;
+      class ResponseError extends Error {
+        constructor(msg, responseCode) {
+          super(msg);
+          this.responseCode = responseCode;
+        }
+      }
+
+      exports.ResponseError = ResponseError;
+      class OneTimePasswordError extends Error {
+        constructor(notice) {
+          super();
+          this.notice = notice;
+        }
+      }
+      exports.OneTimePasswordError = OneTimePasswordError;
+
+      /***/
+    },
+    /* 7 */
+    /***/ function (module, __webpack_exports__, __webpack_require__) {
+      'use strict';
+      /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, 'a', function () {
+        return Subscriber;
+      });
+      /* unused harmony export SafeSubscriber */
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_isFunction__ = __webpack_require__(154);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Observer__ = __webpack_require__(420);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Subscription__ = __webpack_require__(25);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__internal_symbol_rxSubscriber__ =
+        __webpack_require__(321);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__config__ = __webpack_require__(186);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__util_hostReportError__ = __webpack_require__(323);
+      /** PURE_IMPORTS_START tslib,_util_isFunction,_Observer,_Subscription,_internal_symbol_rxSubscriber,_config,_util_hostReportError PURE_IMPORTS_END */
+
+      var Subscriber = /*@__PURE__*/ (function (_super) {
+        __WEBPACK_IMPORTED_MODULE_0_tslib__['a' /* __extends */](Subscriber, _super);
+        function Subscriber(destinationOrNext, error, complete) {
+          var _this = _super.call(this) || this;
+          _this.syncErrorValue = null;
+          _this.syncErrorThrown = false;
+          _this.syncErrorThrowable = false;
+          _this.isStopped = false;
+          _this._parentSubscription = null;
+          switch (arguments.length) {
+            case 0:
+              _this.destination = __WEBPACK_IMPORTED_MODULE_2__Observer__['a' /* empty */];
+              break;
+            case 1:
+              if (!destinationOrNext) {
+                _this.destination = __WEBPACK_IMPORTED_MODULE_2__Observer__['a' /* empty */];
+                break;
+              }
+              if (typeof destinationOrNext === 'object') {
+                if (destinationOrNext instanceof Subscriber) {
+                  _this.syncErrorThrowable = destinationOrNext.syncErrorThrowable;
+                  _this.destination = destinationOrNext;
+                  destinationOrNext.add(_this);
+                } else {
+                  _this.syncErrorThrowable = true;
+                  _this.destination = new SafeSubscriber(_this, destinationOrNext);
+                }
+                break;
+              }
+            default:
+              _this.syncErrorThrowable = true;
+              _this.destination = new SafeSubscriber(_this, destinationOrNext, error, complete);
+              break;
+          }
+          return _this;
+        }
+        Subscriber.prototype[
+          __WEBPACK_IMPORTED_MODULE_4__internal_symbol_rxSubscriber__['a' /* rxSubscriber */]
+        ] = function () {
+          return this;
+        };
+        Subscriber.create = function (next, error, complete) {
+          var subscriber = new Subscriber(next, error, complete);
+          subscriber.syncErrorThrowable = false;
+          return subscriber;
+        };
+        Subscriber.prototype.next = function (value) {
+          if (!this.isStopped) {
+            this._next(value);
+          }
+        };
+        Subscriber.prototype.error = function (err) {
+          if (!this.isStopped) {
+            this.isStopped = true;
+            this._error(err);
+          }
+        };
+        Subscriber.prototype.complete = function () {
+          if (!this.isStopped) {
+            this.isStopped = true;
+            this._complete();
+          }
+        };
+        Subscriber.prototype.unsubscribe = function () {
+          if (this.closed) {
+            return;
+          }
+          this.isStopped = true;
+          _super.prototype.unsubscribe.call(this);
+        };
+        Subscriber.prototype._next = function (value) {
+          this.destination.next(value);
+        };
+        Subscriber.prototype._error = function (err) {
+          this.destination.error(err);
+          this.unsubscribe();
+        };
+        Subscriber.prototype._complete = function () {
+          this.destination.complete();
+          this.unsubscribe();
+        };
+        Subscriber.prototype._unsubscribeAndRecycle = function () {
+          var _a = this,
+            _parent = _a._parent,
+            _parents = _a._parents;
+          this._parent = null;
+          this._parents = null;
+          this.unsubscribe();
+          this.closed = false;
+          this.isStopped = false;
+          this._parent = _parent;
+          this._parents = _parents;
+          this._parentSubscription = null;
+          return this;
+        };
+        return Subscriber;
+      })(__WEBPACK_IMPORTED_MODULE_3__Subscription__['a' /* Subscription */]);
+
+      var SafeSubscriber = /*@__PURE__*/ (function (_super) {
+        __WEBPACK_IMPORTED_MODULE_0_tslib__['a' /* __extends */](SafeSubscriber, _super);
+        function SafeSubscriber(_parentSubscriber, observerOrNext, error, complete) {
+          var _this = _super.call(this) || this;
+          _this._parentSubscriber = _parentSubscriber;
+          var next;
+          var context = _this;
+          if (
+            __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_isFunction__['a' /* isFunction */])(
+              observerOrNext
+            )
+          ) {
+            next = observerOrNext;
+          } else if (observerOrNext) {
+            next = observerOrNext.next;
+            error = observerOrNext.error;
+            complete = observerOrNext.complete;
+            if (observerOrNext !== __WEBPACK_IMPORTED_MODULE_2__Observer__['a' /* empty */]) {
+              context = Object.create(observerOrNext);
+              if (
+                __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_isFunction__['a' /* isFunction */])(
+                  context.unsubscribe
+                )
+              ) {
+                _this.add(context.unsubscribe.bind(context));
+              }
+              context.unsubscribe = _this.unsubscribe.bind(_this);
+            }
+          }
+          _this._context = context;
+          _this._next = next;
+          _this._error = error;
+          _this._complete = complete;
+          return _this;
+        }
+        SafeSubscriber.prototype.next = function (value) {
+          if (!this.isStopped && this._next) {
+            var _parentSubscriber = this._parentSubscriber;
+            if (
+              !__WEBPACK_IMPORTED_MODULE_5__config__['a' /* config */]
+                .useDeprecatedSynchronousErrorHandling ||
+              !_parentSubscriber.syncErrorThrowable
+            ) {
+              this.__tryOrUnsub(this._next, value);
+            } else if (this.__tryOrSetError(_parentSubscriber, this._next, value)) {
+              this.unsubscribe();
+            }
+          }
+        };
+        SafeSubscriber.prototype.error = function (err) {
+          if (!this.isStopped) {
+            var _parentSubscriber = this._parentSubscriber;
+            var useDeprecatedSynchronousErrorHandling =
+              __WEBPACK_IMPORTED_MODULE_5__config__['a' /* config */].useDeprecatedSynchronousErrorHandling;
+            if (this._error) {
+              if (!useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) {
+                this.__tryOrUnsub(this._error, err);
+                this.unsubscribe();
+              } else {
+                this.__tryOrSetError(_parentSubscriber, this._error, err);
+                this.unsubscribe();
+              }
+            } else if (!_parentSubscriber.syncErrorThrowable) {
+              this.unsubscribe();
+              if (useDeprecatedSynchronousErrorHandling) {
+                throw err;
+              }
+              __webpack_require__.i(
+                __WEBPACK_IMPORTED_MODULE_6__util_hostReportError__['a' /* hostReportError */]
+              )(err);
+            } else {
+              if (useDeprecatedSynchronousErrorHandling) {
+                _parentSubscriber.syncErrorValue = err;
+                _parentSubscriber.syncErrorThrown = true;
+              } else {
+                __webpack_require__.i(
+                  __WEBPACK_IMPORTED_MODULE_6__util_hostReportError__['a' /* hostReportError */]
+                )(err);
+              }
+              this.unsubscribe();
+            }
+          }
+        };
+        SafeSubscriber.prototype.complete = function () {
+          var _this = this;
+          if (!this.isStopped) {
+            var _parentSubscriber = this._parentSubscriber;
+            if (this._complete) {
+              var wrappedComplete = function () {
+                return _this._complete.call(_this._context);
+              };
+              if (
+                !__WEBPACK_IMPORTED_MODULE_5__config__['a' /* config */]
+                  .useDeprecatedSynchronousErrorHandling ||
+                !_parentSubscriber.syncErrorThrowable
+              ) {
+                this.__tryOrUnsub(wrappedComplete);
+                this.unsubscribe();
+              } else {
+                this.__tryOrSetError(_parentSubscriber, wrappedComplete);
+                this.unsubscribe();
+              }
+            } else {
+              this.unsubscribe();
+            }
+          }
+        };
+        SafeSubscriber.prototype.__tryOrUnsub = function (fn, value) {
+          try {
+            fn.call(this._context, value);
+          } catch (err) {
+            this.unsubscribe();
+            if (
+              __WEBPACK_IMPORTED_MODULE_5__config__['a' /* config */].useDeprecatedSynchronousErrorHandling
+            ) {
+              throw err;
+            } else {
+              __webpack_require__.i(
+                __WEBPACK_IMPORTED_MODULE_6__util_hostReportError__['a' /* hostReportError */]
+              )(err);
+            }
+          }
+        };
+        SafeSubscriber.prototype.__tryOrSetError = function (parent, fn, value) {
+          if (
+            !__WEBPACK_IMPORTED_MODULE_5__config__['a' /* config */].useDeprecatedSynchronousErrorHandling
+          ) {
+            throw new Error('bad call');
+          }
+          try {
+            fn.call(this._context, value);
+          } catch (err) {
+            if (
+              __WEBPACK_IMPORTED_MODULE_5__config__['a' /* config */].useDeprecatedSynchronousErrorHandling
+            ) {
+              parent.syncErrorValue = err;
+              parent.syncErrorThrown = true;
+              return true;
+            } else {
+              __webpack_require__.i(
+                __WEBPACK_IMPORTED_MODULE_6__util_hostReportError__['a' /* hostReportError */]
+              )(err);
+              return true;
+            }
+          }
+          return false;
+        };
+        SafeSubscriber.prototype._unsubscribe = function () {
+          var _parentSubscriber = this._parentSubscriber;
+          this._context = null;
+          this._parentSubscriber = null;
+          _parentSubscriber.unsubscribe();
+        };
+        return SafeSubscriber;
+      })(Subscriber);
+
+      //# sourceMappingURL=Subscriber.js.map
+
+      /***/
+    },
+    /* 8 */
+    /***/ function (module, exports, __webpack_require__) {
+      'use strict';
+
+      Object.defineProperty(exports, '__esModule', {
+        value: true,
+      });
+      exports.getPathKey = getPathKey;
+      const os = __webpack_require__(46);
+      const path = __webpack_require__(0);
+      const userHome = __webpack_require__(67).default;
+
+      var _require = __webpack_require__(222);
+
+      const getCacheDir = _require.getCacheDir,
+        getConfigDir = _require.getConfigDir,
+        getDataDir = _require.getDataDir;
+
+      const isWebpackBundle = __webpack_require__(278);
+
+      const DEPENDENCY_TYPES = (exports.DEPENDENCY_TYPES = [
+        'devDependencies',
+        'dependencies',
+        'optionalDependencies',
+        'peerDependencies',
+      ]);
+      const OWNED_DEPENDENCY_TYPES = (exports.OWNED_DEPENDENCY_TYPES = [
+        'devDependencies',
+        'dependencies',
+        'optionalDependencies',
+      ]);
+
+      const RESOLUTIONS = (exports.RESOLUTIONS = 'resolutions');
+      const MANIFEST_FIELDS = (exports.MANIFEST_FIELDS = [RESOLUTIONS, ...DEPENDENCY_TYPES]);
+
+      const SUPPORTED_NODE_VERSIONS = (exports.SUPPORTED_NODE_VERSIONS =
+        '^4.8.0 || ^5.7.0 || ^6.2.2 || >=8.0.0');
+
+      const YARN_REGISTRY = (exports.YARN_REGISTRY = 'https://registry.yarnpkg.com');
+      const NPM_REGISTRY_RE = (exports.NPM_REGISTRY_RE = /https?:\/\/registry\.npmjs\.org/g);
+
+      const YARN_DOCS = (exports.YARN_DOCS = 'https://yarnpkg.com/en/docs/cli/');
+      const YARN_INSTALLER_SH = (exports.YARN_INSTALLER_SH = 'https://yarnpkg.com/install.sh');
+      const YARN_INSTALLER_MSI = (exports.YARN_INSTALLER_MSI = 'https://yarnpkg.com/latest.msi');
+
+      const SELF_UPDATE_VERSION_URL = (exports.SELF_UPDATE_VERSION_URL =
+        'https://yarnpkg.com/latest-version');
+
+      // cache version, bump whenever we make backwards incompatible changes
+      const CACHE_VERSION = (exports.CACHE_VERSION = 6);
+
+      // lockfile version, bump whenever we make backwards incompatible changes
+      const LOCKFILE_VERSION = (exports.LOCKFILE_VERSION = 1);
+
+      // max amount of network requests to perform concurrently
+      const NETWORK_CONCURRENCY = (exports.NETWORK_CONCURRENCY = 8);
+
+      // HTTP timeout used when downloading packages
+      const NETWORK_TIMEOUT = (exports.NETWORK_TIMEOUT = 30 * 1000); // in milliseconds
+
+      // max amount of child processes to execute concurrently
+      const CHILD_CONCURRENCY = (exports.CHILD_CONCURRENCY = 5);
+
+      const REQUIRED_PACKAGE_KEYS = (exports.REQUIRED_PACKAGE_KEYS = ['name', 'version', '_uid']);
+
+      function getPreferredCacheDirectories() {
+        const preferredCacheDirectories = [getCacheDir()];
+
+        if (process.getuid) {
+          // $FlowFixMe: process.getuid exists, dammit
+          preferredCacheDirectories.push(path.join(os.tmpdir(), `.yarn-cache-${process.getuid()}`));
+        }
+
+        preferredCacheDirectories.push(path.join(os.tmpdir(), `.yarn-cache`));
+
+        return preferredCacheDirectories;
+      }
+
+      const PREFERRED_MODULE_CACHE_DIRECTORIES = (exports.PREFERRED_MODULE_CACHE_DIRECTORIES =
+        getPreferredCacheDirectories());
+      const CONFIG_DIRECTORY = (exports.CONFIG_DIRECTORY = getConfigDir());
+      const DATA_DIRECTORY = (exports.DATA_DIRECTORY = getDataDir());
+      const LINK_REGISTRY_DIRECTORY = (exports.LINK_REGISTRY_DIRECTORY = path.join(DATA_DIRECTORY, 'link'));
+      const GLOBAL_MODULE_DIRECTORY = (exports.GLOBAL_MODULE_DIRECTORY = path.join(DATA_DIRECTORY, 'global'));
+
+      const NODE_BIN_PATH = (exports.NODE_BIN_PATH = process.execPath);
+      const YARN_BIN_PATH = (exports.YARN_BIN_PATH = getYarnBinPath());
+
+      // Webpack needs to be configured with node.__dirname/__filename = false
+      function getYarnBinPath() {
+        if (isWebpackBundle) {
+          return __filename;
+        } else {
+          return path.join(__dirname, '..', 'bin', 'yarn.js');
+        }
+      }
+
+      const NODE_MODULES_FOLDER = (exports.NODE_MODULES_FOLDER = 'node_modules');
+      const NODE_PACKAGE_JSON = (exports.NODE_PACKAGE_JSON = 'package.json');
+
+      const PNP_FILENAME = (exports.PNP_FILENAME = '.pnp.js');
+
+      const POSIX_GLOBAL_PREFIX = (exports.POSIX_GLOBAL_PREFIX = `${process.env.DESTDIR || ''}/usr/local`);
+      const FALLBACK_GLOBAL_PREFIX = (exports.FALLBACK_GLOBAL_PREFIX = path.join(userHome, '.yarn'));
+
+      const META_FOLDER = (exports.META_FOLDER = '.yarn-meta');
+      const INTEGRITY_FILENAME = (exports.INTEGRITY_FILENAME = '.yarn-integrity');
+      const LOCKFILE_FILENAME = (exports.LOCKFILE_FILENAME = 'yarn.lock');
+      const METADATA_FILENAME = (exports.METADATA_FILENAME = '.yarn-metadata.json');
+      const TARBALL_FILENAME = (exports.TARBALL_FILENAME = '.yarn-tarball.tgz');
+      const CLEAN_FILENAME = (exports.CLEAN_FILENAME = '.yarnclean');
+
+      const NPM_LOCK_FILENAME = (exports.NPM_LOCK_FILENAME = 'package-lock.json');
+      const NPM_SHRINKWRAP_FILENAME = (exports.NPM_SHRINKWRAP_FILENAME = 'npm-shrinkwrap.json');
+
+      const DEFAULT_INDENT = (exports.DEFAULT_INDENT = '  ');
+      const SINGLE_INSTANCE_PORT = (exports.SINGLE_INSTANCE_PORT = 31997);
+      const SINGLE_INSTANCE_FILENAME = (exports.SINGLE_INSTANCE_FILENAME = '.yarn-single-instance');
+
+      const ENV_PATH_KEY = (exports.ENV_PATH_KEY = getPathKey(process.platform, process.env));
+
+      function getPathKey(platform, env) {
+        let pathKey = 'PATH';
+
+        // windows calls its path "Path" usually, but this is not guaranteed.
+        if (platform === 'win32') {
+          pathKey = 'Path';
+
+          for (const key in env) {
+            if (key.toLowerCase() === 'path') {
+              pathKey = key;
+            }
+          }
+        }
+
+        return pathKey;
+      }
+
+      const VERSION_COLOR_SCHEME = (exports.VERSION_COLOR_SCHEME = {
+        major: 'red',
+        premajor: 'red',
+        minor: 'yellow',
+        preminor: 'yellow',
+        patch: 'green',
+        prepatch: 'green',
+        prerelease: 'red',
+        unchanged: 'white',
+        unknown: 'red',
+      });
+
+      /***/
+    },
+    /* 9 */
+    /***/ function (module, exports, __webpack_require__) {
+      'use strict';
+      /**
+       * Copyright (c) 2013-present, Facebook, Inc.
+       *
+       * This source code is licensed under the MIT license found in the
+       * LICENSE file in the root directory of this source tree.
+       */
+
+      /**
+       * Use invariant() to assert state which your program assumes to be true.
+       *
+       * Provide sprintf-style format (only %s is supported) and arguments
+       * to provide information about what broke and what you were
+       * expecting.
+       *
+       * The invariant message will be stripped in production, but the invariant
+       * will remain to ensure logic does not differ in production.
+       */
+
+      var NODE_ENV = process.env.NODE_ENV;
+
+      var invariant = function (condition, format, a, b, c, d, e, f) {
+        if (NODE_ENV !== 'production') {
+          if (format === undefined) {
+            throw new Error('invariant requires an error message argument');
+          }
+        }
+
+        if (!condition) {
+          var error;
+          if (format === undefined) {
+            error = new Error(
+              'Minified exception occurred; use the non-minified dev environment ' +
+                'for the full error message and additional helpful warnings.'
+            );
+          } else {
+            var args = [a, b, c, d, e, f];
+            var argIndex = 0;
+            error = new Error(
+              format.replace(/%s/g, function () {
+                return args[argIndex++];
+              })
+            );
+            error.name = 'Invariant Violation';
+          }
+
+          error.framesToPop = 1; // we don't care about invariant's own frame
+          throw error;
+        }
+      };
+
+      module.exports = invariant;
+
+      /***/
+    },
+    /* 10 */
+    /***/ function (module, exports, __webpack_require__) {
+      'use strict';
+
+      var YAMLException = __webpack_require__(55);
+
+      var TYPE_CONSTRUCTOR_OPTIONS = [
+        'kind',
+        'resolve',
+        'construct',
+        'instanceOf',
+        'predicate',
+        'represent',
+        'defaultStyle',
+        'styleAliases',
+      ];
+
+      var YAML_NODE_KINDS = ['scalar', 'sequence', 'mapping'];
+
+      function compileStyleAliases(map) {
+        var result = {};
+
+        if (map !== null) {
+          Object.keys(map).forEach(function (style) {
+            map[style].forEach(function (alias) {
+              result[String(alias)] = style;
+            });
+          });
+        }
+
+        return result;
+      }
+
+      function Type(tag, options) {
+        options = options || {};
+
+        Object.keys(options).forEach(function (name) {
+          if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name) === -1) {
+            throw new YAMLException(
+              'Unknown option "' + name + '" is met in definition of "' + tag + '" YAML type.'
+            );
+          }
+        });
+
+        // TODO: Add tag format check.
+        this.tag = tag;
+        this.kind = options['kind'] || null;
+        this.resolve =
+          options['resolve'] ||
+          function () {
+            return true;
+          };
+        this.construct =
+          options['construct'] ||
+          function (data) {
+            return data;
+          };
+        this.instanceOf = options['instanceOf'] || null;
+        this.predicate = options['predicate'] || null;
+        this.represent = options['represent'] || null;
+        this.defaultStyle = options['defaultStyle'] || null;
+        this.styleAliases = compileStyleAliases(options['styleAliases'] || null);
+
+        if (YAML_NODE_KINDS.indexOf(this.kind) === -1) {
+          throw new YAMLException(
+            'Unknown kind "' + this.kind + '" is specified for "' + tag + '" YAML type.'
+          );
+        }
+      }
+
+      module.exports = Type;
+
+      /***/
+    },
+    /* 11 */
+    /***/ function (module, exports) {
+      module.exports = require('crypto');
+
+      /***/
+    },
+    /* 12 */
+    /***/ function (module, __webpack_exports__, __webpack_require__) {
+      'use strict';
+      /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, 'a', function () {
+        return Observable;
+      });
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__util_canReportError__ = __webpack_require__(322);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_toSubscriber__ = __webpack_require__(932);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__internal_symbol_observable__ =
+        __webpack_require__(118);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__util_pipe__ = __webpack_require__(324);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__config__ = __webpack_require__(186);
+      /** PURE_IMPORTS_START _util_canReportError,_util_toSubscriber,_internal_symbol_observable,_util_pipe,_config PURE_IMPORTS_END */
+
+      var Observable = /*@__PURE__*/ (function () {
+        function Observable(subscribe) {
+          this._isScalar = false;
+          if (subscribe) {
+            this._subscribe = subscribe;
+          }
+        }
+        Observable.prototype.lift = function (operator) {
+          var observable = new Observable();
+          observable.source = this;
+          observable.operator = operator;
+          return observable;
+        };
+        Observable.prototype.subscribe = function (observerOrNext, error, complete) {
+          var operator = this.operator;
+          var sink = __webpack_require__.i(
+            __WEBPACK_IMPORTED_MODULE_1__util_toSubscriber__['a' /* toSubscriber */]
+          )(observerOrNext, error, complete);
+          if (operator) {
+            operator.call(sink, this.source);
+          } else {
+            sink.add(
+              this.source ||
+                (__WEBPACK_IMPORTED_MODULE_4__config__['a' /* config */]
+                  .useDeprecatedSynchronousErrorHandling &&
+                  !sink.syncErrorThrowable)
+                ? this._subscribe(sink)
+                : this._trySubscribe(sink)
+            );
+          }
+          if (__WEBPACK_IMPORTED_MODULE_4__config__['a' /* config */].useDeprecatedSynchronousErrorHandling) {
+            if (sink.syncErrorThrowable) {
+              sink.syncErrorThrowable = false;
+              if (sink.syncErrorThrown) {
+                throw sink.syncErrorValue;
+              }
+            }
+          }
+          return sink;
+        };
+        Observable.prototype._trySubscribe = function (sink) {
+          try {
+            return this._subscribe(sink);
+          } catch (err) {
+            if (
+              __WEBPACK_IMPORTED_MODULE_4__config__['a' /* config */].useDeprecatedSynchronousErrorHandling
+            ) {
+              sink.syncErrorThrown = true;
+              sink.syncErrorValue = err;
+            }
+            if (
+              __webpack_require__.i(
+                __WEBPACK_IMPORTED_MODULE_0__util_canReportError__['a' /* canReportError */]
+              )(sink)
+            ) {
+              sink.error(err);
+            } else {
+              console.warn(err);
+            }
+          }
+        };
+        Observable.prototype.forEach = function (next, promiseCtor) {
+          var _this = this;
+          promiseCtor = getPromiseCtor(promiseCtor);
+          return new promiseCtor(function (resolve, reject) {
+            var subscription;
+            subscription = _this.subscribe(
+              function (value) {
+                try {
+                  next(value);
+                } catch (err) {
+                  reject(err);
+                  if (subscription) {
+                    subscription.unsubscribe();
+                  }
+                }
+              },
+              reject,
+              resolve
+            );
+          });
+        };
+        Observable.prototype._subscribe = function (subscriber) {
+          var source = this.source;
+          return source && source.subscribe(subscriber);
+        };
+        Observable.prototype[
+          __WEBPACK_IMPORTED_MODULE_2__internal_symbol_observable__['a' /* observable */]
+        ] = function () {
+          return this;
+        };
+        Observable.prototype.pipe = function () {
+          var operations = [];
+          for (var _i = 0; _i < arguments.length; _i++) {
+            operations[_i] = arguments[_i];
+          }
+          if (operations.length === 0) {
+            return this;
+          }
+          return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__util_pipe__['b' /* pipeFromArray */])(
+            operations
+          )(this);
+        };
+        Observable.prototype.toPromise = function (promiseCtor) {
+          var _this = this;
+          promiseCtor = getPromiseCtor(promiseCtor);
+          return new promiseCtor(function (resolve, reject) {
+            var value;
+            _this.subscribe(
+              function (x) {
+                return (value = x);
+              },
+              function (err) {
+                return reject(err);
+              },
+              function () {
+                return resolve(value);
+              }
+            );
+          });
+        };
+        Observable.create = function (subscribe) {
+          return new Observable(subscribe);
+        };
+        return Observable;
+      })();
+
+      function getPromiseCtor(promiseCtor) {
+        if (!promiseCtor) {
+          promiseCtor = __WEBPACK_IMPORTED_MODULE_4__config__['a' /* config */].Promise || Promise;
+        }
+        if (!promiseCtor) {
+          throw new Error('no Promise impl found');
+        }
+        return promiseCtor;
+      }
+      //# sourceMappingURL=Observable.js.map
+
+      /***/
+    },
+    /* 13 */
+    /***/ function (module, __webpack_exports__, __webpack_require__) {
+      'use strict';
+      /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, 'a', function () {
+        return OuterSubscriber;
+      });
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Subscriber__ = __webpack_require__(7);
+      /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */
+
+      var OuterSubscriber = /*@__PURE__*/ (function (_super) {
+        __WEBPACK_IMPORTED_MODULE_0_tslib__['a' /* __extends */](OuterSubscriber, _super);
+        function OuterSubscriber() {
+          return (_super !== null && _super.apply(this, arguments)) || this;
+        }
+        OuterSubscriber.prototype.notifyNext = function (
+          outerValue,
+          innerValue,
+          outerIndex,
+          innerIndex,
+          innerSub
+        ) {
+          this.destination.next(innerValue);
+        };
+        OuterSubscriber.prototype.notifyError = function (error, innerSub) {
+          this.destination.error(error);
+        };
+        OuterSubscriber.prototype.notifyComplete = function (innerSub) {
+          this.destination.complete();
+        };
+        return OuterSubscriber;
+      })(__WEBPACK_IMPORTED_MODULE_1__Subscriber__['a' /* Subscriber */]);
+
+      //# sourceMappingURL=OuterSubscriber.js.map
+
+      /***/
+    },
+    /* 14 */
+    /***/ function (module, __webpack_exports__, __webpack_require__) {
+      'use strict';
+      /* harmony export (immutable) */ __webpack_exports__['a'] = subscribeToResult;
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__InnerSubscriber__ = __webpack_require__(84);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__subscribeTo__ = __webpack_require__(446);
+      /** PURE_IMPORTS_START _InnerSubscriber,_subscribeTo PURE_IMPORTS_END */
+
+      function subscribeToResult(outerSubscriber, result, outerValue, outerIndex, destination) {
+        if (destination === void 0) {
+          destination = new __WEBPACK_IMPORTED_MODULE_0__InnerSubscriber__['a' /* InnerSubscriber */](
+            outerSubscriber,
+            outerValue,
+            outerIndex
+          );
+        }
+        if (destination.closed) {
+          return;
+        }
+        return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__subscribeTo__['a' /* subscribeTo */])(
+          result
+        )(destination);
+      }
+      //# sourceMappingURL=subscribeToResult.js.map
+
+      /***/
+    },
+    /* 15 */
+    /***/ function (module, exports, __webpack_require__) {
+      'use strict';
+      /* eslint-disable node/no-deprecated-api */
+
+      var buffer = __webpack_require__(64);
+      var Buffer = buffer.Buffer;
+
+      var safer = {};
+
+      var key;
+
+      for (key in buffer) {
+        if (!buffer.hasOwnProperty(key)) continue;
+        if (key === 'SlowBuffer' || key === 'Buffer') continue;
+        safer[key] = buffer[key];
+      }
+
+      var Safer = (safer.Buffer = {});
+      for (key in Buffer) {
+        if (!Buffer.hasOwnProperty(key)) continue;
+        if (key === 'allocUnsafe' || key === 'allocUnsafeSlow') continue;
+        Safer[key] = Buffer[key];
+      }
+
+      safer.Buffer.prototype = Buffer.prototype;
+
+      if (!Safer.from || Safer.from === Uint8Array.from) {
+        Safer.from = function (value, encodingOrOffset, length) {
+          if (typeof value === 'number') {
+            throw new TypeError(
+              'The "value" argument must not be of type number. Received type ' + typeof value
+            );
+          }
+          if (value && typeof value.length === 'undefined') {
+            throw new TypeError(
+              'The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type ' +
+                typeof value
+            );
+          }
+          return Buffer(value, encodingOrOffset, length);
+        };
+      }
+
+      if (!Safer.alloc) {
+        Safer.alloc = function (size, fill, encoding) {
+          if (typeof size !== 'number') {
+            throw new TypeError('The "size" argument must be of type number. Received type ' + typeof size);
+          }
+          if (size < 0 || size >= 2 * (1 << 30)) {
+            throw new RangeError('The value "' + size + '" is invalid for option "size"');
+          }
+          var buf = Buffer(size);
+          if (!fill || fill.length === 0) {
+            buf.fill(0);
+          } else if (typeof encoding === 'string') {
+            buf.fill(fill, encoding);
+          } else {
+            buf.fill(fill);
+          }
+          return buf;
+        };
+      }
+
+      if (!safer.kStringMaxLength) {
+        try {
+          safer.kStringMaxLength = process.binding('buffer').kStringMaxLength;
+        } catch (e) {
+          // we can't determine kStringMaxLength in environments where process.binding
+          // is unsupported, so let's not set it
+        }
+      }
+
+      if (!safer.constants) {
+        safer.constants = {
+          MAX_LENGTH: safer.kMaxLength,
+        };
+        if (safer.kStringMaxLength) {
+          safer.constants.MAX_STRING_LENGTH = safer.kStringMaxLength;
+        }
+      }
+
+      module.exports = safer;
+
+      /***/
+    },
+    /* 16 */
+    /***/ function (module, exports, __webpack_require__) {
+      // Copyright (c) 2012, Mark Cavage. All rights reserved.
+      // Copyright 2015 Joyent, Inc.
+
+      var assert = __webpack_require__(28);
+      var Stream = __webpack_require__(23).Stream;
+      var util = __webpack_require__(3);
+
+      ///--- Globals
+
+      /* JSSTYLED */
+      var UUID_REGEXP = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/;
+
+      ///--- Internal
+
+      function _capitalize(str) {
+        return str.charAt(0).toUpperCase() + str.slice(1);
+      }
+
+      function _toss(name, expected, oper, arg, actual) {
+        throw new assert.AssertionError({
+          message: util.format('%s (%s) is required', name, expected),
+          actual: actual === undefined ? typeof arg : actual(arg),
+          expected: expected,
+          operator: oper || '===',
+          stackStartFunction: _toss.caller,
+        });
+      }
+
+      function _getClass(arg) {
+        return Object.prototype.toString.call(arg).slice(8, -1);
+      }
+
+      function noop() {
+        // Why even bother with asserts?
+      }
+
+      ///--- Exports
+
+      var types = {
+        bool: {
+          check: function (arg) {
+            return typeof arg === 'boolean';
+          },
+        },
+        func: {
+          check: function (arg) {
+            return typeof arg === 'function';
+          },
+        },
+        string: {
+          check: function (arg) {
+            return typeof arg === 'string';
+          },
+        },
+        object: {
+          check: function (arg) {
+            return typeof arg === 'object' && arg !== null;
+          },
+        },
+        number: {
+          check: function (arg) {
+            return typeof arg === 'number' && !isNaN(arg);
+          },
+        },
+        finite: {
+          check: function (arg) {
+            return typeof arg === 'number' && !isNaN(arg) && isFinite(arg);
+          },
+        },
+        buffer: {
+          check: function (arg) {
+            return Buffer.isBuffer(arg);
+          },
+          operator: 'Buffer.isBuffer',
+        },
+        array: {
+          check: function (arg) {
+            return Array.isArray(arg);
+          },
+          operator: 'Array.isArray',
+        },
+        stream: {
+          check: function (arg) {
+            return arg instanceof Stream;
+          },
+          operator: 'instanceof',
+          actual: _getClass,
+        },
+        date: {
+          check: function (arg) {
+            return arg instanceof Date;
+          },
+          operator: 'instanceof',
+          actual: _getClass,
+        },
+        regexp: {
+          check: function (arg) {
+            return arg instanceof RegExp;
+          },
+          operator: 'instanceof',
+          actual: _getClass,
+        },
+        uuid: {
+          check: function (arg) {
+            return typeof arg === 'string' && UUID_REGEXP.test(arg);
+          },
+          operator: 'isUUID',
+        },
+      };
+
+      function _setExports(ndebug) {
+        var keys = Object.keys(types);
+        var out;
+
+        /* re-export standard assert */
+        if (process.env.NODE_NDEBUG) {
+          out = noop;
+        } else {
+          out = function (arg, msg) {
+            if (!arg) {
+              _toss(msg, 'true', arg);
+            }
+          };
+        }
+
+        /* standard checks */
+        keys.forEach(function (k) {
+          if (ndebug) {
+            out[k] = noop;
+            return;
+          }
+          var type = types[k];
+          out[k] = function (arg, msg) {
+            if (!type.check(arg)) {
+              _toss(msg, k, type.operator, arg, type.actual);
+            }
+          };
+        });
+
+        /* optional checks */
+        keys.forEach(function (k) {
+          var name = 'optional' + _capitalize(k);
+          if (ndebug) {
+            out[name] = noop;
+            return;
+          }
+          var type = types[k];
+          out[name] = function (arg, msg) {
+            if (arg === undefined || arg === null) {
+              return;
+            }
+            if (!type.check(arg)) {
+              _toss(msg, k, type.operator, arg, type.actual);
+            }
+          };
+        });
+
+        /* arrayOf checks */
+        keys.forEach(function (k) {
+          var name = 'arrayOf' + _capitalize(k);
+          if (ndebug) {
+            out[name] = noop;
+            return;
+          }
+          var type = types[k];
+          var expected = '[' + k + ']';
+          out[name] = function (arg, msg) {
+            if (!Array.isArray(arg)) {
+              _toss(msg, expected, type.operator, arg, type.actual);
+            }
+            var i;
+            for (i = 0; i < arg.length; i++) {
+              if (!type.check(arg[i])) {
+                _toss(msg, expected, type.operator, arg, type.actual);
+              }
+            }
+          };
+        });
+
+        /* optionalArrayOf checks */
+        keys.forEach(function (k) {
+          var name = 'optionalArrayOf' + _capitalize(k);
+          if (ndebug) {
+            out[name] = noop;
+            return;
+          }
+          var type = types[k];
+          var expected = '[' + k + ']';
+          out[name] = function (arg, msg) {
+            if (arg === undefined || arg === null) {
+              return;
+            }
+            if (!Array.isArray(arg)) {
+              _toss(msg, expected, type.operator, arg, type.actual);
+            }
+            var i;
+            for (i = 0; i < arg.length; i++) {
+              if (!type.check(arg[i])) {
+                _toss(msg, expected, type.operator, arg, type.actual);
+              }
+            }
+          };
+        });
+
+        /* re-export built-in assertions */
+        Object.keys(assert).forEach(function (k) {
+          if (k === 'AssertionError') {
+            out[k] = assert[k];
+            return;
+          }
+          if (ndebug) {
+            out[k] = noop;
+            return;
+          }
+          out[k] = assert[k];
+        });
+
+        /* export ourselves (for unit tests _only_) */
+        out._setExports = _setExports;
+
+        return out;
+      }
+
+      module.exports = _setExports(process.env.NODE_NDEBUG);
+
+      /***/
+    },
+    /* 17 */
+    /***/ function (module, exports) {
+      // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
+      var global = (module.exports =
+        typeof window != 'undefined' && window.Math == Math
+          ? window
+          : typeof self != 'undefined' && self.Math == Math
+          ? self
+          : // eslint-disable-next-line no-new-func
+            Function('return this')());
+      if (typeof __g == 'number') __g = global; // eslint-disable-line no-undef
+
+      /***/
+    },
+    /* 18 */
+    /***/ function (module, exports, __webpack_require__) {
+      'use strict';
+
+      Object.defineProperty(exports, '__esModule', {
+        value: true,
+      });
+      exports.sortAlpha = sortAlpha;
+      exports.sortOptionsByFlags = sortOptionsByFlags;
+      exports.entries = entries;
+      exports.removePrefix = removePrefix;
+      exports.removeSuffix = removeSuffix;
+      exports.addSuffix = addSuffix;
+      exports.hyphenate = hyphenate;
+      exports.camelCase = camelCase;
+      exports.compareSortedArrays = compareSortedArrays;
+      exports.sleep = sleep;
+      const _camelCase = __webpack_require__(227);
+
+      function sortAlpha(a, b) {
+        // sort alphabetically in a deterministic way
+        const shortLen = Math.min(a.length, b.length);
+        for (let i = 0; i < shortLen; i++) {
+          const aChar = a.charCodeAt(i);
+          const bChar = b.charCodeAt(i);
+          if (aChar !== bChar) {
+            return aChar - bChar;
+          }
+        }
+        return a.length - b.length;
+      }
+
+      function sortOptionsByFlags(a, b) {
+        const aOpt = a.flags.replace(/-/g, '');
+        const bOpt = b.flags.replace(/-/g, '');
+        return sortAlpha(aOpt, bOpt);
+      }
+
+      function entries(obj) {
+        const entries = [];
+        if (obj) {
+          for (const key in obj) {
+            entries.push([key, obj[key]]);
+          }
+        }
+        return entries;
+      }
+
+      function removePrefix(pattern, prefix) {
+        if (pattern.startsWith(prefix)) {
+          pattern = pattern.slice(prefix.length);
+        }
+
+        return pattern;
+      }
+
+      function removeSuffix(pattern, suffix) {
+        if (pattern.endsWith(suffix)) {
+          return pattern.slice(0, -suffix.length);
+        }
+
+        return pattern;
+      }
+
+      function addSuffix(pattern, suffix) {
+        if (!pattern.endsWith(suffix)) {
+          return pattern + suffix;
+        }
+
+        return pattern;
+      }
+
+      function hyphenate(str) {
+        return str.replace(/[A-Z]/g, (match) => {
+          return '-' + match.charAt(0).toLowerCase();
+        });
+      }
+
+      function camelCase(str) {
+        if (/[A-Z]/.test(str)) {
+          return null;
+        } else {
+          return _camelCase(str);
+        }
+      }
+
+      function compareSortedArrays(array1, array2) {
+        if (array1.length !== array2.length) {
+          return false;
+        }
+        for (let i = 0, len = array1.length; i < len; i++) {
+          if (array1[i] !== array2[i]) {
+            return false;
+          }
+        }
+        return true;
+      }
+
+      function sleep(ms) {
+        return new Promise((resolve) => {
+          setTimeout(resolve, ms);
+        });
+      }
+
+      /***/
+    },
+    /* 19 */
+    /***/ function (module, exports, __webpack_require__) {
+      'use strict';
+
+      Object.defineProperty(exports, '__esModule', {
+        value: true,
+      });
+      exports.stringify = exports.parse = undefined;
+
+      var _asyncToGenerator2;
+
+      function _load_asyncToGenerator() {
+        return (_asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)));
+      }
+
+      var _parse;
+
+      function _load_parse() {
+        return (_parse = __webpack_require__(106));
+      }
+
+      Object.defineProperty(exports, 'parse', {
+        enumerable: true,
+        get: function get() {
+          return _interopRequireDefault(_parse || _load_parse()).default;
+        },
+      });
+
+      var _stringify;
+
+      function _load_stringify() {
+        return (_stringify = __webpack_require__(200));
+      }
+
+      Object.defineProperty(exports, 'stringify', {
+        enumerable: true,
+        get: function get() {
+          return _interopRequireDefault(_stringify || _load_stringify()).default;
+        },
+      });
+      exports.implodeEntry = implodeEntry;
+      exports.explodeEntry = explodeEntry;
+
+      var _misc;
+
+      function _load_misc() {
+        return (_misc = __webpack_require__(18));
+      }
+
+      var _normalizePattern;
+
+      function _load_normalizePattern() {
+        return (_normalizePattern = __webpack_require__(37));
+      }
+
+      var _parse2;
+
+      function _load_parse2() {
+        return (_parse2 = _interopRequireDefault(__webpack_require__(106)));
+      }
+
+      var _constants;
+
+      function _load_constants() {
+        return (_constants = __webpack_require__(8));
+      }
+
+      var _fs;
+
+      function _load_fs() {
+        return (_fs = _interopRequireWildcard(__webpack_require__(5)));
+      }
+
+      function _interopRequireWildcard(obj) {
+        if (obj && obj.__esModule) {
+          return obj;
+        } else {
+          var newObj = {};
+          if (obj != null) {
+            for (var key in obj) {
+              if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key];
+            }
+          }
+          newObj.default = obj;
+          return newObj;
+        }
+      }
+
+      function _interopRequireDefault(obj) {
+        return obj && obj.__esModule ? obj : { default: obj };
+      }
+
+      const invariant = __webpack_require__(9);
+
+      const path = __webpack_require__(0);
+      const ssri = __webpack_require__(65);
+
+      function getName(pattern) {
+        return (0, (_normalizePattern || _load_normalizePattern()).normalizePattern)(pattern).name;
+      }
+
+      function blankObjectUndefined(obj) {
+        return obj && Object.keys(obj).length ? obj : undefined;
+      }
+
+      function keyForRemote(remote) {
+        return (
+          remote.resolved || (remote.reference && remote.hash ? `${remote.reference}#${remote.hash}` : null)
+        );
+      }
+
+      function serializeIntegrity(integrity) {
+        // We need this because `Integrity.toString()` does not use sorting to ensure a stable string output
+        // See https://git.io/vx2Hy
+        return integrity.toString().split(' ').sort().join(' ');
+      }
+
+      function implodeEntry(pattern, obj) {
+        const inferredName = getName(pattern);
+        const integrity = obj.integrity ? serializeIntegrity(obj.integrity) : '';
+        const imploded = {
+          name: inferredName === obj.name ? undefined : obj.name,
+          version: obj.version,
+          uid: obj.uid === obj.version ? undefined : obj.uid,
+          resolved: obj.resolved,
+          registry: obj.registry === 'npm' ? undefined : obj.registry,
+          dependencies: blankObjectUndefined(obj.dependencies),
+          optionalDependencies: blankObjectUndefined(obj.optionalDependencies),
+          permissions: blankObjectUndefined(obj.permissions),
+          prebuiltVariants: blankObjectUndefined(obj.prebuiltVariants),
+        };
+        if (integrity) {
+          imploded.integrity = integrity;
+        }
+        return imploded;
+      }
+
+      function explodeEntry(pattern, obj) {
+        obj.optionalDependencies = obj.optionalDependencies || {};
+        obj.dependencies = obj.dependencies || {};
+        obj.uid = obj.uid || obj.version;
+        obj.permissions = obj.permissions || {};
+        obj.registry = obj.registry || 'npm';
+        obj.name = obj.name || getName(pattern);
+        const integrity = obj.integrity;
+        if (integrity && integrity.isIntegrity) {
+          obj.integrity = ssri.parse(integrity);
+        }
+        return obj;
+      }
+
+      class Lockfile {
+        constructor({ cache, source, parseResultType } = {}) {
+          this.source = source || '';
+          this.cache = cache;
+          this.parseResultType = parseResultType;
+        }
+
+        // source string if the `cache` was parsed
+
+        // if true, we're parsing an old yarn file and need to update integrity fields
+        hasEntriesExistWithoutIntegrity() {
+          if (!this.cache) {
+            return false;
+          }
+
+          for (const key in this.cache) {
+            // $FlowFixMe - `this.cache` is clearly defined at this point
+            if (!/^.*@(file:|http)/.test(key) && this.cache[key] && !this.cache[key].integrity) {
+              return true;
+            }
+          }
+
+          return false;
+        }
+
+        static fromDirectory(dir, reporter) {
+          return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
+            // read the manifest in this directory
+            const lockfileLoc = path.join(dir, (_constants || _load_constants()).LOCKFILE_FILENAME);
+
+            let lockfile;
+            let rawLockfile = '';
+            let parseResult;
+
+            if (yield (_fs || _load_fs()).exists(lockfileLoc)) {
+              rawLockfile = yield (_fs || _load_fs()).readFile(lockfileLoc);
+              parseResult = (0, (_parse2 || _load_parse2()).default)(rawLockfile, lockfileLoc);
+
+              if (reporter) {
+                if (parseResult.type === 'merge') {
+                  reporter.info(reporter.lang('lockfileMerged'));
+                } else if (parseResult.type === 'conflict') {
+                  reporter.warn(reporter.lang('lockfileConflict'));
+                }
+              }
+
+              lockfile = parseResult.object;
+            } else if (reporter) {
+              reporter.info(reporter.lang('noLockfileFound'));
+            }
+
+            if (lockfile && lockfile.__metadata) {
+              const lockfilev2 = lockfile;
+              lockfile = {};
+            }
+
+            return new Lockfile({
+              cache: lockfile,
+              source: rawLockfile,
+              parseResultType: parseResult && parseResult.type,
+            });
+          })();
+        }
+
+        getLocked(pattern) {
+          const cache = this.cache;
+          if (!cache) {
+            return undefined;
+          }
+
+          const shrunk = pattern in cache && cache[pattern];
+
+          if (typeof shrunk === 'string') {
+            return this.getLocked(shrunk);
+          } else if (shrunk) {
+            explodeEntry(pattern, shrunk);
+            return shrunk;
+          }
+
+          return undefined;
+        }
+
+        removePattern(pattern) {
+          const cache = this.cache;
+          if (!cache) {
+            return;
+          }
+          delete cache[pattern];
+        }
+
+        getLockfile(patterns) {
+          const lockfile = {};
+          const seen = new Map();
+
+          // order by name so that lockfile manifest is assigned to the first dependency with this manifest
+          // the others that have the same remoteKey will just refer to the first
+          // ordering allows for consistency in lockfile when it is serialized
+          const sortedPatternsKeys = Object.keys(patterns).sort((_misc || _load_misc()).sortAlpha);
+
+          for (
+            var _iterator = sortedPatternsKeys,
+              _isArray = Array.isArray(_iterator),
+              _i = 0,
+              _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();
+            ;
+
+          ) {
+            var _ref;
+
+            if (_isArray) {
+              if (_i >= _iterator.length) break;
+              _ref = _iterator[_i++];
+            } else {
+              _i = _iterator.next();
+              if (_i.done) break;
+              _ref = _i.value;
+            }
+
+            const pattern = _ref;
+
+            const pkg = patterns[pattern];
+            const remote = pkg._remote,
+              ref = pkg._reference;
+
+            invariant(ref, 'Package is missing a reference');
+            invariant(remote, 'Package is missing a remote');
+
+            const remoteKey = keyForRemote(remote);
+            const seenPattern = remoteKey && seen.get(remoteKey);
+            if (seenPattern) {
+              // no point in duplicating it
+              lockfile[pattern] = seenPattern;
+
+              // if we're relying on our name being inferred and two of the patterns have
+              // different inferred names then we need to set it
+              if (!seenPattern.name && getName(pattern) !== pkg.name) {
+                seenPattern.name = pkg.name;
+              }
+              continue;
+            }
+            const obj = implodeEntry(pattern, {
+              name: pkg.name,
+              version: pkg.version,
+              uid: pkg._uid,
+              resolved: remote.resolved,
+              integrity: remote.integrity,
+              registry: remote.registry,
+              dependencies: pkg.dependencies,
+              peerDependencies: pkg.peerDependencies,
+              optionalDependencies: pkg.optionalDependencies,
+              permissions: ref.permissions,
+              prebuiltVariants: pkg.prebuiltVariants,
+            });
+
+            lockfile[pattern] = obj;
+
+            if (remoteKey) {
+              seen.set(remoteKey, obj);
+            }
+          }
+
+          return lockfile;
+        }
+      }
+      exports.default = Lockfile;
+
+      /***/
+    },
+    /* 20 */
+    /***/ function (module, exports, __webpack_require__) {
+      'use strict';
+
+      exports.__esModule = true;
+
+      var _assign = __webpack_require__(559);
+
+      var _assign2 = _interopRequireDefault(_assign);
+
+      function _interopRequireDefault(obj) {
+        return obj && obj.__esModule ? obj : { default: obj };
+      }
+
+      exports.default =
+        _assign2.default ||
+        function (target) {
+          for (var i = 1; i < arguments.length; i++) {
+            var source = arguments[i];
+
+            for (var key in source) {
+              if (Object.prototype.hasOwnProperty.call(source, key)) {
+                target[key] = source[key];
+              }
+            }
+          }
+
+          return target;
+        };
+
+      /***/
+    },
+    /* 21 */
+    /***/ function (module, exports, __webpack_require__) {
+      var store = __webpack_require__(133)('wks');
+      var uid = __webpack_require__(137);
+      var Symbol = __webpack_require__(17).Symbol;
+      var USE_SYMBOL = typeof Symbol == 'function';
+
+      var $exports = (module.exports = function (name) {
+        return (
+          store[name] ||
+          (store[name] = (USE_SYMBOL && Symbol[name]) || (USE_SYMBOL ? Symbol : uid)('Symbol.' + name))
+        );
+      });
+
+      $exports.store = store;
+
+      /***/
+    },
+    /* 22 */
+    /***/ function (module, exports) {
+      exports = module.exports = SemVer;
+
+      // The debug function is excluded entirely from the minified version.
+      /* nomin */ var debug;
+      /* nomin */ if (
+        typeof process === 'object' &&
+        /* nomin */ process.env &&
+        /* nomin */ process.env.NODE_DEBUG &&
+        /* nomin */ /\bsemver\b/i.test(process.env.NODE_DEBUG)
+      )
+        /* nomin */ debug = function () {
+          /* nomin */ var args = Array.prototype.slice.call(arguments, 0);
+          /* nomin */ args.unshift('SEMVER');
+          /* nomin */ console.log.apply(console, args);
+          /* nomin */
+        };
+      /* nomin */
+      /* nomin */ else debug = function () {};
+
+      // Note: this is the semver.org version of the spec that it implements
+      // Not necessarily the package version of this code.
+      exports.SEMVER_SPEC_VERSION = '2.0.0';
+
+      var MAX_LENGTH = 256;
+      var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;
+
+      // Max safe segment length for coercion.
+      var MAX_SAFE_COMPONENT_LENGTH = 16;
+
+      // The actual regexps go on exports.re
+      var re = (exports.re = []);
+      var src = (exports.src = []);
+      var R = 0;
+
+      // The following Regular Expressions can be used for tokenizing,
+      // validating, and parsing SemVer version strings.
+
+      // ## Numeric Identifier
+      // A single `0`, or a non-zero digit followed by zero or more digits.
+
+      var NUMERICIDENTIFIER = R++;
+      src[NUMERICIDENTIFIER] = '0|[1-9]\\d*';
+      var NUMERICIDENTIFIERLOOSE = R++;
+      src[NUMERICIDENTIFIERLOOSE] = '[0-9]+';
+
+      // ## Non-numeric Identifier
+      // Zero or more digits, followed by a letter or hyphen, and then zero or
+      // more letters, digits, or hyphens.
+
+      var NONNUMERICIDENTIFIER = R++;
+      src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*';
+
+      // ## Main Version
+      // Three dot-separated numeric identifiers.
+
+      var MAINVERSION = R++;
+      src[MAINVERSION] =
+        '(' +
+        src[NUMERICIDENTIFIER] +
+        ')\\.' +
+        '(' +
+        src[NUMERICIDENTIFIER] +
+        ')\\.' +
+        '(' +
+        src[NUMERICIDENTIFIER] +
+        ')';
+
+      var MAINVERSIONLOOSE = R++;
+      src[MAINVERSIONLOOSE] =
+        '(' +
+        src[NUMERICIDENTIFIERLOOSE] +
+        ')\\.' +
+        '(' +
+        src[NUMERICIDENTIFIERLOOSE] +
+        ')\\.' +
+        '(' +
+        src[NUMERICIDENTIFIERLOOSE] +
+        ')';
+
+      // ## Pre-release Version Identifier
+      // A numeric identifier, or a non-numeric identifier.
+
+      var PRERELEASEIDENTIFIER = R++;
+      src[PRERELEASEIDENTIFIER] = '(?:' + src[NUMERICIDENTIFIER] + '|' + src[NONNUMERICIDENTIFIER] + ')';
+
+      var PRERELEASEIDENTIFIERLOOSE = R++;
+      src[PRERELEASEIDENTIFIERLOOSE] =
+        '(?:' + src[NUMERICIDENTIFIERLOOSE] + '|' + src[NONNUMERICIDENTIFIER] + ')';
+
+      // ## Pre-release Version
+      // Hyphen, followed by one or more dot-separated pre-release version
+      // identifiers.
+
+      var PRERELEASE = R++;
+      src[PRERELEASE] = '(?:-(' + src[PRERELEASEIDENTIFIER] + '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))';
+
+      var PRERELEASELOOSE = R++;
+      src[PRERELEASELOOSE] =
+        '(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] + '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))';
+
+      // ## Build Metadata Identifier
+      // Any combination of digits, letters, or hyphens.
+
+      var BUILDIDENTIFIER = R++;
+      src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+';
+
+      // ## Build Metadata
+      // Plus sign, followed by one or more period-separated build metadata
+      // identifiers.
+
+      var BUILD = R++;
+      src[BUILD] = '(?:\\+(' + src[BUILDIDENTIFIER] + '(?:\\.' + src[BUILDIDENTIFIER] + ')*))';
+
+      // ## Full Version String
+      // A main version, followed optionally by a pre-release version and
+      // build metadata.
+
+      // Note that the only major, minor, patch, and pre-release sections of
+      // the version string are capturing groups.  The build metadata is not a
+      // capturing group, because it should not ever be used in version
+      // comparison.
+
+      var FULL = R++;
+      var FULLPLAIN = 'v?' + src[MAINVERSION] + src[PRERELEASE] + '?' + src[BUILD] + '?';
+
+      src[FULL] = '^' + FULLPLAIN + '$';
+
+      // like full, but allows v1.2.3 and =1.2.3, which people do sometimes.
+      // also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty
+      // common in the npm registry.
+      var LOOSEPLAIN = '[v=\\s]*' + src[MAINVERSIONLOOSE] + src[PRERELEASELOOSE] + '?' + src[BUILD] + '?';
+
+      var LOOSE = R++;
+      src[LOOSE] = '^' + LOOSEPLAIN + '$';
+
+      var GTLT = R++;
+      src[GTLT] = '((?:<|>)?=?)';
+
+      // Something like "2.*" or "1.2.x".
+      // Note that "x.x" is a valid xRange identifer, meaning "any version"
+      // Only the first item is strictly required.
+      var XRANGEIDENTIFIERLOOSE = R++;
+      src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*';
+      var XRANGEIDENTIFIER = R++;
+      src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*';
+
+      var XRANGEPLAIN = R++;
+      src[XRANGEPLAIN] =
+        '[v=\\s]*(' +
+        src[XRANGEIDENTIFIER] +
+        ')' +
+        '(?:\\.(' +
+        src[XRANGEIDENTIFIER] +
+        ')' +
+        '(?:\\.(' +
+        src[XRANGEIDENTIFIER] +
+        ')' +
+        '(?:' +
+        src[PRERELEASE] +
+        ')?' +
+        src[BUILD] +
+        '?' +
+        ')?)?';
+
+      var XRANGEPLAINLOOSE = R++;
+      src[XRANGEPLAINLOOSE] =
+        '[v=\\s]*(' +
+        src[XRANGEIDENTIFIERLOOSE] +
+        ')' +
+        '(?:\\.(' +
+        src[XRANGEIDENTIFIERLOOSE] +
+        ')' +
+        '(?:\\.(' +
+        src[XRANGEIDENTIFIERLOOSE] +
+        ')' +
+        '(?:' +
+        src[PRERELEASELOOSE] +
+        ')?' +
+        src[BUILD] +
+        '?' +
+        ')?)?';
+
+      var XRANGE = R++;
+      src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$';
+      var XRANGELOOSE = R++;
+      src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$';
+
+      // Coercion.
+      // Extract anything that could conceivably be a part of a valid semver
+      var COERCE = R++;
+      src[COERCE] =
+        '(?:^|[^\\d])' +
+        '(\\d{1,' +
+        MAX_SAFE_COMPONENT_LENGTH +
+        '})' +
+        '(?:\\.(\\d{1,' +
+        MAX_SAFE_COMPONENT_LENGTH +
+        '}))?' +
+        '(?:\\.(\\d{1,' +
+        MAX_SAFE_COMPONENT_LENGTH +
+        '}))?' +
+        '(?:$|[^\\d])';
+
+      // Tilde ranges.
+      // Meaning is "reasonably at or greater than"
+      var LONETILDE = R++;
+      src[LONETILDE] = '(?:~>?)';
+
+      var TILDETRIM = R++;
+      src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+';
+      re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g');
+      var tildeTrimReplace = '$1~';
+
+      var TILDE = R++;
+      src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$';
+      var TILDELOOSE = R++;
+      src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$';
+
+      // Caret ranges.
+      // Meaning is "at least and backwards compatible with"
+      var LONECARET = R++;
+      src[LONECARET] = '(?:\\^)';
+
+      var CARETTRIM = R++;
+      src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+';
+      re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g');
+      var caretTrimReplace = '$1^';
+
+      var CARET = R++;
+      src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$';
+      var CARETLOOSE = R++;
+      src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$';
+
+      // A simple gt/lt/eq thing, or just "" to indicate "any version"
+      var COMPARATORLOOSE = R++;
+      src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$';
+      var COMPARATOR = R++;
+      src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$';
+
+      // An expression to strip any whitespace between the gtlt and the thing
+      // it modifies, so that `> 1.2.3` ==> `>1.2.3`
+      var COMPARATORTRIM = R++;
+      src[COMPARATORTRIM] = '(\\s*)' + src[GTLT] + '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')';
+
+      // this one has to use the /g flag
+      re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g');
+      var comparatorTrimReplace = '$1$2$3';
+
+      // Something like `1.2.3 - 1.2.4`
+      // Note that these all use the loose form, because they'll be
+      // checked against either the strict or loose comparator form
+      // later.
+      var HYPHENRANGE = R++;
+      src[HYPHENRANGE] =
+        '^\\s*(' + src[XRANGEPLAIN] + ')' + '\\s+-\\s+' + '(' + src[XRANGEPLAIN] + ')' + '\\s*$';
+
+      var HYPHENRANGELOOSE = R++;
+      src[HYPHENRANGELOOSE] =
+        '^\\s*(' + src[XRANGEPLAINLOOSE] + ')' + '\\s+-\\s+' + '(' + src[XRANGEPLAINLOOSE] + ')' + '\\s*$';
+
+      // Star ranges basically just allow anything at all.
+      var STAR = R++;
+      src[STAR] = '(<|>)?=?\\s*\\*';
+
+      // Compile to actual regexp objects.
+      // All are flag-free, unless they were created above with a flag.
+      for (var i = 0; i < R; i++) {
+        debug(i, src[i]);
+        if (!re[i]) re[i] = new RegExp(src[i]);
+      }
+
+      exports.parse = parse;
+      function parse(version, loose) {
+        if (version instanceof SemVer) return version;
+
+        if (typeof version !== 'string') return null;
+
+        if (version.length > MAX_LENGTH) return null;
+
+        var r = loose ? re[LOOSE] : re[FULL];
+        if (!r.test(version)) return null;
+
+        try {
+          return new SemVer(version, loose);
+        } catch (er) {
+          return null;
+        }
+      }
+
+      exports.valid = valid;
+      function valid(version, loose) {
+        var v = parse(version, loose);
+        return v ? v.version : null;
+      }
+
+      exports.clean = clean;
+      function clean(version, loose) {
+        var s = parse(version.trim().replace(/^[=v]+/, ''), loose);
+        return s ? s.version : null;
+      }
+
+      exports.SemVer = SemVer;
+
+      function SemVer(version, loose) {
+        if (version instanceof SemVer) {
+          if (version.loose === loose) return version;
+          else version = version.version;
+        } else if (typeof version !== 'string') {
+          throw new TypeError('Invalid Version: ' + version);
+        }
+
+        if (version.length > MAX_LENGTH)
+          throw new TypeError('version is longer than ' + MAX_LENGTH + ' characters');
+
+        if (!(this instanceof SemVer)) return new SemVer(version, loose);
+
+        debug('SemVer', version, loose);
+        this.loose = loose;
+        var m = version.trim().match(loose ? re[LOOSE] : re[FULL]);
+
+        if (!m) throw new TypeError('Invalid Version: ' + version);
+
+        this.raw = version;
+
+        // these are actually numbers
+        this.major = +m[1];
+        this.minor = +m[2];
+        this.patch = +m[3];
+
+        if (this.major > MAX_SAFE_INTEGER || this.major < 0) throw new TypeError('Invalid major version');
+
+        if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) throw new TypeError('Invalid minor version');
+
+        if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) throw new TypeError('Invalid patch version');
+
+        // numberify any prerelease numeric ids
+        if (!m[4]) this.prerelease = [];
+        else
+          this.prerelease = m[4].split('.').map(function (id) {
+            if (/^[0-9]+$/.test(id)) {
+              var num = +id;
+              if (num >= 0 && num < MAX_SAFE_INTEGER) return num;
+            }
+            return id;
+          });
+
+        this.build = m[5] ? m[5].split('.') : [];
+        this.format();
+      }
+
+      SemVer.prototype.format = function () {
+        this.version = this.major + '.' + this.minor + '.' + this.patch;
+        if (this.prerelease.length) this.version += '-' + this.prerelease.join('.');
+        return this.version;
+      };
+
+      SemVer.prototype.toString = function () {
+        return this.version;
+      };
+
+      SemVer.prototype.compare = function (other) {
+        debug('SemVer.compare', this.version, this.loose, other);
+        if (!(other instanceof SemVer)) other = new SemVer(other, this.loose);
+
+        return this.compareMain(other) || this.comparePre(other);
+      };
+
+      SemVer.prototype.compareMain = function (other) {
+        if (!(other instanceof SemVer)) other = new SemVer(other, this.loose);
+
+        return (
+          compareIdentifiers(this.major, other.major) ||
+          compareIdentifiers(this.minor, other.minor) ||
+          compareIdentifiers(this.patch, other.patch)
+        );
+      };
+
+      SemVer.prototype.comparePre = function (other) {
+        if (!(other instanceof SemVer)) other = new SemVer(other, this.loose);
+
+        // NOT having a prerelease is > having one
+        if (this.prerelease.length && !other.prerelease.length) return -1;
+        else if (!this.prerelease.length && other.prerelease.length) return 1;
+        else if (!this.prerelease.length && !other.prerelease.length) return 0;
+
+        var i = 0;
+        do {
+          var a = this.prerelease[i];
+          var b = other.prerelease[i];
+          debug('prerelease compare', i, a, b);
+          if (a === undefined && b === undefined) return 0;
+          else if (b === undefined) return 1;
+          else if (a === undefined) return -1;
+          else if (a === b) continue;
+          else return compareIdentifiers(a, b);
+        } while (++i);
+      };
+
+      // preminor will bump the version up to the next minor release, and immediately
+      // down to pre-release. premajor and prepatch work the same way.
+      SemVer.prototype.inc = function (release, identifier) {
+        switch (release) {
+          case 'premajor':
+            this.prerelease.length = 0;
+            this.patch = 0;
+            this.minor = 0;
+            this.major++;
+            this.inc('pre', identifier);
+            break;
+          case 'preminor':
+            this.prerelease.length = 0;
+            this.patch = 0;
+            this.minor++;
+            this.inc('pre', identifier);
+            break;
+          case 'prepatch':
+            // If this is already a prerelease, it will bump to the next version
+            // drop any prereleases that might already exist, since they are not
+            // relevant at this point.
+            this.prerelease.length = 0;
+            this.inc('patch', identifier);
+            this.inc('pre', identifier);
+            break;
+          // If the input is a non-prerelease version, this acts the same as
+          // prepatch.
+          case 'prerelease':
+            if (this.prerelease.length === 0) this.inc('patch', identifier);
+            this.inc('pre', identifier);
+            break;
+
+          case 'major':
+            // If this is a pre-major version, bump up to the same major version.
+            // Otherwise increment major.
+            // 1.0.0-5 bumps to 1.0.0
+            // 1.1.0 bumps to 2.0.0
+            if (this.minor !== 0 || this.patch !== 0 || this.prerelease.length === 0) this.major++;
+            this.minor = 0;
+            this.patch = 0;
+            this.prerelease = [];
+            break;
+          case 'minor':
+            // If this is a pre-minor version, bump up to the same minor version.
+            // Otherwise increment minor.
+            // 1.2.0-5 bumps to 1.2.0
+            // 1.2.1 bumps to 1.3.0
+            if (this.patch !== 0 || this.prerelease.length === 0) this.minor++;
+            this.patch = 0;
+            this.prerelease = [];
+            break;
+          case 'patch':
+            // If this is not a pre-release version, it will increment the patch.
+            // If it is a pre-release it will bump up to the same patch version.
+            // 1.2.0-5 patches to 1.2.0
+            // 1.2.0 patches to 1.2.1
+            if (this.prerelease.length === 0) this.patch++;
+            this.prerelease = [];
+            break;
+          // This probably shouldn't be used publicly.
+          // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction.
+          case 'pre':
+            if (this.prerelease.length === 0) this.prerelease = [0];
+            else {
+              var i = this.prerelease.length;
+              while (--i >= 0) {
+                if (typeof this.prerelease[i] === 'number') {
+                  this.prerelease[i]++;
+                  i = -2;
+                }
+              }
+              if (i === -1)
+                // didn't increment anything
+                this.prerelease.push(0);
+            }
+            if (identifier) {
+              // 1.2.0-beta.1 bumps to 1.2.0-beta.2,
+              // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0
+              if (this.prerelease[0] === identifier) {
+                if (isNaN(this.prerelease[1])) this.prerelease = [identifier, 0];
+              } else this.prerelease = [identifier, 0];
+            }
+            break;
+
+          default:
+            throw new Error('invalid increment argument: ' + release);
+        }
+        this.format();
+        this.raw = this.version;
+        return this;
+      };
+
+      exports.inc = inc;
+      function inc(version, release, loose, identifier) {
+        if (typeof loose === 'string') {
+          identifier = loose;
+          loose = undefined;
+        }
+
+        try {
+          return new SemVer(version, loose).inc(release, identifier).version;
+        } catch (er) {
+          return null;
+        }
+      }
+
+      exports.diff = diff;
+      function diff(version1, version2) {
+        if (eq(version1, version2)) {
+          return null;
+        } else {
+          var v1 = parse(version1);
+          var v2 = parse(version2);
+          if (v1.prerelease.length || v2.prerelease.length) {
+            for (var key in v1) {
+              if (key === 'major' || key === 'minor' || key === 'patch') {
+                if (v1[key] !== v2[key]) {
+                  return 'pre' + key;
+                }
+              }
+            }
+            return 'prerelease';
+          }
+          for (var key in v1) {
+            if (key === 'major' || key === 'minor' || key === 'patch') {
+              if (v1[key] !== v2[key]) {
+                return key;
+              }
+            }
+          }
+        }
+      }
+
+      exports.compareIdentifiers = compareIdentifiers;
+
+      var numeric = /^[0-9]+$/;
+      function compareIdentifiers(a, b) {
+        var anum = numeric.test(a);
+        var bnum = numeric.test(b);
+
+        if (anum && bnum) {
+          a = +a;
+          b = +b;
+        }
+
+        return anum && !bnum ? -1 : bnum && !anum ? 1 : a < b ? -1 : a > b ? 1 : 0;
+      }
+
+      exports.rcompareIdentifiers = rcompareIdentifiers;
+      function rcompareIdentifiers(a, b) {
+        return compareIdentifiers(b, a);
+      }
+
+      exports.major = major;
+      function major(a, loose) {
+        return new SemVer(a, loose).major;
+      }
+
+      exports.minor = minor;
+      function minor(a, loose) {
+        return new SemVer(a, loose).minor;
+      }
+
+      exports.patch = patch;
+      function patch(a, loose) {
+        return new SemVer(a, loose).patch;
+      }
+
+      exports.compare = compare;
+      function compare(a, b, loose) {
+        return new SemVer(a, loose).compare(new SemVer(b, loose));
+      }
+
+      exports.compareLoose = compareLoose;
+      function compareLoose(a, b) {
+        return compare(a, b, true);
+      }
+
+      exports.rcompare = rcompare;
+      function rcompare(a, b, loose) {
+        return compare(b, a, loose);
+      }
+
+      exports.sort = sort;
+      function sort(list, loose) {
+        return list.sort(function (a, b) {
+          return exports.compare(a, b, loose);
+        });
+      }
+
+      exports.rsort = rsort;
+      function rsort(list, loose) {
+        return list.sort(function (a, b) {
+          return exports.rcompare(a, b, loose);
+        });
+      }
+
+      exports.gt = gt;
+      function gt(a, b, loose) {
+        return compare(a, b, loose) > 0;
+      }
+
+      exports.lt = lt;
+      function lt(a, b, loose) {
+        return compare(a, b, loose) < 0;
+      }
+
+      exports.eq = eq;
+      function eq(a, b, loose) {
+        return compare(a, b, loose) === 0;
+      }
+
+      exports.neq = neq;
+      function neq(a, b, loose) {
+        return compare(a, b, loose) !== 0;
+      }
+
+      exports.gte = gte;
+      function gte(a, b, loose) {
+        return compare(a, b, loose) >= 0;
+      }
+
+      exports.lte = lte;
+      function lte(a, b, loose) {
+        return compare(a, b, loose) <= 0;
+      }
+
+      exports.cmp = cmp;
+      function cmp(a, op, b, loose) {
+        var ret;
+        switch (op) {
+          case '===':
+            if (typeof a === 'object') a = a.version;
+            if (typeof b === 'object') b = b.version;
+            ret = a === b;
+            break;
+          case '!==':
+            if (typeof a === 'object') a = a.version;
+            if (typeof b === 'object') b = b.version;
+            ret = a !== b;
+            break;
+          case '':
+          case '=':
+          case '==':
+            ret = eq(a, b, loose);
+            break;
+          case '!=':
+            ret = neq(a, b, loose);
+            break;
+          case '>':
+            ret = gt(a, b, loose);
+            break;
+          case '>=':
+            ret = gte(a, b, loose);
+            break;
+          case '<':
+            ret = lt(a, b, loose);
+            break;
+          case '<=':
+            ret = lte(a, b, loose);
+            break;
+          default:
+            throw new TypeError('Invalid operator: ' + op);
+        }
+        return ret;
+      }
+
+      exports.Comparator = Comparator;
+      function Comparator(comp, loose) {
+        if (comp instanceof Comparator) {
+          if (comp.loose === loose) return comp;
+          else comp = comp.value;
+        }
+
+        if (!(this instanceof Comparator)) return new Comparator(comp, loose);
+
+        debug('comparator', comp, loose);
+        this.loose = loose;
+        this.parse(comp);
+
+        if (this.semver === ANY) this.value = '';
+        else this.value = this.operator + this.semver.version;
+
+        debug('comp', this);
+      }
+
+      var ANY = {};
+      Comparator.prototype.parse = function (comp) {
+        var r = this.loose ? re[COMPARATORLOOSE] : re[COMPARATOR];
+        var m = comp.match(r);
+
+        if (!m) throw new TypeError('Invalid comparator: ' + comp);
+
+        this.operator = m[1];
+        if (this.operator === '=') this.operator = '';
+
+        // if it literally is just '>' or '' then allow anything.
+        if (!m[2]) this.semver = ANY;
+        else this.semver = new SemVer(m[2], this.loose);
+      };
+
+      Comparator.prototype.toString = function () {
+        return this.value;
+      };
+
+      Comparator.prototype.test = function (version) {
+        debug('Comparator.test', version, this.loose);
+
+        if (this.semver === ANY) return true;
+
+        if (typeof version === 'string') version = new SemVer(version, this.loose);
+
+        return cmp(version, this.operator, this.semver, this.loose);
+      };
+
+      Comparator.prototype.intersects = function (comp, loose) {
+        if (!(comp instanceof Comparator)) {
+          throw new TypeError('a Comparator is required');
+        }
+
+        var rangeTmp;
+
+        if (this.operator === '') {
+          rangeTmp = new Range(comp.value, loose);
+          return satisfies(this.value, rangeTmp, loose);
+        } else if (comp.operator === '') {
+          rangeTmp = new Range(this.value, loose);
+          return satisfies(comp.semver, rangeTmp, loose);
+        }
+
+        var sameDirectionIncreasing =
+          (this.operator === '>=' || this.operator === '>') &&
+          (comp.operator === '>=' || comp.operator === '>');
+        var sameDirectionDecreasing =
+          (this.operator === '<=' || this.operator === '<') &&
+          (comp.operator === '<=' || comp.operator === '<');
+        var sameSemVer = this.semver.version === comp.semver.version;
+        var differentDirectionsInclusive =
+          (this.operator === '>=' || this.operator === '<=') &&
+          (comp.operator === '>=' || comp.operator === '<=');
+        var oppositeDirectionsLessThan =
+          cmp(this.semver, '<', comp.semver, loose) &&
+          (this.operator === '>=' || this.operator === '>') &&
+          (comp.operator === '<=' || comp.operator === '<');
+        var oppositeDirectionsGreaterThan =
+          cmp(this.semver, '>', comp.semver, loose) &&
+          (this.operator === '<=' || this.operator === '<') &&
+          (comp.operator === '>=' || comp.operator === '>');
+
+        return (
+          sameDirectionIncreasing ||
+          sameDirectionDecreasing ||
+          (sameSemVer && differentDirectionsInclusive) ||
+          oppositeDirectionsLessThan ||
+          oppositeDirectionsGreaterThan
+        );
+      };
+
+      exports.Range = Range;
+      function Range(range, loose) {
+        if (range instanceof Range) {
+          if (range.loose === loose) {
+            return range;
+          } else {
+            return new Range(range.raw, loose);
+          }
+        }
+
+        if (range instanceof Comparator) {
+          return new Range(range.value, loose);
+        }
+
+        if (!(this instanceof Range)) return new Range(range, loose);
+
+        this.loose = loose;
+
+        // First, split based on boolean or ||
+        this.raw = range;
+        this.set = range
+          .split(/\s*\|\|\s*/)
+          .map(function (range) {
+            return this.parseRange(range.trim());
+          }, this)
+          .filter(function (c) {
+            // throw out any that are not relevant for whatever reason
+            return c.length;
+          });
+
+        if (!this.set.length) {
+          throw new TypeError('Invalid SemVer Range: ' + range);
+        }
+
+        this.format();
+      }
+
+      Range.prototype.format = function () {
+        this.range = this.set
+          .map(function (comps) {
+            return comps.join(' ').trim();
+          })
+          .join('||')
+          .trim();
+        return this.range;
+      };
+
+      Range.prototype.toString = function () {
+        return this.range;
+      };
+
+      Range.prototype.parseRange = function (range) {
+        var loose = this.loose;
+        range = range.trim();
+        debug('range', range, loose);
+        // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
+        var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE];
+        range = range.replace(hr, hyphenReplace);
+        debug('hyphen replace', range);
+        // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
+        range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace);
+        debug('comparator trim', range, re[COMPARATORTRIM]);
+
+        // `~ 1.2.3` => `~1.2.3`
+        range = range.replace(re[TILDETRIM], tildeTrimReplace);
+
+        // `^ 1.2.3` => `^1.2.3`
+        range = range.replace(re[CARETTRIM], caretTrimReplace);
+
+        // normalize spaces
+        range = range.split(/\s+/).join(' ');
+
+        // At this point, the range is completely trimmed and
+        // ready to be split into comparators.
+
+        var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR];
+        var set = range
+          .split(' ')
+          .map(function (comp) {
+            return parseComparator(comp, loose);
+          })
+          .join(' ')
+          .split(/\s+/);
+        if (this.loose) {
+          // in loose mode, throw out any that are not valid comparators
+          set = set.filter(function (comp) {
+            return !!comp.match(compRe);
+          });
+        }
+        set = set.map(function (comp) {
+          return new Comparator(comp, loose);
+        });
+
+        return set;
+      };
+
+      Range.prototype.intersects = function (range, loose) {
+        if (!(range instanceof Range)) {
+          throw new TypeError('a Range is required');
+        }
+
+        return this.set.some(function (thisComparators) {
+          return thisComparators.every(function (thisComparator) {
+            return range.set.some(function (rangeComparators) {
+              return rangeComparators.every(function (rangeComparator) {
+                return thisComparator.intersects(rangeComparator, loose);
+              });
+            });
+          });
+        });
+      };
+
+      // Mostly just for testing and legacy API reasons
+      exports.toComparators = toComparators;
+      function toComparators(range, loose) {
+        return new Range(range, loose).set.map(function (comp) {
+          return comp
+            .map(function (c) {
+              return c.value;
+            })
+            .join(' ')
+            .trim()
+            .split(' ');
+        });
+      }
+
+      // comprised of xranges, tildes, stars, and gtlt's at this point.
+      // already replaced the hyphen ranges
+      // turn into a set of JUST comparators.
+      function parseComparator(comp, loose) {
+        debug('comp', comp);
+        comp = replaceCarets(comp, loose);
+        debug('caret', comp);
+        comp = replaceTildes(comp, loose);
+        debug('tildes', comp);
+        comp = replaceXRanges(comp, loose);
+        debug('xrange', comp);
+        comp = replaceStars(comp, loose);
+        debug('stars', comp);
+        return comp;
+      }
+
+      function isX(id) {
+        return !id || id.toLowerCase() === 'x' || id === '*';
+      }
+
+      // ~, ~> --> * (any, kinda silly)
+      // ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0
+      // ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0
+      // ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0
+      // ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0
+      // ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0
+      function replaceTildes(comp, loose) {
+        return comp
+          .trim()
+          .split(/\s+/)
+          .map(function (comp) {
+            return replaceTilde(comp, loose);
+          })
+          .join(' ');
+      }
+
+      function replaceTilde(comp, loose) {
+        var r = loose ? re[TILDELOOSE] : re[TILDE];
+        return comp.replace(r, function (_, M, m, p, pr) {
+          debug('tilde', comp, _, M, m, p, pr);
+          var ret;
+
+          if (isX(M)) ret = '';
+          else if (isX(m)) ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0';
+          else if (isX(p))
+            // ~1.2 == >=1.2.0 <1.3.0
+            ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0';
+          else if (pr) {
+            debug('replaceTilde pr', pr);
+            if (pr.charAt(0) !== '-') pr = '-' + pr;
+            ret = '>=' + M + '.' + m + '.' + p + pr + ' <' + M + '.' + (+m + 1) + '.0';
+          }
+          // ~1.2.3 == >=1.2.3 <1.3.0
+          else ret = '>=' + M + '.' + m + '.' + p + ' <' + M + '.' + (+m + 1) + '.0';
+
+          debug('tilde return', ret);
+          return ret;
+        });
+      }
+
+      // ^ --> * (any, kinda silly)
+      // ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0
+      // ^2.0, ^2.0.x --> >=2.0.0 <3.0.0
+      // ^1.2, ^1.2.x --> >=1.2.0 <2.0.0
+      // ^1.2.3 --> >=1.2.3 <2.0.0
+      // ^1.2.0 --> >=1.2.0 <2.0.0
+      function replaceCarets(comp, loose) {
+        return comp
+          .trim()
+          .split(/\s+/)
+          .map(function (comp) {
+            return replaceCaret(comp, loose);
+          })
+          .join(' ');
+      }
+
+      function replaceCaret(comp, loose) {
+        debug('caret', comp, loose);
+        var r = loose ? re[CARETLOOSE] : re[CARET];
+        return comp.replace(r, function (_, M, m, p, pr) {
+          debug('caret', comp, _, M, m, p, pr);
+          var ret;
+
+          if (isX(M)) ret = '';
+          else if (isX(m)) ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0';
+          else if (isX(p)) {
+            if (M === '0') ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0';
+            else ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0';
+          } else if (pr) {
+            debug('replaceCaret pr', pr);
+            if (pr.charAt(0) !== '-') pr = '-' + pr;
+            if (M === '0') {
+              if (m === '0') ret = '>=' + M + '.' + m + '.' + p + pr + ' <' + M + '.' + m + '.' + (+p + 1);
+              else ret = '>=' + M + '.' + m + '.' + p + pr + ' <' + M + '.' + (+m + 1) + '.0';
+            } else ret = '>=' + M + '.' + m + '.' + p + pr + ' <' + (+M + 1) + '.0.0';
+          } else {
+            debug('no pr');
+            if (M === '0') {
+              if (m === '0') ret = '>=' + M + '.' + m + '.' + p + ' <' + M + '.' + m + '.' + (+p + 1);
+              else ret = '>=' + M + '.' + m + '.' + p + ' <' + M + '.' + (+m + 1) + '.0';
+            } else ret = '>=' + M + '.' + m + '.' + p + ' <' + (+M + 1) + '.0.0';
+          }
+
+          debug('caret return', ret);
+          return ret;
+        });
+      }
+
+      function replaceXRanges(comp, loose) {
+        debug('replaceXRanges', comp, loose);
+        return comp
+          .split(/\s+/)
+          .map(function (comp) {
+            return replaceXRange(comp, loose);
+          })
+          .join(' ');
+      }
+
+      function replaceXRange(comp, loose) {
+        comp = comp.trim();
+        var r = loose ? re[XRANGELOOSE] : re[XRANGE];
+        return comp.replace(r, function (ret, gtlt, M, m, p, pr) {
+          debug('xRange', comp, ret, gtlt, M, m, p, pr);
+          var xM = isX(M);
+          var xm = xM || isX(m);
+          var xp = xm || isX(p);
+          var anyX = xp;
+
+          if (gtlt === '=' && anyX) gtlt = '';
+
+          if (xM) {
+            if (gtlt === '>' || gtlt === '<') {
+              // nothing is allowed
+              ret = '<0.0.0';
+            } else {
+              // nothing is forbidden
+              ret = '*';
+            }
+          } else if (gtlt && anyX) {
+            // replace X with 0
+            if (xm) m = 0;
+            if (xp) p = 0;
+
+            if (gtlt === '>') {
+              // >1 => >=2.0.0
+              // >1.2 => >=1.3.0
+              // >1.2.3 => >= 1.2.4
+              gtlt = '>=';
+              if (xm) {
+                M = +M + 1;
+                m = 0;
+                p = 0;
+              } else if (xp) {
+                m = +m + 1;
+                p = 0;
+              }
+            } else if (gtlt === '<=') {
+              // <=0.7.x is actually <0.8.0, since any 0.7.x should
+              // pass.  Similarly, <=7.x is actually <8.0.0, etc.
+              gtlt = '<';
+              if (xm) M = +M + 1;
+              else m = +m + 1;
+            }
+
+            ret = gtlt + M + '.' + m + '.' + p;
+          } else if (xm) {
+            ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0';
+          } else if (xp) {
+            ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0';
+          }
+
+          debug('xRange return', ret);
+
+          return ret;
+        });
+      }
+
+      // Because * is AND-ed with everything else in the comparator,
+      // and '' means "any version", just remove the *s entirely.
+      function replaceStars(comp, loose) {
+        debug('replaceStars', comp, loose);
+        // Looseness is ignored here.  star is always as loose as it gets!
+        return comp.trim().replace(re[STAR], '');
+      }
+
+      // This function is passed to string.replace(re[HYPHENRANGE])
+      // M, m, patch, prerelease, build
+      // 1.2 - 3.4.5 => >=1.2.0 <=3.4.5
+      // 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do
+      // 1.2 - 3.4 => >=1.2.0 <3.5.0
+      function hyphenReplace($0, from, fM, fm, fp, fpr, fb, to, tM, tm, tp, tpr, tb) {
+        if (isX(fM)) from = '';
+        else if (isX(fm)) from = '>=' + fM + '.0.0';
+        else if (isX(fp)) from = '>=' + fM + '.' + fm + '.0';
+        else from = '>=' + from;
+
+        if (isX(tM)) to = '';
+        else if (isX(tm)) to = '<' + (+tM + 1) + '.0.0';
+        else if (isX(tp)) to = '<' + tM + '.' + (+tm + 1) + '.0';
+        else if (tpr) to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr;
+        else to = '<=' + to;
+
+        return (from + ' ' + to).trim();
+      }
+
+      // if ANY of the sets match ALL of its comparators, then pass
+      Range.prototype.test = function (version) {
+        if (!version) return false;
+
+        if (typeof version === 'string') version = new SemVer(version, this.loose);
+
+        for (var i = 0; i < this.set.length; i++) {
+          if (testSet(this.set[i], version)) return true;
+        }
+        return false;
+      };
+
+      function testSet(set, version) {
+        for (var i = 0; i < set.length; i++) {
+          if (!set[i].test(version)) return false;
+        }
+
+        if (version.prerelease.length) {
+          // Find the set of versions that are allowed to have prereleases
+          // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0
+          // That should allow `1.2.3-pr.2` to pass.
+          // However, `1.2.4-alpha.notready` should NOT be allowed,
+          // even though it's within the range set by the comparators.
+          for (var i = 0; i < set.length; i++) {
+            debug(set[i].semver);
+            if (set[i].semver === ANY) continue;
+
+            if (set[i].semver.prerelease.length > 0) {
+              var allowed = set[i].semver;
+              if (
+                allowed.major === version.major &&
+                allowed.minor === version.minor &&
+                allowed.patch === version.patch
+              )
+                return true;
+            }
+          }
+
+          // Version has a -pre, but it's not one of the ones we like.
+          return false;
+        }
+
+        return true;
+      }
+
+      exports.satisfies = satisfies;
+      function satisfies(version, range, loose) {
+        try {
+          range = new Range(range, loose);
+        } catch (er) {
+          return false;
+        }
+        return range.test(version);
+      }
+
+      exports.maxSatisfying = maxSatisfying;
+      function maxSatisfying(versions, range, loose) {
+        var max = null;
+        var maxSV = null;
+        try {
+          var rangeObj = new Range(range, loose);
+        } catch (er) {
+          return null;
+        }
+        versions.forEach(function (v) {
+          if (rangeObj.test(v)) {
+            // satisfies(v, range, loose)
+            if (!max || maxSV.compare(v) === -1) {
+              // compare(max, v, true)
+              max = v;
+              maxSV = new SemVer(max, loose);
+            }
+          }
+        });
+        return max;
+      }
+
+      exports.minSatisfying = minSatisfying;
+      function minSatisfying(versions, range, loose) {
+        var min = null;
+        var minSV = null;
+        try {
+          var rangeObj = new Range(range, loose);
+        } catch (er) {
+          return null;
+        }
+        versions.forEach(function (v) {
+          if (rangeObj.test(v)) {
+            // satisfies(v, range, loose)
+            if (!min || minSV.compare(v) === 1) {
+              // compare(min, v, true)
+              min = v;
+              minSV = new SemVer(min, loose);
+            }
+          }
+        });
+        return min;
+      }
+
+      exports.validRange = validRange;
+      function validRange(range, loose) {
+        try {
+          // Return '*' instead of '' so that truthiness works.
+          // This will throw if it's invalid anyway
+          return new Range(range, loose).range || '*';
+        } catch (er) {
+          return null;
+        }
+      }
+
+      // Determine if version is less than all the versions possible in the range
+      exports.ltr = ltr;
+      function ltr(version, range, loose) {
+        return outside(version, range, '<', loose);
+      }
+
+      // Determine if version is greater than all the versions possible in the range.
+      exports.gtr = gtr;
+      function gtr(version, range, loose) {
+        return outside(version, range, '>', loose);
+      }
+
+      exports.outside = outside;
+      function outside(version, range, hilo, loose) {
+        version = new SemVer(version, loose);
+        range = new Range(range, loose);
+
+        var gtfn, ltefn, ltfn, comp, ecomp;
+        switch (hilo) {
+          case '>':
+            gtfn = gt;
+            ltefn = lte;
+            ltfn = lt;
+            comp = '>';
+            ecomp = '>=';
+            break;
+          case '<':
+            gtfn = lt;
+            ltefn = gte;
+            ltfn = gt;
+            comp = '<';
+            ecomp = '<=';
+            break;
+          default:
+            throw new TypeError('Must provide a hilo val of "<" or ">"');
+        }
+
+        // If it satisifes the range it is not outside
+        if (satisfies(version, range, loose)) {
+          return false;
+        }
+
+        // From now on, variable terms are as if we're in "gtr" mode.
+        // but note that everything is flipped for the "ltr" function.
+
+        for (var i = 0; i < range.set.length; ++i) {
+          var comparators = range.set[i];
+
+          var high = null;
+          var low = null;
+
+          comparators.forEach(function (comparator) {
+            if (comparator.semver === ANY) {
+              comparator = new Comparator('>=0.0.0');
+            }
+            high = high || comparator;
+            low = low || comparator;
+            if (gtfn(comparator.semver, high.semver, loose)) {
+              high = comparator;
+            } else if (ltfn(comparator.semver, low.semver, loose)) {
+              low = comparator;
+            }
+          });
+
+          // If the edge version comparator has a operator then our version
+          // isn't outside it
+          if (high.operator === comp || high.operator === ecomp) {
+            return false;
+          }
+
+          // If the lowest version comparator has an operator and our version
+          // is less than it then it isn't higher than the range
+          if ((!low.operator || low.operator === comp) && ltefn(version, low.semver)) {
+            return false;
+          } else if (low.operator === ecomp && ltfn(version, low.semver)) {
+            return false;
+          }
+        }
+        return true;
+      }
+
+      exports.prerelease = prerelease;
+      function prerelease(version, loose) {
+        var parsed = parse(version, loose);
+        return parsed && parsed.prerelease.length ? parsed.prerelease : null;
+      }
+
+      exports.intersects = intersects;
+      function intersects(r1, r2, loose) {
+        r1 = new Range(r1, loose);
+        r2 = new Range(r2, loose);
+        return r1.intersects(r2);
+      }
+
+      exports.coerce = coerce;
+      function coerce(version) {
+        if (version instanceof SemVer) return version;
+
+        if (typeof version !== 'string') return null;
+
+        var match = version.match(re[COERCE]);
+
+        if (match == null) return null;
+
+        return parse((match[1] || '0') + '.' + (match[2] || '0') + '.' + (match[3] || '0'));
+      }
+
+      /***/
+    },
+    /* 23 */
+    /***/ function (module, exports) {
+      module.exports = require('stream');
+
+      /***/
+    },
+    /* 24 */
+    /***/ function (module, exports) {
+      module.exports = require('url');
+
+      /***/
+    },
+    /* 25 */
+    /***/ function (module, __webpack_exports__, __webpack_require__) {
+      'use strict';
+      /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, 'a', function () {
+        return Subscription;
+      });
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__util_isArray__ = __webpack_require__(41);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_isObject__ = __webpack_require__(444);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__util_isFunction__ = __webpack_require__(154);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__util_tryCatch__ = __webpack_require__(57);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__util_errorObject__ = __webpack_require__(48);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__ =
+        __webpack_require__(441);
+      /** PURE_IMPORTS_START _util_isArray,_util_isObject,_util_isFunction,_util_tryCatch,_util_errorObject,_util_UnsubscriptionError PURE_IMPORTS_END */
+
+      var Subscription = /*@__PURE__*/ (function () {
+        function Subscription(unsubscribe) {
+          this.closed = false;
+          this._parent = null;
+          this._parents = null;
+          this._subscriptions = null;
+          if (unsubscribe) {
+            this._unsubscribe = unsubscribe;
+          }
+        }
+        Subscription.prototype.unsubscribe = function () {
+          var hasErrors = false;
+          var errors;
+          if (this.closed) {
+            return;
+          }
+          var _a = this,
+            _parent = _a._parent,
+            _parents = _a._parents,
+            _unsubscribe = _a._unsubscribe,
+            _subscriptions = _a._subscriptions;
+          this.closed = true;
+          this._parent = null;
+          this._parents = null;
+          this._subscriptions = null;
+          var index = -1;
+          var len = _parents ? _parents.length : 0;
+          while (_parent) {
+            _parent.remove(this);
+            _parent = (++index < len && _parents[index]) || null;
+          }
+          if (
+            __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_2__util_isFunction__['a' /* isFunction */])(
+              _unsubscribe
+            )
+          ) {
+            var trial = __webpack_require__
+              .i(__WEBPACK_IMPORTED_MODULE_3__util_tryCatch__['a' /* tryCatch */])(_unsubscribe)
+              .call(this);
+            if (trial === __WEBPACK_IMPORTED_MODULE_4__util_errorObject__['a' /* errorObject */]) {
+              hasErrors = true;
+              errors =
+                errors ||
+                (__WEBPACK_IMPORTED_MODULE_4__util_errorObject__['a' /* errorObject */].e instanceof
+                __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__['a' /* UnsubscriptionError */]
+                  ? flattenUnsubscriptionErrors(
+                      __WEBPACK_IMPORTED_MODULE_4__util_errorObject__['a' /* errorObject */].e.errors
+                    )
+                  : [__WEBPACK_IMPORTED_MODULE_4__util_errorObject__['a' /* errorObject */].e]);
+            }
+          }
+          if (
+            __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__util_isArray__['a' /* isArray */])(
+              _subscriptions
+            )
+          ) {
+            index = -1;
+            len = _subscriptions.length;
+            while (++index < len) {
+              var sub = _subscriptions[index];
+              if (
+                __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_isObject__['a' /* isObject */])(sub)
+              ) {
+                var trial = __webpack_require__
+                  .i(__WEBPACK_IMPORTED_MODULE_3__util_tryCatch__['a' /* tryCatch */])(sub.unsubscribe)
+                  .call(sub);
+                if (trial === __WEBPACK_IMPORTED_MODULE_4__util_errorObject__['a' /* errorObject */]) {
+                  hasErrors = true;
+                  errors = errors || [];
+                  var err = __WEBPACK_IMPORTED_MODULE_4__util_errorObject__['a' /* errorObject */].e;
+                  if (
+                    err instanceof
+                    __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__['a' /* UnsubscriptionError */]
+                  ) {
+                    errors = errors.concat(flattenUnsubscriptionErrors(err.errors));
+                  } else {
+                    errors.push(err);
+                  }
+                }
+              }
+            }
+          }
+          if (hasErrors) {
+            throw new __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__['a' /* UnsubscriptionError */](
+              errors
+            );
+          }
+        };
+        Subscription.prototype.add = function (teardown) {
+          if (!teardown || teardown === Subscription.EMPTY) {
+            return Subscription.EMPTY;
+          }
+          if (teardown === this) {
+            return this;
+          }
+          var subscription = teardown;
+          switch (typeof teardown) {
+            case 'function':
+              subscription = new Subscription(teardown);
+            case 'object':
+              if (subscription.closed || typeof subscription.unsubscribe !== 'function') {
+                return subscription;
+              } else if (this.closed) {
+                subscription.unsubscribe();
+                return subscription;
+              } else if (typeof subscription._addParent !== 'function') {
+                var tmp = subscription;
+                subscription = new Subscription();
+                subscription._subscriptions = [tmp];
+              }
+              break;
+            default:
+              throw new Error('unrecognized teardown ' + teardown + ' added to Subscription.');
+          }
+          var subscriptions = this._subscriptions || (this._subscriptions = []);
+          subscriptions.push(subscription);
+          subscription._addParent(this);
+          return subscription;
+        };
+        Subscription.prototype.remove = function (subscription) {
+          var subscriptions = this._subscriptions;
+          if (subscriptions) {
+            var subscriptionIndex = subscriptions.indexOf(subscription);
+            if (subscriptionIndex !== -1) {
+              subscriptions.splice(subscriptionIndex, 1);
+            }
+          }
+        };
+        Subscription.prototype._addParent = function (parent) {
+          var _a = this,
+            _parent = _a._parent,
+            _parents = _a._parents;
+          if (!_parent || _parent === parent) {
+            this._parent = parent;
+          } else if (!_parents) {
+            this._parents = [parent];
+          } else if (_parents.indexOf(parent) === -1) {
+            _parents.push(parent);
+          }
+        };
+        Subscription.EMPTY = (function (empty) {
+          empty.closed = true;
+          return empty;
+        })(new Subscription());
+        return Subscription;
+      })();
+
+      function flattenUnsubscriptionErrors(errors) {
+        return errors.reduce(function (errs, err) {
+          return errs.concat(
+            err instanceof
+              __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__['a' /* UnsubscriptionError */]
+              ? err.errors
+              : err
+          );
+        }, []);
+      }
+      //# sourceMappingURL=Subscription.js.map
+
+      /***/
+    },
+    /* 26 */
+    /***/ function (module, exports, __webpack_require__) {
+      // Copyright 2015 Joyent, Inc.
+
+      module.exports = {
+        bufferSplit: bufferSplit,
+        addRSAMissing: addRSAMissing,
+        calculateDSAPublic: calculateDSAPublic,
+        calculateED25519Public: calculateED25519Public,
+        calculateX25519Public: calculateX25519Public,
+        mpNormalize: mpNormalize,
+        mpDenormalize: mpDenormalize,
+        ecNormalize: ecNormalize,
+        countZeros: countZeros,
+        assertCompatible: assertCompatible,
+        isCompatible: isCompatible,
+        opensslKeyDeriv: opensslKeyDeriv,
+        opensshCipherInfo: opensshCipherInfo,
+        publicFromPrivateECDSA: publicFromPrivateECDSA,
+        zeroPadToLength: zeroPadToLength,
+        writeBitString: writeBitString,
+        readBitString: readBitString,
+      };
+
+      var assert = __webpack_require__(16);
+      var Buffer = __webpack_require__(15).Buffer;
+      var PrivateKey = __webpack_require__(33);
+      var Key = __webpack_require__(27);
+      var crypto = __webpack_require__(11);
+      var algs = __webpack_require__(32);
+      var asn1 = __webpack_require__(66);
+
+      var ec, jsbn;
+      var nacl;
+
+      var MAX_CLASS_DEPTH = 3;
+
+      function isCompatible(obj, klass, needVer) {
+        if (obj === null || typeof obj !== 'object') return false;
+        if (needVer === undefined) needVer = klass.prototype._sshpkApiVersion;
+        if (obj instanceof klass && klass.prototype._sshpkApiVersion[0] == needVer[0]) return true;
+        var proto = Object.getPrototypeOf(obj);
+        var depth = 0;
+        while (proto.constructor.name !== klass.name) {
+          proto = Object.getPrototypeOf(proto);
+          if (!proto || ++depth > MAX_CLASS_DEPTH) return false;
+        }
+        if (proto.constructor.name !== klass.name) return false;
+        var ver = proto._sshpkApiVersion;
+        if (ver === undefined) ver = klass._oldVersionDetect(obj);
+        if (ver[0] != needVer[0] || ver[1] < needVer[1]) return false;
+        return true;
+      }
+
+      function assertCompatible(obj, klass, needVer, name) {
+        if (name === undefined) name = 'object';
+        assert.ok(obj, name + ' must not be null');
+        assert.object(obj, name + ' must be an object');
+        if (needVer === undefined) needVer = klass.prototype._sshpkApiVersion;
+        if (obj instanceof klass && klass.prototype._sshpkApiVersion[0] == needVer[0]) return;
+        var proto = Object.getPrototypeOf(obj);
+        var depth = 0;
+        while (proto.constructor.name !== klass.name) {
+          proto = Object.getPrototypeOf(proto);
+          assert.ok(proto && ++depth <= MAX_CLASS_DEPTH, name + ' must be a ' + klass.name + ' instance');
+        }
+        assert.strictEqual(
+          proto.constructor.name,
+          klass.name,
+          name + ' must be a ' + klass.name + ' instance'
+        );
+        var ver = proto._sshpkApiVersion;
+        if (ver === undefined) ver = klass._oldVersionDetect(obj);
+        assert.ok(
+          ver[0] == needVer[0] && ver[1] >= needVer[1],
+          name +
+            ' must be compatible with ' +
+            klass.name +
+            ' klass ' +
+            'version ' +
+            needVer[0] +
+            '.' +
+            needVer[1]
+        );
+      }
+
+      var CIPHER_LEN = {
+        'des-ede3-cbc': { key: 7, iv: 8 },
+        'aes-128-cbc': { key: 16, iv: 16 },
+      };
+      var PKCS5_SALT_LEN = 8;
+
+      function opensslKeyDeriv(cipher, salt, passphrase, count) {
+        assert.buffer(salt, 'salt');
+        assert.buffer(passphrase, 'passphrase');
+        assert.number(count, 'iteration count');
+
+        var clen = CIPHER_LEN[cipher];
+        assert.object(clen, 'supported cipher');
+
+        salt = salt.slice(0, PKCS5_SALT_LEN);
+
+        var D, D_prev, bufs;
+        var material = Buffer.alloc(0);
+        while (material.length < clen.key + clen.iv) {
+          bufs = [];
+          if (D_prev) bufs.push(D_prev);
+          bufs.push(passphrase);
+          bufs.push(salt);
+          D = Buffer.concat(bufs);
+          for (var j = 0; j < count; ++j) D = crypto.createHash('md5').update(D).digest();
+          material = Buffer.concat([material, D]);
+          D_prev = D;
+        }
+
+        return {
+          key: material.slice(0, clen.key),
+          iv: material.slice(clen.key, clen.key + clen.iv),
+        };
+      }
+
+      /* Count leading zero bits on a buffer */
+      function countZeros(buf) {
+        var o = 0,
+          obit = 8;
+        while (o < buf.length) {
+          var mask = 1 << obit;
+          if ((buf[o] & mask) === mask) break;
+          obit--;
+          if (obit < 0) {
+            o++;
+            obit = 8;
+          }
+        }
+        return o * 8 + (8 - obit) - 1;
+      }
+
+      function bufferSplit(buf, chr) {
+        assert.buffer(buf);
+        assert.string(chr);
+
+        var parts = [];
+        var lastPart = 0;
+        var matches = 0;
+        for (var i = 0; i < buf.length; ++i) {
+          if (buf[i] === chr.charCodeAt(matches)) ++matches;
+          else if (buf[i] === chr.charCodeAt(0)) matches = 1;
+          else matches = 0;
+
+          if (matches >= chr.length) {
+            var newPart = i + 1;
+            parts.push(buf.slice(lastPart, newPart - matches));
+            lastPart = newPart;
+            matches = 0;
+          }
+        }
+        if (lastPart <= buf.length) parts.push(buf.slice(lastPart, buf.length));
+
+        return parts;
+      }
+
+      function ecNormalize(buf, addZero) {
+        assert.buffer(buf);
+        if (buf[0] === 0x00 && buf[1] === 0x04) {
+          if (addZero) return buf;
+          return buf.slice(1);
+        } else if (buf[0] === 0x04) {
+          if (!addZero) return buf;
+        } else {
+          while (buf[0] === 0x00) buf = buf.slice(1);
+          if (buf[0] === 0x02 || buf[0] === 0x03)
+            throw new Error('Compressed elliptic curve points ' + 'are not supported');
+          if (buf[0] !== 0x04) throw new Error('Not a valid elliptic curve point');
+          if (!addZero) return buf;
+        }
+        var b = Buffer.alloc(buf.length + 1);
+        b[0] = 0x0;
+        buf.copy(b, 1);
+        return b;
+      }
+
+      function readBitString(der, tag) {
+        if (tag === undefined) tag = asn1.Ber.BitString;
+        var buf = der.readString(tag, true);
+        assert.strictEqual(
+          buf[0],
+          0x00,
+          'bit strings with unused bits are ' + 'not supported (0x' + buf[0].toString(16) + ')'
+        );
+        return buf.slice(1);
+      }
+
+      function writeBitString(der, buf, tag) {
+        if (tag === undefined) tag = asn1.Ber.BitString;
+        var b = Buffer.alloc(buf.length + 1);
+        b[0] = 0x00;
+        buf.copy(b, 1);
+        der.writeBuffer(b, tag);
+      }
+
+      function mpNormalize(buf) {
+        assert.buffer(buf);
+        while (buf.length > 1 && buf[0] === 0x00 && (buf[1] & 0x80) === 0x00) buf = buf.slice(1);
+        if ((buf[0] & 0x80) === 0x80) {
+          var b = Buffer.alloc(buf.length + 1);
+          b[0] = 0x00;
+          buf.copy(b, 1);
+          buf = b;
+        }
+        return buf;
+      }
+
+      function mpDenormalize(buf) {
+        assert.buffer(buf);
+        while (buf.length > 1 && buf[0] === 0x00) buf = buf.slice(1);
+        return buf;
+      }
+
+      function zeroPadToLength(buf, len) {
+        assert.buffer(buf);
+        assert.number(len);
+        while (buf.length > len) {
+          assert.equal(buf[0], 0x00);
+          buf = buf.slice(1);
+        }
+        while (buf.length < len) {
+          var b = Buffer.alloc(buf.length + 1);
+          b[0] = 0x00;
+          buf.copy(b, 1);
+          buf = b;
+        }
+        return buf;
+      }
+
+      function bigintToMpBuf(bigint) {
+        var buf = Buffer.from(bigint.toByteArray());
+        buf = mpNormalize(buf);
+        return buf;
+      }
+
+      function calculateDSAPublic(g, p, x) {
+        assert.buffer(g);
+        assert.buffer(p);
+        assert.buffer(x);
+        try {
+          var bigInt = __webpack_require__(81).BigInteger;
+        } catch (e) {
+          throw new Error('To load a PKCS#8 format DSA private key, ' + 'the node jsbn library is required.');
+        }
+        g = new bigInt(g);
+        p = new bigInt(p);
+        x = new bigInt(x);
+        var y = g.modPow(x, p);
+        var ybuf = bigintToMpBuf(y);
+        return ybuf;
+      }
+
+      function calculateED25519Public(k) {
+        assert.buffer(k);
+
+        if (nacl === undefined) nacl = __webpack_require__(76);
+
+        var kp = nacl.sign.keyPair.fromSeed(new Uint8Array(k));
+        return Buffer.from(kp.publicKey);
+      }
+
+      function calculateX25519Public(k) {
+        assert.buffer(k);
+
+        if (nacl === undefined) nacl = __webpack_require__(76);
+
+        var kp = nacl.box.keyPair.fromSeed(new Uint8Array(k));
+        return Buffer.from(kp.publicKey);
+      }
+
+      function addRSAMissing(key) {
+        assert.object(key);
+        assertCompatible(key, PrivateKey, [1, 1]);
+        try {
+          var bigInt = __webpack_require__(81).BigInteger;
+        } catch (e) {
+          throw new Error('To write a PEM private key from ' + 'this source, the node jsbn lib is required.');
+        }
+
+        var d = new bigInt(key.part.d.data);
+        var buf;
+
+        if (!key.part.dmodp) {
+          var p = new bigInt(key.part.p.data);
+          var dmodp = d.mod(p.subtract(1));
+
+          buf = bigintToMpBuf(dmodp);
+          key.part.dmodp = { name: 'dmodp', data: buf };
+          key.parts.push(key.part.dmodp);
+        }
+        if (!key.part.dmodq) {
+          var q = new bigInt(key.part.q.data);
+          var dmodq = d.mod(q.subtract(1));
+
+          buf = bigintToMpBuf(dmodq);
+          key.part.dmodq = { name: 'dmodq', data: buf };
+          key.parts.push(key.part.dmodq);
+        }
+      }
+
+      function publicFromPrivateECDSA(curveName, priv) {
+        assert.string(curveName, 'curveName');
+        assert.buffer(priv);
+        if (ec === undefined) ec = __webpack_require__(139);
+        if (jsbn === undefined) jsbn = __webpack_require__(81).BigInteger;
+        var params = algs.curves[curveName];
+        var p = new jsbn(params.p);
+        var a = new jsbn(params.a);
+        var b = new jsbn(params.b);
+        var curve = new ec.ECCurveFp(p, a, b);
+        var G = curve.decodePointHex(params.G.toString('hex'));
+
+        var d = new jsbn(mpNormalize(priv));
+        var pub = G.multiply(d);
+        pub = Buffer.from(curve.encodePointHex(pub), 'hex');
+
+        var parts = [];
+        parts.push({ name: 'curve', data: Buffer.from(curveName) });
+        parts.push({ name: 'Q', data: pub });
+
+        var key = new Key({ type: 'ecdsa', curve: curve, parts: parts });
+        return key;
+      }
+
+      function opensshCipherInfo(cipher) {
+        var inf = {};
+        switch (cipher) {
+          case '3des-cbc':
+            inf.keySize = 24;
+            inf.blockSize = 8;
+            inf.opensslName = 'des-ede3-cbc';
+            break;
+          case 'blowfish-cbc':
+            inf.keySize = 16;
+            inf.blockSize = 8;
+            inf.opensslName = 'bf-cbc';
+            break;
+          case 'aes128-cbc':
+          case 'aes128-ctr':
+          case 'aes128-gcm@openssh.com':
+            inf.keySize = 16;
+            inf.blockSize = 16;
+            inf.opensslName = 'aes-128-' + cipher.slice(7, 10);
+            break;
+          case 'aes192-cbc':
+          case 'aes192-ctr':
+          case 'aes192-gcm@openssh.com':
+            inf.keySize = 24;
+            inf.blockSize = 16;
+            inf.opensslName = 'aes-192-' + cipher.slice(7, 10);
+            break;
+          case 'aes256-cbc':
+          case 'aes256-ctr':
+          case 'aes256-gcm@openssh.com':
+            inf.keySize = 32;
+            inf.blockSize = 16;
+            inf.opensslName = 'aes-256-' + cipher.slice(7, 10);
+            break;
+          default:
+            throw new Error('Unsupported openssl cipher "' + cipher + '"');
+        }
+        return inf;
+      }
+
+      /***/
+    },
+    /* 27 */
+    /***/ function (module, exports, __webpack_require__) {
+      // Copyright 2017 Joyent, Inc.
+
+      module.exports = Key;
+
+      var assert = __webpack_require__(16);
+      var algs = __webpack_require__(32);
+      var crypto = __webpack_require__(11);
+      var Fingerprint = __webpack_require__(156);
+      var Signature = __webpack_require__(75);
+      var DiffieHellman = __webpack_require__(325).DiffieHellman;
+      var errs = __webpack_require__(74);
+      var utils = __webpack_require__(26);
+      var PrivateKey = __webpack_require__(33);
+      var edCompat;
+
+      try {
+        edCompat = __webpack_require__(454);
+      } catch (e) {
+        /* Just continue through, and bail out if we try to use it. */
+      }
+
+      var InvalidAlgorithmError = errs.InvalidAlgorithmError;
+      var KeyParseError = errs.KeyParseError;
+
+      var formats = {};
+      formats['auto'] = __webpack_require__(455);
+      formats['pem'] = __webpack_require__(86);
+      formats['pkcs1'] = __webpack_require__(327);
+      formats['pkcs8'] = __webpack_require__(157);
+      formats['rfc4253'] = __webpack_require__(103);
+      formats['ssh'] = __webpack_require__(456);
+      formats['ssh-private'] = __webpack_require__(193);
+      formats['openssh'] = formats['ssh-private'];
+      formats['dnssec'] = __webpack_require__(326);
+
+      function Key(opts) {
+        assert.object(opts, 'options');
+        assert.arrayOfObject(opts.parts, 'options.parts');
+        assert.string(opts.type, 'options.type');
+        assert.optionalString(opts.comment, 'options.comment');
+
+        var algInfo = algs.info[opts.type];
+        if (typeof algInfo !== 'object') throw new InvalidAlgorithmError(opts.type);
+
+        var partLookup = {};
+        for (var i = 0; i < opts.parts.length; ++i) {
+          var part = opts.parts[i];
+          partLookup[part.name] = part;
+        }
+
+        this.type = opts.type;
+        this.parts = opts.parts;
+        this.part = partLookup;
+        this.comment = undefined;
+        this.source = opts.source;
+
+        /* for speeding up hashing/fingerprint operations */
+        this._rfc4253Cache = opts._rfc4253Cache;
+        this._hashCache = {};
+
+        var sz;
+        this.curve = undefined;
+        if (this.type === 'ecdsa') {
+          var curve = this.part.curve.data.toString();
+          this.curve = curve;
+          sz = algs.curves[curve].size;
+        } else if (this.type === 'ed25519' || this.type === 'curve25519') {
+          sz = 256;
+          this.curve = 'curve25519';
+        } else {
+          var szPart = this.part[algInfo.sizePart];
+          sz = szPart.data.length;
+          sz = sz * 8 - utils.countZeros(szPart.data);
+        }
+        this.size = sz;
+      }
+
+      Key.formats = formats;
+
+      Key.prototype.toBuffer = function (format, options) {
+        if (format === undefined) format = 'ssh';
+        assert.string(format, 'format');
+        assert.object(formats[format], 'formats[format]');
+        assert.optionalObject(options, 'options');
+
+        if (format === 'rfc4253') {
+          if (this._rfc4253Cache === undefined) this._rfc4253Cache = formats['rfc4253'].write(this);
+          return this._rfc4253Cache;
+        }
+
+        return formats[format].write(this, options);
+      };
+
+      Key.prototype.toString = function (format, options) {
+        return this.toBuffer(format, options).toString();
+      };
+
+      Key.prototype.hash = function (algo) {
+        assert.string(algo, 'algorithm');
+        algo = algo.toLowerCase();
+        if (algs.hashAlgs[algo] === undefined) throw new InvalidAlgorithmError(algo);
+
+        if (this._hashCache[algo]) return this._hashCache[algo];
+        var hash = crypto.createHash(algo).update(this.toBuffer('rfc4253')).digest();
+        this._hashCache[algo] = hash;
+        return hash;
+      };
+
+      Key.prototype.fingerprint = function (algo) {
+        if (algo === undefined) algo = 'sha256';
+        assert.string(algo, 'algorithm');
+        var opts = {
+          type: 'key',
+          hash: this.hash(algo),
+          algorithm: algo,
+        };
+        return new Fingerprint(opts);
+      };
+
+      Key.prototype.defaultHashAlgorithm = function () {
+        var hashAlgo = 'sha1';
+        if (this.type === 'rsa') hashAlgo = 'sha256';
+        if (this.type === 'dsa' && this.size > 1024) hashAlgo = 'sha256';
+        if (this.type === 'ed25519') hashAlgo = 'sha512';
+        if (this.type === 'ecdsa') {
+          if (this.size <= 256) hashAlgo = 'sha256';
+          else if (this.size <= 384) hashAlgo = 'sha384';
+          else hashAlgo = 'sha512';
+        }
+        return hashAlgo;
+      };
+
+      Key.prototype.createVerify = function (hashAlgo) {
+        if (hashAlgo === undefined) hashAlgo = this.defaultHashAlgorithm();
+        assert.string(hashAlgo, 'hash algorithm');
+
+        /* ED25519 is not supported by OpenSSL, use a javascript impl. */
+        if (this.type === 'ed25519' && edCompat !== undefined) return new edCompat.Verifier(this, hashAlgo);
+        if (this.type === 'curve25519')
+          throw new Error('Curve25519 keys are not suitable for ' + 'signing or verification');
+
+        var v, nm, err;
+        try {
+          nm = hashAlgo.toUpperCase();
+          v = crypto.createVerify(nm);
+        } catch (e) {
+          err = e;
+        }
+        if (v === undefined || (err instanceof Error && err.message.match(/Unknown message digest/))) {
+          nm = 'RSA-';
+          nm += hashAlgo.toUpperCase();
+          v = crypto.createVerify(nm);
+        }
+        assert.ok(v, 'failed to create verifier');
+        var oldVerify = v.verify.bind(v);
+        var key = this.toBuffer('pkcs8');
+        var curve = this.curve;
+        var self = this;
+        v.verify = function (signature, fmt) {
+          if (Signature.isSignature(signature, [2, 0])) {
+            if (signature.type !== self.type) return false;
+            if (signature.hashAlgorithm && signature.hashAlgorithm !== hashAlgo) return false;
+            if (signature.curve && self.type === 'ecdsa' && signature.curve !== curve) return false;
+            return oldVerify(key, signature.toBuffer('asn1'));
+          } else if (typeof signature === 'string' || Buffer.isBuffer(signature)) {
+            return oldVerify(key, signature, fmt);
+
+            /*
+             * Avoid doing this on valid arguments, walking the prototype
+             * chain can be quite slow.
+             */
+          } else if (Signature.isSignature(signature, [1, 0])) {
+            throw new Error(
+              'signature was created by too old ' + 'a version of sshpk and cannot be verified'
+            );
+          } else {
+            throw new TypeError('signature must be a string, ' + 'Buffer, or Signature object');
+          }
+        };
+        return v;
+      };
+
+      Key.prototype.createDiffieHellman = function () {
+        if (this.type === 'rsa') throw new Error('RSA keys do not support Diffie-Hellman');
+
+        return new DiffieHellman(this);
+      };
+      Key.prototype.createDH = Key.prototype.createDiffieHellman;
+
+      Key.parse = function (data, format, options) {
+        if (typeof data !== 'string') assert.buffer(data, 'data');
+        if (format === undefined) format = 'auto';
+        assert.string(format, 'format');
+        if (typeof options === 'string') options = { filename: options };
+        assert.optionalObject(options, 'options');
+        if (options === undefined) options = {};
+        assert.optionalString(options.filename, 'options.filename');
+        if (options.filename === undefined) options.filename = '(unnamed)';
+
+        assert.object(formats[format], 'formats[format]');
+
+        try {
+          var k = formats[format].read(data, options);
+          if (k instanceof PrivateKey) k = k.toPublic();
+          if (!k.comment) k.comment = options.filename;
+          return k;
+        } catch (e) {
+          if (e.name === 'KeyEncryptedError') throw e;
+          throw new KeyParseError(options.filename, format, e);
+        }
+      };
+
+      Key.isKey = function (obj, ver) {
+        return utils.isCompatible(obj, Key, ver);
+      };
+
+      /*
+       * API versions for Key:
+       * [1,0] -- initial ver, may take Signature for createVerify or may not
+       * [1,1] -- added pkcs1, pkcs8 formats
+       * [1,2] -- added auto, ssh-private, openssh formats
+       * [1,3] -- added defaultHashAlgorithm
+       * [1,4] -- added ed support, createDH
+       * [1,5] -- first explicitly tagged version
+       * [1,6] -- changed ed25519 part names
+       */
+      Key.prototype._sshpkApiVersion = [1, 6];
+
+      Key._oldVersionDetect = function (obj) {
+        assert.func(obj.toBuffer);
+        assert.func(obj.fingerprint);
+        if (obj.createDH) return [1, 4];
+        if (obj.defaultHashAlgorithm) return [1, 3];
+        if (obj.formats['auto']) return [1, 2];
+        if (obj.formats['pkcs1']) return [1, 1];
+        return [1, 0];
+      };
+
+      /***/
+    },
+    /* 28 */
+    /***/ function (module, exports) {
+      module.exports = require('assert');
+
+      /***/
+    },
+    /* 29 */
+    /***/ function (module, exports, __webpack_require__) {
+      'use strict';
+
+      Object.defineProperty(exports, '__esModule', {
+        value: true,
+      });
+      exports.default = nullify;
+      function nullify(obj = {}) {
+        if (Array.isArray(obj)) {
+          for (
+            var _iterator = obj,
+              _isArray = Array.isArray(_iterator),
+              _i = 0,
+              _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();
+            ;
+
+          ) {
+            var _ref;
+
+            if (_isArray) {
+              if (_i >= _iterator.length) break;
+              _ref = _iterator[_i++];
+            } else {
+              _i = _iterator.next();
+              if (_i.done) break;
+              _ref = _i.value;
+            }
+
+            const item = _ref;
+
+            nullify(item);
+          }
+        } else if ((obj !== null && typeof obj === 'object') || typeof obj === 'function') {
+          Object.setPrototypeOf(obj, null);
+
+          // for..in can only be applied to 'object', not 'function'
+          if (typeof obj === 'object') {
+            for (const key in obj) {
+              nullify(obj[key]);
+            }
+          }
+        }
+
+        return obj;
+      }
+
+      /***/
+    },
+    /* 30 */
+    /***/ function (module, exports, __webpack_require__) {
+      'use strict';
+
+      const escapeStringRegexp = __webpack_require__(382);
+      const ansiStyles = __webpack_require__(474);
+      const stdoutColor = __webpack_require__(566).stdout;
+
+      const template = __webpack_require__(567);
+
+      const isSimpleWindowsTerm =
+        process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm');
+
+      // `supportsColor.level` → `ansiStyles.color[name]` mapping
+      const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m'];
+
+      // `color-convert` models to exclude from the Chalk API due to conflicts and such
+      const skipModels = new Set(['gray']);
+
+      const styles = Object.create(null);
+
+      function applyOptions(obj, options) {
+        options = options || {};
+
+        // Detect level if not set manually
+        const scLevel = stdoutColor ? stdoutColor.level : 0;
+        obj.level = options.level === undefined ? scLevel : options.level;
+        obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0;
+      }
+
+      function Chalk(options) {
+        // We check for this.template here since calling `chalk.constructor()`
+        // by itself will have a `this` of a previously constructed chalk object
+        if (!this || !(this instanceof Chalk) || this.template) {
+          const chalk = {};
+          applyOptions(chalk, options);
+
+          chalk.template = function () {
+            const args = [].slice.call(arguments);
+            return chalkTag.apply(null, [chalk.template].concat(args));
+          };
+
+          Object.setPrototypeOf(chalk, Chalk.prototype);
+          Object.setPrototypeOf(chalk.template, chalk);
+
+          chalk.template.constructor = Chalk;
+
+          return chalk.template;
+        }
+
+        applyOptions(this, options);
+      }
+
+      // Use bright blue on Windows as the normal blue color is illegible
+      if (isSimpleWindowsTerm) {
+        ansiStyles.blue.open = '\u001B[94m';
+      }
+
+      for (const key of Object.keys(ansiStyles)) {
+        ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g');
+
+        styles[key] = {
+          get() {
+            const codes = ansiStyles[key];
+            return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key);
+          },
+        };
+      }
+
+      styles.visible = {
+        get() {
+          return build.call(this, this._styles || [], true, 'visible');
+        },
+      };
+
+      ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g');
+      for (const model of Object.keys(ansiStyles.color.ansi)) {
+        if (skipModels.has(model)) {
+          continue;
+        }
+
+        styles[model] = {
+          get() {
+            const level = this.level;
+            return function () {
+              const open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments);
+              const codes = {
+                open,
+                close: ansiStyles.color.close,
+                closeRe: ansiStyles.color.closeRe,
+              };
+              return build.call(
+                this,
+                this._styles ? this._styles.concat(codes) : [codes],
+                this._empty,
+                model
+              );
+            };
+          },
+        };
+      }
+
+      ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g');
+      for (const model of Object.keys(ansiStyles.bgColor.ansi)) {
+        if (skipModels.has(model)) {
+          continue;
+        }
+
+        const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1);
+        styles[bgModel] = {
+          get() {
+            const level = this.level;
+            return function () {
+              const open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments);
+              const codes = {
+                open,
+                close: ansiStyles.bgColor.close,
+                closeRe: ansiStyles.bgColor.closeRe,
+              };
+              return build.call(
+                this,
+                this._styles ? this._styles.concat(codes) : [codes],
+                this._empty,
+                model
+              );
+            };
+          },
+        };
+      }
+
+      const proto = Object.defineProperties(() => {}, styles);
+
+      function build(_styles, _empty, key) {
+        const builder = function () {
+          return applyStyle.apply(builder, arguments);
+        };
+
+        builder._styles = _styles;
+        builder._empty = _empty;
+
+        const self = this;
+
+        Object.defineProperty(builder, 'level', {
+          enumerable: true,
+          get() {
+            return self.level;
+          },
+          set(level) {
+            self.level = level;
+          },
+        });
+
+        Object.defineProperty(builder, 'enabled', {
+          enumerable: true,
+          get() {
+            return self.enabled;
+          },
+          set(enabled) {
+            self.enabled = enabled;
+          },
+        });
+
+        // See below for fix regarding invisible grey/dim combination on Windows
+        builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey';
+
+        // `__proto__` is used because we must return a function, but there is
+        // no way to create a function with a different prototype
+        builder.__proto__ = proto; // eslint-disable-line no-proto
+
+        return builder;
+      }
+
+      function applyStyle() {
+        // Support varags, but simply cast to string in case there's only one arg
+        const args = arguments;
+        const argsLen = args.length;
+        let str = String(arguments[0]);
+
+        if (argsLen === 0) {
+          return '';
+        }
+
+        if (argsLen > 1) {
+          // Don't slice `arguments`, it prevents V8 optimizations
+          for (let a = 1; a < argsLen; a++) {
+            str += ' ' + args[a];
+          }
+        }
+
+        if (!this.enabled || this.level <= 0 || !str) {
+          return this._empty ? '' : str;
+        }
+
+        // Turns out that on Windows dimmed gray text becomes invisible in cmd.exe,
+        // see https://github.com/chalk/chalk/issues/58
+        // If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop.
+        const originalDim = ansiStyles.dim.open;
+        if (isSimpleWindowsTerm && this.hasGrey) {
+          ansiStyles.dim.open = '';
+        }
+
+        for (const code of this._styles.slice().reverse()) {
+          // Replace any instances already present with a re-opening code
+          // otherwise only the part of the string until said closing code
+          // will be colored, and the rest will simply be 'plain'.
+          str = code.open + str.replace(code.closeRe, code.open) + code.close;
+
+          // Close the styling before a linebreak and reopen
+          // after next line to fix a bleed issue on macOS
+          // https://github.com/chalk/chalk/pull/92
+          str = str.replace(/\r?\n/g, `${code.close}$&${code.open}`);
+        }
+
+        // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue
+        ansiStyles.dim.open = originalDim;
+
+        return str;
+      }
+
+      function chalkTag(chalk, strings) {
+        if (!Array.isArray(strings)) {
+          // If chalk() was called by itself or with a string,
+          // return the string itself as a string.
+          return [].slice.call(arguments, 1).join(' ');
+        }
+
+        const args = [].slice.call(arguments, 2);
+        const parts = [strings.raw[0]];
+
+        for (let i = 1; i < strings.length; i++) {
+          parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&'));
+          parts.push(String(strings.raw[i]));
+        }
+
+        return template(chalk, parts.join(''));
+      }
+
+      Object.defineProperties(Chalk.prototype, styles);
+
+      module.exports = Chalk(); // eslint-disable-line new-cap
+      module.exports.supportsColor = stdoutColor;
+      module.exports.default = module.exports; // For TypeScript
+
+      /***/
+    },
+    /* 31 */
+    /***/ function (module, exports) {
+      var core = (module.exports = { version: '2.5.7' });
+      if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef
+
+      /***/
+    },
+    /* 32 */
+    /***/ function (module, exports, __webpack_require__) {
+      // Copyright 2015 Joyent, Inc.
+
+      var Buffer = __webpack_require__(15).Buffer;
+
+      var algInfo = {
+        dsa: {
+          parts: ['p', 'q', 'g', 'y'],
+          sizePart: 'p',
+        },
+        rsa: {
+          parts: ['e', 'n'],
+          sizePart: 'n',
+        },
+        ecdsa: {
+          parts: ['curve', 'Q'],
+          sizePart: 'Q',
+        },
+        ed25519: {
+          parts: ['A'],
+          sizePart: 'A',
+        },
+      };
+      algInfo['curve25519'] = algInfo['ed25519'];
+
+      var algPrivInfo = {
+        dsa: {
+          parts: ['p', 'q', 'g', 'y', 'x'],
+        },
+        rsa: {
+          parts: ['n', 'e', 'd', 'iqmp', 'p', 'q'],
+        },
+        ecdsa: {
+          parts: ['curve', 'Q', 'd'],
+        },
+        ed25519: {
+          parts: ['A', 'k'],
+        },
+      };
+      algPrivInfo['curve25519'] = algPrivInfo['ed25519'];
+
+      var hashAlgs = {
+        md5: true,
+        sha1: true,
+        sha256: true,
+        sha384: true,
+        sha512: true,
+      };
+
+      /*
+       * Taken from
+       * http://csrc.nist.gov/groups/ST/toolkit/documents/dss/NISTReCur.pdf
+       */
+      var curves = {
+        nistp256: {
+          size: 256,
+          pkcs8oid: '1.2.840.10045.3.1.7',
+          p: Buffer.from(
+            ('00' + 'ffffffff 00000001 00000000 00000000' + '00000000 ffffffff ffffffff ffffffff').replace(
+              / /g,
+              ''
+            ),
+            'hex'
+          ),
+          a: Buffer.from(
+            ('00' + 'FFFFFFFF 00000001 00000000 00000000' + '00000000 FFFFFFFF FFFFFFFF FFFFFFFC').replace(
+              / /g,
+              ''
+            ),
+            'hex'
+          ),
+          b: Buffer.from(
+            ('5ac635d8 aa3a93e7 b3ebbd55 769886bc' + '651d06b0 cc53b0f6 3bce3c3e 27d2604b').replace(/ /g, ''),
+            'hex'
+          ),
+          s: Buffer.from(
+            ('00' + 'c49d3608 86e70493 6a6678e1 139d26b7' + '819f7e90').replace(/ /g, ''),
+            'hex'
+          ),
+          n: Buffer.from(
+            ('00' + 'ffffffff 00000000 ffffffff ffffffff' + 'bce6faad a7179e84 f3b9cac2 fc632551').replace(
+              / /g,
+              ''
+            ),
+            'hex'
+          ),
+          G: Buffer.from(
+            (
+              '04' +
+              '6b17d1f2 e12c4247 f8bce6e5 63a440f2' +
+              '77037d81 2deb33a0 f4a13945 d898c296' +
+              '4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16' +
+              '2bce3357 6b315ece cbb64068 37bf51f5'
+            ).replace(/ /g, ''),
+            'hex'
+          ),
+        },
+        nistp384: {
+          size: 384,
+          pkcs8oid: '1.3.132.0.34',
+          p: Buffer.from(
+            (
+              '00' +
+              'ffffffff ffffffff ffffffff ffffffff' +
+              'ffffffff ffffffff ffffffff fffffffe' +
+              'ffffffff 00000000 00000000 ffffffff'
+            ).replace(/ /g, ''),
+            'hex'
+          ),
+          a: Buffer.from(
+            (
+              '00' +
+              'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' +
+              'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE' +
+              'FFFFFFFF 00000000 00000000 FFFFFFFC'
+            ).replace(/ /g, ''),
+            'hex'
+          ),
+          b: Buffer.from(
+            (
+              'b3312fa7 e23ee7e4 988e056b e3f82d19' +
+              '181d9c6e fe814112 0314088f 5013875a' +
+              'c656398d 8a2ed19d 2a85c8ed d3ec2aef'
+            ).replace(/ /g, ''),
+            'hex'
+          ),
+          s: Buffer.from(
+            ('00' + 'a335926a a319a27a 1d00896a 6773a482' + '7acdac73').replace(/ /g, ''),
+            'hex'
+          ),
+          n: Buffer.from(
+            (
+              '00' +
+              'ffffffff ffffffff ffffffff ffffffff' +
+              'ffffffff ffffffff c7634d81 f4372ddf' +
+              '581a0db2 48b0a77a ecec196a ccc52973'
+            ).replace(/ /g, ''),
+            'hex'
+          ),
+          G: Buffer.from(
+            (
+              '04' +
+              'aa87ca22 be8b0537 8eb1c71e f320ad74' +
+              '6e1d3b62 8ba79b98 59f741e0 82542a38' +
+              '5502f25d bf55296c 3a545e38 72760ab7' +
+              '3617de4a 96262c6f 5d9e98bf 9292dc29' +
+              'f8f41dbd 289a147c e9da3113 b5f0b8c0' +
+              '0a60b1ce 1d7e819d 7a431d7c 90ea0e5f'
+            ).replace(/ /g, ''),
+            'hex'
+          ),
+        },
+        nistp521: {
+          size: 521,
+          pkcs8oid: '1.3.132.0.35',
+          p: Buffer.from(
+            (
+              '01ffffff ffffffff ffffffff ffffffff' +
+              'ffffffff ffffffff ffffffff ffffffff' +
+              'ffffffff ffffffff ffffffff ffffffff' +
+              'ffffffff ffffffff ffffffff ffffffff' +
+              'ffff'
+            ).replace(/ /g, ''),
+            'hex'
+          ),
+          a: Buffer.from(
+            (
+              '01FF' +
+              'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' +
+              'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' +
+              'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' +
+              'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFC'
+            ).replace(/ /g, ''),
+            'hex'
+          ),
+          b: Buffer.from(
+            (
+              '51' +
+              '953eb961 8e1c9a1f 929a21a0 b68540ee' +
+              'a2da725b 99b315f3 b8b48991 8ef109e1' +
+              '56193951 ec7e937b 1652c0bd 3bb1bf07' +
+              '3573df88 3d2c34f1 ef451fd4 6b503f00'
+            ).replace(/ /g, ''),
+            'hex'
+          ),
+          s: Buffer.from(
+            ('00' + 'd09e8800 291cb853 96cc6717 393284aa' + 'a0da64ba').replace(/ /g, ''),
+            'hex'
+          ),
+          n: Buffer.from(
+            (
+              '01ff' +
+              'ffffffff ffffffff ffffffff ffffffff' +
+              'ffffffff ffffffff ffffffff fffffffa' +
+              '51868783 bf2f966b 7fcc0148 f709a5d0' +
+              '3bb5c9b8 899c47ae bb6fb71e 91386409'
+            ).replace(/ /g, ''),
+            'hex'
+          ),
+          G: Buffer.from(
+            (
+              '04' +
+              '00c6 858e06b7 0404e9cd 9e3ecb66 2395b442' +
+              '9c648139 053fb521 f828af60 6b4d3dba' +
+              'a14b5e77 efe75928 fe1dc127 a2ffa8de' +
+              '3348b3c1 856a429b f97e7e31 c2e5bd66' +
+              '0118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9' +
+              '98f54449 579b4468 17afbd17 273e662c' +
+              '97ee7299 5ef42640 c550b901 3fad0761' +
+              '353c7086 a272c240 88be9476 9fd16650'
+            ).replace(/ /g, ''),
+            'hex'
+          ),
+        },
+      };
+
+      module.exports = {
+        info: algInfo,
+        privInfo: algPrivInfo,
+        hashAlgs: hashAlgs,
+        curves: curves,
+      };
+
+      /***/
+    },
+    /* 33 */
+    /***/ function (module, exports, __webpack_require__) {
+      // Copyright 2017 Joyent, Inc.
+
+      module.exports = PrivateKey;
+
+      var assert = __webpack_require__(16);
+      var Buffer = __webpack_require__(15).Buffer;
+      var algs = __webpack_require__(32);
+      var crypto = __webpack_require__(11);
+      var Fingerprint = __webpack_require__(156);
+      var Signature = __webpack_require__(75);
+      var errs = __webpack_require__(74);
+      var util = __webpack_require__(3);
+      var utils = __webpack_require__(26);
+      var dhe = __webpack_require__(325);
+      var generateECDSA = dhe.generateECDSA;
+      var generateED25519 = dhe.generateED25519;
+      var edCompat;
+      var nacl;
+
+      try {
+        edCompat = __webpack_require__(454);
+      } catch (e) {
+        /* Just continue through, and bail out if we try to use it. */
+      }
+
+      var Key = __webpack_require__(27);
+
+      var InvalidAlgorithmError = errs.InvalidAlgorithmError;
+      var KeyParseError = errs.KeyParseError;
+      var KeyEncryptedError = errs.KeyEncryptedError;
+
+      var formats = {};
+      formats['auto'] = __webpack_require__(455);
+      formats['pem'] = __webpack_require__(86);
+      formats['pkcs1'] = __webpack_require__(327);
+      formats['pkcs8'] = __webpack_require__(157);
+      formats['rfc4253'] = __webpack_require__(103);
+      formats['ssh-private'] = __webpack_require__(193);
+      formats['openssh'] = formats['ssh-private'];
+      formats['ssh'] = formats['ssh-private'];
+      formats['dnssec'] = __webpack_require__(326);
+
+      function PrivateKey(opts) {
+        assert.object(opts, 'options');
+        Key.call(this, opts);
+
+        this._pubCache = undefined;
+      }
+      util.inherits(PrivateKey, Key);
+
+      PrivateKey.formats = formats;
+
+      PrivateKey.prototype.toBuffer = function (format, options) {
+        if (format === undefined) format = 'pkcs1';
+        assert.string(format, 'format');
+        assert.object(formats[format], 'formats[format]');
+        assert.optionalObject(options, 'options');
+
+        return formats[format].write(this, options);
+      };
+
+      PrivateKey.prototype.hash = function (algo) {
+        return this.toPublic().hash(algo);
+      };
+
+      PrivateKey.prototype.toPublic = function () {
+        if (this._pubCache) return this._pubCache;
+
+        var algInfo = algs.info[this.type];
+        var pubParts = [];
+        for (var i = 0; i < algInfo.parts.length; ++i) {
+          var p = algInfo.parts[i];
+          pubParts.push(this.part[p]);
+        }
+
+        this._pubCache = new Key({
+          type: this.type,
+          source: this,
+          parts: pubParts,
+        });
+        if (this.comment) this._pubCache.comment = this.comment;
+        return this._pubCache;
+      };
+
+      PrivateKey.prototype.derive = function (newType) {
+        assert.string(newType, 'type');
+        var priv, pub, pair;
+
+        if (this.type === 'ed25519' && newType === 'curve25519') {
+          if (nacl === undefined) nacl = __webpack_require__(76);
+
+          priv = this.part.k.data;
+          if (priv[0] === 0x00) priv = priv.slice(1);
+
+          pair = nacl.box.keyPair.fromSecretKey(new Uint8Array(priv));
+          pub = Buffer.from(pair.publicKey);
+
+          return new PrivateKey({
+            type: 'curve25519',
+            parts: [
+              { name: 'A', data: utils.mpNormalize(pub) },
+              { name: 'k', data: utils.mpNormalize(priv) },
+            ],
+          });
+        } else if (this.type === 'curve25519' && newType === 'ed25519') {
+          if (nacl === undefined) nacl = __webpack_require__(76);
+
+          priv = this.part.k.data;
+          if (priv[0] === 0x00) priv = priv.slice(1);
+
+          pair = nacl.sign.keyPair.fromSeed(new Uint8Array(priv));
+          pub = Buffer.from(pair.publicKey);
+
+          return new PrivateKey({
+            type: 'ed25519',
+            parts: [
+              { name: 'A', data: utils.mpNormalize(pub) },
+              { name: 'k', data: utils.mpNormalize(priv) },
+            ],
+          });
+        }
+        throw new Error('Key derivation not supported from ' + this.type + ' to ' + newType);
+      };
+
+      PrivateKey.prototype.createVerify = function (hashAlgo) {
+        return this.toPublic().createVerify(hashAlgo);
+      };
+
+      PrivateKey.prototype.createSign = function (hashAlgo) {
+        if (hashAlgo === undefined) hashAlgo = this.defaultHashAlgorithm();
+        assert.string(hashAlgo, 'hash algorithm');
+
+        /* ED25519 is not supported by OpenSSL, use a javascript impl. */
+        if (this.type === 'ed25519' && edCompat !== undefined) return new edCompat.Signer(this, hashAlgo);
+        if (this.type === 'curve25519')
+          throw new Error('Curve25519 keys are not suitable for ' + 'signing or verification');
+
+        var v, nm, err;
+        try {
+          nm = hashAlgo.toUpperCase();
+          v = crypto.createSign(nm);
+        } catch (e) {
+          err = e;
+        }
+        if (v === undefined || (err instanceof Error && err.message.match(/Unknown message digest/))) {
+          nm = 'RSA-';
+          nm += hashAlgo.toUpperCase();
+          v = crypto.createSign(nm);
+        }
+        assert.ok(v, 'failed to create verifier');
+        var oldSign = v.sign.bind(v);
+        var key = this.toBuffer('pkcs1');
+        var type = this.type;
+        var curve = this.curve;
+        v.sign = function () {
+          var sig = oldSign(key);
+          if (typeof sig === 'string') sig = Buffer.from(sig, 'binary');
+          sig = Signature.parse(sig, type, 'asn1');
+          sig.hashAlgorithm = hashAlgo;
+          sig.curve = curve;
+          return sig;
+        };
+        return v;
+      };
+
+      PrivateKey.parse = function (data, format, options) {
+        if (typeof data !== 'string') assert.buffer(data, 'data');
+        if (format === undefined) format = 'auto';
+        assert.string(format, 'format');
+        if (typeof options === 'string') options = { filename: options };
+        assert.optionalObject(options, 'options');
+        if (options === undefined) options = {};
+        assert.optionalString(options.filename, 'options.filename');
+        if (options.filename === undefined) options.filename = '(unnamed)';
+
+        assert.object(formats[format], 'formats[format]');
+
+        try {
+          var k = formats[format].read(data, options);
+          assert.ok(k instanceof PrivateKey, 'key is not a private key');
+          if (!k.comment) k.comment = options.filename;
+          return k;
+        } catch (e) {
+          if (e.name === 'KeyEncryptedError') throw e;
+          throw new KeyParseError(options.filename, format, e);
+        }
+      };
+
+      PrivateKey.isPrivateKey = function (obj, ver) {
+        return utils.isCompatible(obj, PrivateKey, ver);
+      };
+
+      PrivateKey.generate = function (type, options) {
+        if (options === undefined) options = {};
+        assert.object(options, 'options');
+
+        switch (type) {
+          case 'ecdsa':
+            if (options.curve === undefined) options.curve = 'nistp256';
+            assert.string(options.curve, 'options.curve');
+            return generateECDSA(options.curve);
+          case 'ed25519':
+            return generateED25519();
+          default:
+            throw new Error('Key generation not supported with key ' + 'type "' + type + '"');
+        }
+      };
+
+      /*
+       * API versions for PrivateKey:
+       * [1,0] -- initial ver
+       * [1,1] -- added auto, pkcs[18], openssh/ssh-private formats
+       * [1,2] -- added defaultHashAlgorithm
+       * [1,3] -- added derive, ed, createDH
+       * [1,4] -- first tagged version
+       * [1,5] -- changed ed25519 part names and format
+       */
+      PrivateKey.prototype._sshpkApiVersion = [1, 5];
+
+      PrivateKey._oldVersionDetect = function (obj) {
+        assert.func(obj.toPublic);
+        assert.func(obj.createSign);
+        if (obj.derive) return [1, 3];
+        if (obj.defaultHashAlgorithm) return [1, 2];
+        if (obj.formats['auto']) return [1, 1];
+        return [1, 0];
+      };
+
+      /***/
+    },
+    /* 34 */
+    /***/ function (module, exports, __webpack_require__) {
+      'use strict';
+
+      Object.defineProperty(exports, '__esModule', {
+        value: true,
+      });
+      exports.wrapLifecycle = exports.run = exports.install = exports.Install = undefined;
+
+      var _extends2;
+
+      function _load_extends() {
+        return (_extends2 = _interopRequireDefault(__webpack_require__(20)));
+      }
+
+      var _asyncToGenerator2;
+
+      function _load_asyncToGenerator() {
+        return (_asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)));
+      }
+
+      let install = (exports.install = (() => {
+        var _ref29 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (
+          config,
+          reporter,
+          flags,
+          lockfile
+        ) {
+          yield wrapLifecycle(
+            config,
+            flags,
+            (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
+              const install = new Install(flags, config, reporter, lockfile);
+              yield install.init();
+            })
+          );
+        });
+
+        return function install(_x7, _x8, _x9, _x10) {
+          return _ref29.apply(this, arguments);
+        };
+      })());
+
+      let run = (exports.run = (() => {
+        var _ref31 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (
+          config,
+          reporter,
+          flags,
+          args
+        ) {
+          let lockfile;
+          let error = 'installCommandRenamed';
+          if (flags.lockfile === false) {
+            lockfile = new (_lockfile || _load_lockfile()).default();
+          } else {
+            lockfile = yield (_lockfile || _load_lockfile()).default.fromDirectory(
+              config.lockfileFolder,
+              reporter
+            );
+          }
+
+          if (args.length) {
+            const exampleArgs = args.slice();
+
+            if (flags.saveDev) {
+              exampleArgs.push('--dev');
+            }
+            if (flags.savePeer) {
+              exampleArgs.push('--peer');
+            }
+            if (flags.saveOptional) {
+              exampleArgs.push('--optional');
+            }
+            if (flags.saveExact) {
+              exampleArgs.push('--exact');
+            }
+            if (flags.saveTilde) {
+              exampleArgs.push('--tilde');
+            }
+            let command = 'add';
+            if (flags.global) {
+              error = 'globalFlagRemoved';
+              command = 'global add';
+            }
+            throw new (_errors || _load_errors()).MessageError(
+              reporter.lang(error, `yarn ${command} ${exampleArgs.join(' ')}`)
+            );
+          }
+
+          yield install(config, reporter, flags, lockfile);
+        });
+
+        return function run(_x11, _x12, _x13, _x14) {
+          return _ref31.apply(this, arguments);
+        };
+      })());
+
+      let wrapLifecycle = (exports.wrapLifecycle = (() => {
+        var _ref32 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (
+          config,
+          flags,
+          factory
+        ) {
+          yield config.executeLifecycleScript('preinstall');
+
+          yield factory();
+
+          // npm behaviour, seems kinda funky but yay compatibility
+          yield config.executeLifecycleScript('install');
+          yield config.executeLifecycleScript('postinstall');
+
+          if (!config.production) {
+            if (!config.disablePrepublish) {
+              yield config.executeLifecycleScript('prepublish');
+            }
+            yield config.executeLifecycleScript('prepare');
+          }
+        });
+
+        return function wrapLifecycle(_x15, _x16, _x17) {
+          return _ref32.apply(this, arguments);
+        };
+      })());
+
+      exports.hasWrapper = hasWrapper;
+      exports.setFlags = setFlags;
+
+      var _objectPath;
+
+      function _load_objectPath() {
+        return (_objectPath = _interopRequireDefault(__webpack_require__(304)));
+      }
+
+      var _hooks;
+
+      function _load_hooks() {
+        return (_hooks = __webpack_require__(368));
+      }
+
+      var _index;
+
+      function _load_index() {
+        return (_index = _interopRequireDefault(__webpack_require__(218)));
+      }
+
+      var _errors;
+
+      function _load_errors() {
+        return (_errors = __webpack_require__(6));
+      }
+
+      var _integrityChecker;
+
+      function _load_integrityChecker() {
+        return (_integrityChecker = _interopRequireDefault(__webpack_require__(206)));
+      }
+
+      var _lockfile;
+
+      function _load_lockfile() {
+        return (_lockfile = _interopRequireDefault(__webpack_require__(19)));
+      }
+
+      var _lockfile2;
+
+      function _load_lockfile2() {
+        return (_lockfile2 = __webpack_require__(19));
+      }
+
+      var _packageFetcher;
+
+      function _load_packageFetcher() {
+        return (_packageFetcher = _interopRequireWildcard(__webpack_require__(208)));
+      }
+
+      var _packageInstallScripts;
+
+      function _load_packageInstallScripts() {
+        return (_packageInstallScripts = _interopRequireDefault(__webpack_require__(525)));
+      }
+
+      var _packageCompatibility;
+
+      function _load_packageCompatibility() {
+        return (_packageCompatibility = _interopRequireWildcard(__webpack_require__(207)));
+      }
+
+      var _packageResolver;
+
+      function _load_packageResolver() {
+        return (_packageResolver = _interopRequireDefault(__webpack_require__(360)));
+      }
+
+      var _packageLinker;
+
+      function _load_packageLinker() {
+        return (_packageLinker = _interopRequireDefault(__webpack_require__(209)));
+      }
+
+      var _index2;
+
+      function _load_index2() {
+        return (_index2 = __webpack_require__(58));
+      }
+
+      var _index3;
+
+      function _load_index3() {
+        return (_index3 = __webpack_require__(78));
+      }
+
+      var _autoclean;
+
+      function _load_autoclean() {
+        return (_autoclean = __webpack_require__(348));
+      }
+
+      var _constants;
+
+      function _load_constants() {
+        return (_constants = _interopRequireWildcard(__webpack_require__(8)));
+      }
+
+      var _normalizePattern;
+
+      function _load_normalizePattern() {
+        return (_normalizePattern = __webpack_require__(37));
+      }
+
+      var _fs;
+
+      function _load_fs() {
+        return (_fs = _interopRequireWildcard(__webpack_require__(5)));
+      }
+
+      var _map;
+
+      function _load_map() {
+        return (_map = _interopRequireDefault(__webpack_require__(29)));
+      }
+
+      var _yarnVersion;
+
+      function _load_yarnVersion() {
+        return (_yarnVersion = __webpack_require__(105));
+      }
+
+      var _generatePnpMap;
+
+      function _load_generatePnpMap() {
+        return (_generatePnpMap = __webpack_require__(547));
+      }
+
+      var _workspaceLayout;
+
+      function _load_workspaceLayout() {
+        return (_workspaceLayout = _interopRequireDefault(__webpack_require__(90)));
+      }
+
+      var _resolutionMap;
+
+      function _load_resolutionMap() {
+        return (_resolutionMap = _interopRequireDefault(__webpack_require__(212)));
+      }
+
+      var _guessName;
+
+      function _load_guessName() {
+        return (_guessName = _interopRequireDefault(__webpack_require__(169)));
+      }
+
+      var _audit;
+
+      function _load_audit() {
+        return (_audit = _interopRequireDefault(__webpack_require__(347)));
+      }
+
+      function _interopRequireWildcard(obj) {
+        if (obj && obj.__esModule) {
+          return obj;
+        } else {
+          var newObj = {};
+          if (obj != null) {
+            for (var key in obj) {
+              if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key];
+            }
+          }
+          newObj.default = obj;
+          return newObj;
+        }
+      }
+
+      function _interopRequireDefault(obj) {
+        return obj && obj.__esModule ? obj : { default: obj };
+      }
+
+      const deepEqual = __webpack_require__(599);
+
+      const emoji = __webpack_require__(302);
+      const invariant = __webpack_require__(9);
+      const path = __webpack_require__(0);
+      const semver = __webpack_require__(22);
+      const uuid = __webpack_require__(120);
+      const ssri = __webpack_require__(65);
+
+      const ONE_DAY = 1000 * 60 * 60 * 24;
+
+      /**
+       * Try and detect the installation method for Yarn and provide a command to update it with.
+       */
+
+      function getUpdateCommand(installationMethod) {
+        if (installationMethod === 'tar') {
+          return `curl --compressed -o- -L ${(_constants || _load_constants()).YARN_INSTALLER_SH} | bash`;
+        }
+
+        if (installationMethod === 'homebrew') {
+          return 'brew upgrade yarn';
+        }
+
+        if (installationMethod === 'deb') {
+          return 'sudo apt-get update && sudo apt-get install yarn';
+        }
+
+        if (installationMethod === 'rpm') {
+          return 'sudo yum install yarn';
+        }
+
+        if (installationMethod === 'npm') {
+          return 'npm install --global yarn';
+        }
+
+        if (installationMethod === 'chocolatey') {
+          return 'choco upgrade yarn';
+        }
+
+        if (installationMethod === 'apk') {
+          return 'apk update && apk add -u yarn';
+        }
+
+        if (installationMethod === 'portage') {
+          return 'sudo emerge --sync && sudo emerge -au sys-apps/yarn';
+        }
+
+        return null;
+      }
+
+      function getUpdateInstaller(installationMethod) {
+        // Windows
+        if (installationMethod === 'msi') {
+          return (_constants || _load_constants()).YARN_INSTALLER_MSI;
+        }
+
+        return null;
+      }
+
+      function normalizeFlags(config, rawFlags) {
+        const flags = {
+          // install
+          har: !!rawFlags.har,
+          ignorePlatform: !!rawFlags.ignorePlatform,
+          ignoreEngines: !!rawFlags.ignoreEngines,
+          ignoreScripts: !!rawFlags.ignoreScripts,
+          ignoreOptional: !!rawFlags.ignoreOptional,
+          force: !!rawFlags.force,
+          flat: !!rawFlags.flat,
+          lockfile: rawFlags.lockfile !== false,
+          pureLockfile: !!rawFlags.pureLockfile,
+          updateChecksums: !!rawFlags.updateChecksums,
+          skipIntegrityCheck: !!rawFlags.skipIntegrityCheck,
+          frozenLockfile: !!rawFlags.frozenLockfile,
+          linkDuplicates: !!rawFlags.linkDuplicates,
+          checkFiles: !!rawFlags.checkFiles,
+          audit: !!rawFlags.audit,
+
+          // add
+          peer: !!rawFlags.peer,
+          dev: !!rawFlags.dev,
+          optional: !!rawFlags.optional,
+          exact: !!rawFlags.exact,
+          tilde: !!rawFlags.tilde,
+          ignoreWorkspaceRootCheck: !!rawFlags.ignoreWorkspaceRootCheck,
+
+          // outdated, update-interactive
+          includeWorkspaceDeps: !!rawFlags.includeWorkspaceDeps,
+
+          // add, remove, update
+          workspaceRootIsCwd: rawFlags.workspaceRootIsCwd !== false,
+        };
+
+        if (config.getOption('ignore-scripts')) {
+          flags.ignoreScripts = true;
+        }
+
+        if (config.getOption('ignore-platform')) {
+          flags.ignorePlatform = true;
+        }
+
+        if (config.getOption('ignore-engines')) {
+          flags.ignoreEngines = true;
+        }
+
+        if (config.getOption('ignore-optional')) {
+          flags.ignoreOptional = true;
+        }
+
+        if (config.getOption('force')) {
+          flags.force = true;
+        }
+
+        return flags;
+      }
+
+      class Install {
+        constructor(flags, config, reporter, lockfile) {
+          this.rootManifestRegistries = [];
+          this.rootPatternsToOrigin = (0, (_map || _load_map()).default)();
+          this.lockfile = lockfile;
+          this.reporter = reporter;
+          this.config = config;
+          this.flags = normalizeFlags(config, flags);
+          this.resolutions = (0, (_map || _load_map()).default)(); // Legacy resolutions field used for flat install mode
+          this.resolutionMap = new (_resolutionMap || _load_resolutionMap()).default(config); // Selective resolutions for nested dependencies
+          this.resolver = new (_packageResolver || _load_packageResolver()).default(
+            config,
+            lockfile,
+            this.resolutionMap
+          );
+          this.integrityChecker = new (_integrityChecker || _load_integrityChecker()).default(config);
+          this.linker = new (_packageLinker || _load_packageLinker()).default(config, this.resolver);
+          this.scripts = new (_packageInstallScripts || _load_packageInstallScripts()).default(
+            config,
+            this.resolver,
+            this.flags.force
+          );
+        }
+
+        /**
+         * Create a list of dependency requests from the current directories manifests.
+         */
+
+        fetchRequestFromCwd(excludePatterns = [], ignoreUnusedPatterns = false) {
+          var _this = this;
+
+          return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
+            const patterns = [];
+            const deps = [];
+            let resolutionDeps = [];
+            const manifest = {};
+
+            const ignorePatterns = [];
+            const usedPatterns = [];
+            let workspaceLayout;
+
+            // some commands should always run in the context of the entire workspace
+            const cwd =
+              _this.flags.includeWorkspaceDeps || _this.flags.workspaceRootIsCwd
+                ? _this.config.lockfileFolder
+                : _this.config.cwd;
+
+            // non-workspaces are always root, otherwise check for workspace root
+            const cwdIsRoot = !_this.config.workspaceRootFolder || _this.config.lockfileFolder === cwd;
+
+            // exclude package names that are in install args
+            const excludeNames = [];
+            for (
+              var _iterator = excludePatterns,
+                _isArray = Array.isArray(_iterator),
+                _i = 0,
+                _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();
+              ;
+
+            ) {
+              var _ref;
+
+              if (_isArray) {
+                if (_i >= _iterator.length) break;
+                _ref = _iterator[_i++];
+              } else {
+                _i = _iterator.next();
+                if (_i.done) break;
+                _ref = _i.value;
+              }
+
+              const pattern = _ref;
+
+              if ((0, (_index3 || _load_index3()).getExoticResolver)(pattern)) {
+                excludeNames.push((0, (_guessName || _load_guessName()).default)(pattern));
+              } else {
+                // extract the name
+                const parts = (0, (_normalizePattern || _load_normalizePattern()).normalizePattern)(pattern);
+                excludeNames.push(parts.name);
+              }
+            }
+
+            const stripExcluded = function stripExcluded(manifest) {
+              for (
+                var _iterator2 = excludeNames,
+                  _isArray2 = Array.isArray(_iterator2),
+                  _i2 = 0,
+                  _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();
+                ;
+
+              ) {
+                var _ref2;
+
+                if (_isArray2) {
+                  if (_i2 >= _iterator2.length) break;
+                  _ref2 = _iterator2[_i2++];
+                } else {
+                  _i2 = _iterator2.next();
+                  if (_i2.done) break;
+                  _ref2 = _i2.value;
+                }
+
+                const exclude = _ref2;
+
+                if (manifest.dependencies && manifest.dependencies[exclude]) {
+                  delete manifest.dependencies[exclude];
+                }
+                if (manifest.devDependencies && manifest.devDependencies[exclude]) {
+                  delete manifest.devDependencies[exclude];
+                }
+                if (manifest.optionalDependencies && manifest.optionalDependencies[exclude]) {
+                  delete manifest.optionalDependencies[exclude];
+                }
+              }
+            };
+
+            for (
+              var _iterator3 = Object.keys((_index2 || _load_index2()).registries),
+                _isArray3 = Array.isArray(_iterator3),
+                _i3 = 0,
+                _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();
+              ;
+
+            ) {
+              var _ref3;
+
+              if (_isArray3) {
+                if (_i3 >= _iterator3.length) break;
+                _ref3 = _iterator3[_i3++];
+              } else {
+                _i3 = _iterator3.next();
+                if (_i3.done) break;
+                _ref3 = _i3.value;
+              }
+
+              const registry = _ref3;
+
+              const filename = (_index2 || _load_index2()).registries[registry].filename;
+
+              const loc = path.join(cwd, filename);
+              if (!(yield (_fs || _load_fs()).exists(loc))) {
+                continue;
+              }
+
+              _this.rootManifestRegistries.push(registry);
+
+              const projectManifestJson = yield _this.config.readJson(loc);
+              yield (0, (_index || _load_index()).default)(projectManifestJson, cwd, _this.config, cwdIsRoot);
+
+              Object.assign(_this.resolutions, projectManifestJson.resolutions);
+              Object.assign(manifest, projectManifestJson);
+
+              _this.resolutionMap.init(_this.resolutions);
+              for (
+                var _iterator4 = Object.keys(_this.resolutionMap.resolutionsByPackage),
+                  _isArray4 = Array.isArray(_iterator4),
+                  _i4 = 0,
+                  _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();
+                ;
+
+              ) {
+                var _ref4;
+
+                if (_isArray4) {
+                  if (_i4 >= _iterator4.length) break;
+                  _ref4 = _iterator4[_i4++];
+                } else {
+                  _i4 = _iterator4.next();
+                  if (_i4.done) break;
+                  _ref4 = _i4.value;
+                }
+
+                const packageName = _ref4;
+
+                const optional =
+                  (_objectPath || _load_objectPath()).default.has(
+                    manifest.optionalDependencies,
+                    packageName
+                  ) && _this.flags.ignoreOptional;
+                for (
+                  var _iterator8 = _this.resolutionMap.resolutionsByPackage[packageName],
+                    _isArray8 = Array.isArray(_iterator8),
+                    _i8 = 0,
+                    _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();
+                  ;
+
+                ) {
+                  var _ref9;
+
+                  if (_isArray8) {
+                    if (_i8 >= _iterator8.length) break;
+                    _ref9 = _iterator8[_i8++];
+                  } else {
+                    _i8 = _iterator8.next();
+                    if (_i8.done) break;
+                    _ref9 = _i8.value;
+                  }
+
+                  const _ref8 = _ref9;
+                  const pattern = _ref8.pattern;
+
+                  resolutionDeps = [...resolutionDeps, { registry, pattern, optional, hint: 'resolution' }];
+                }
+              }
+
+              const pushDeps = function pushDeps(depType, manifest, { hint, optional }, isUsed) {
+                if (ignoreUnusedPatterns && !isUsed) {
+                  return;
+                }
+                // We only take unused dependencies into consideration to get deterministic hoisting.
+                // Since flat mode doesn't care about hoisting and everything is top level and specified then we can safely
+                // leave these out.
+                if (_this.flags.flat && !isUsed) {
+                  return;
+                }
+                const depMap = manifest[depType];
+                for (const name in depMap) {
+                  if (excludeNames.indexOf(name) >= 0) {
+                    continue;
+                  }
+
+                  let pattern = name;
+                  if (!_this.lockfile.getLocked(pattern)) {
+                    // when we use --save we save the dependency to the lockfile with just the name rather than the
+                    // version combo
+                    pattern += '@' + depMap[name];
+                  }
+
+                  // normalization made sure packages are mentioned only once
+                  if (isUsed) {
+                    usedPatterns.push(pattern);
+                  } else {
+                    ignorePatterns.push(pattern);
+                  }
+
+                  _this.rootPatternsToOrigin[pattern] = depType;
+                  patterns.push(pattern);
+                  deps.push({
+                    pattern,
+                    registry,
+                    hint,
+                    optional,
+                    workspaceName: manifest.name,
+                    workspaceLoc: manifest._loc,
+                  });
+                }
+              };
+
+              if (cwdIsRoot) {
+                pushDeps('dependencies', projectManifestJson, { hint: null, optional: false }, true);
+                pushDeps(
+                  'devDependencies',
+                  projectManifestJson,
+                  { hint: 'dev', optional: false },
+                  !_this.config.production
+                );
+                pushDeps(
+                  'optionalDependencies',
+                  projectManifestJson,
+                  { hint: 'optional', optional: true },
+                  true
+                );
+              }
+
+              if (_this.config.workspaceRootFolder) {
+                const workspaceLoc = cwdIsRoot ? loc : path.join(_this.config.lockfileFolder, filename);
+                const workspacesRoot = path.dirname(workspaceLoc);
+
+                let workspaceManifestJson = projectManifestJson;
+                if (!cwdIsRoot) {
+                  // the manifest we read before was a child workspace, so get the root
+                  workspaceManifestJson = yield _this.config.readJson(workspaceLoc);
+                  yield (0, (_index || _load_index()).default)(
+                    workspaceManifestJson,
+                    workspacesRoot,
+                    _this.config,
+                    true
+                  );
+                }
+
+                const workspaces = yield _this.config.resolveWorkspaces(
+                  workspacesRoot,
+                  workspaceManifestJson
+                );
+                workspaceLayout = new (_workspaceLayout || _load_workspaceLayout()).default(
+                  workspaces,
+                  _this.config
+                );
+
+                // add virtual manifest that depends on all workspaces, this way package hoisters and resolvers will work fine
+                const workspaceDependencies = (0, (_extends2 || _load_extends()).default)(
+                  {},
+                  workspaceManifestJson.dependencies
+                );
+                for (
+                  var _iterator5 = Object.keys(workspaces),
+                    _isArray5 = Array.isArray(_iterator5),
+                    _i5 = 0,
+                    _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();
+                  ;
+
+                ) {
+                  var _ref5;
+
+                  if (_isArray5) {
+                    if (_i5 >= _iterator5.length) break;
+                    _ref5 = _iterator5[_i5++];
+                  } else {
+                    _i5 = _iterator5.next();
+                    if (_i5.done) break;
+                    _ref5 = _i5.value;
+                  }
+
+                  const workspaceName = _ref5;
+
+                  const workspaceManifest = workspaces[workspaceName].manifest;
+                  workspaceDependencies[workspaceName] = workspaceManifest.version;
+
+                  // include dependencies from all workspaces
+                  if (_this.flags.includeWorkspaceDeps) {
+                    pushDeps('dependencies', workspaceManifest, { hint: null, optional: false }, true);
+                    pushDeps(
+                      'devDependencies',
+                      workspaceManifest,
+                      { hint: 'dev', optional: false },
+                      !_this.config.production
+                    );
+                    pushDeps(
+                      'optionalDependencies',
+                      workspaceManifest,
+                      { hint: 'optional', optional: true },
+                      true
+                    );
+                  }
+                }
+                const virtualDependencyManifest = {
+                  _uid: '',
+                  name: `workspace-aggregator-${uuid.v4()}`,
+                  version: '1.0.0',
+                  _registry: 'npm',
+                  _loc: workspacesRoot,
+                  dependencies: workspaceDependencies,
+                  devDependencies: (0, (_extends2 || _load_extends()).default)(
+                    {},
+                    workspaceManifestJson.devDependencies
+                  ),
+                  optionalDependencies: (0, (_extends2 || _load_extends()).default)(
+                    {},
+                    workspaceManifestJson.optionalDependencies
+                  ),
+                  private: workspaceManifestJson.private,
+                  workspaces: workspaceManifestJson.workspaces,
+                };
+                workspaceLayout.virtualManifestName = virtualDependencyManifest.name;
+                const virtualDep = {};
+                virtualDep[virtualDependencyManifest.name] = virtualDependencyManifest.version;
+                workspaces[virtualDependencyManifest.name] = {
+                  loc: workspacesRoot,
+                  manifest: virtualDependencyManifest,
+                };
+
+                // ensure dependencies that should be excluded are stripped from the correct manifest
+                stripExcluded(
+                  cwdIsRoot ? virtualDependencyManifest : workspaces[projectManifestJson.name].manifest
+                );
+
+                pushDeps(
+                  'workspaces',
+                  { workspaces: virtualDep },
+                  { hint: 'workspaces', optional: false },
+                  true
+                );
+
+                const implicitWorkspaceDependencies = (0, (_extends2 || _load_extends()).default)(
+                  {},
+                  workspaceDependencies
+                );
+
+                for (
+                  var _iterator6 = (_constants || _load_constants()).OWNED_DEPENDENCY_TYPES,
+                    _isArray6 = Array.isArray(_iterator6),
+                    _i6 = 0,
+                    _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();
+                  ;
+
+                ) {
+                  var _ref6;
+
+                  if (_isArray6) {
+                    if (_i6 >= _iterator6.length) break;
+                    _ref6 = _iterator6[_i6++];
+                  } else {
+                    _i6 = _iterator6.next();
+                    if (_i6.done) break;
+                    _ref6 = _i6.value;
+                  }
+
+                  const type = _ref6;
+
+                  for (
+                    var _iterator7 = Object.keys(projectManifestJson[type] || {}),
+                      _isArray7 = Array.isArray(_iterator7),
+                      _i7 = 0,
+                      _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();
+                    ;
+
+                  ) {
+                    var _ref7;
+
+                    if (_isArray7) {
+                      if (_i7 >= _iterator7.length) break;
+                      _ref7 = _iterator7[_i7++];
+                    } else {
+                      _i7 = _iterator7.next();
+                      if (_i7.done) break;
+                      _ref7 = _i7.value;
+                    }
+
+                    const dependencyName = _ref7;
+
+                    delete implicitWorkspaceDependencies[dependencyName];
+                  }
+                }
+
+                pushDeps(
+                  'dependencies',
+                  { dependencies: implicitWorkspaceDependencies },
+                  { hint: 'workspaces', optional: false },
+                  true
+                );
+              }
+
+              break;
+            }
+
+            // inherit root flat flag
+            if (manifest.flat) {
+              _this.flags.flat = true;
+            }
+
+            return {
+              requests: [...resolutionDeps, ...deps],
+              patterns,
+              manifest,
+              usedPatterns,
+              ignorePatterns,
+              workspaceLayout,
+            };
+          })();
+        }
+
+        /**
+         * TODO description
+         */
+
+        prepareRequests(requests) {
+          return requests;
+        }
+
+        preparePatterns(patterns) {
+          return patterns;
+        }
+        preparePatternsForLinking(patterns, cwdManifest, cwdIsRoot) {
+          return patterns;
+        }
+
+        prepareManifests() {
+          var _this2 = this;
+
+          return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
+            const manifests = yield _this2.config.getRootManifests();
+            return manifests;
+          })();
+        }
+
+        bailout(patterns, workspaceLayout) {
+          var _this3 = this;
+
+          return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
+            // We don't want to skip the audit - it could yield important errors
+            if (_this3.flags.audit) {
+              return false;
+            }
+            // PNP is so fast that the integrity check isn't pertinent
+            if (_this3.config.plugnplayEnabled) {
+              return false;
+            }
+            if (_this3.flags.skipIntegrityCheck || _this3.flags.force) {
+              return false;
+            }
+            const lockfileCache = _this3.lockfile.cache;
+            if (!lockfileCache) {
+              return false;
+            }
+            const lockfileClean = _this3.lockfile.parseResultType === 'success';
+            const match = yield _this3.integrityChecker.check(
+              patterns,
+              lockfileCache,
+              _this3.flags,
+              workspaceLayout
+            );
+            if (_this3.flags.frozenLockfile && (!lockfileClean || match.missingPatterns.length > 0)) {
+              throw new (_errors || _load_errors()).MessageError(_this3.reporter.lang('frozenLockfileError'));
+            }
+
+            const haveLockfile = yield (_fs || _load_fs()).exists(
+              path.join(_this3.config.lockfileFolder, (_constants || _load_constants()).LOCKFILE_FILENAME)
+            );
+
+            const lockfileIntegrityPresent = !_this3.lockfile.hasEntriesExistWithoutIntegrity();
+            const integrityBailout = lockfileIntegrityPresent || !_this3.config.autoAddIntegrity;
+
+            if (match.integrityMatches && haveLockfile && lockfileClean && integrityBailout) {
+              _this3.reporter.success(_this3.reporter.lang('upToDate'));
+              return true;
+            }
+
+            if (match.integrityFileMissing && haveLockfile) {
+              // Integrity file missing, force script installations
+              _this3.scripts.setForce(true);
+              return false;
+            }
+
+            if (match.hardRefreshRequired) {
+              // e.g. node version doesn't match, force script installations
+              _this3.scripts.setForce(true);
+              return false;
+            }
+
+            if (!patterns.length && !match.integrityFileMissing) {
+              _this3.reporter.success(_this3.reporter.lang('nothingToInstall'));
+              yield _this3.createEmptyManifestFolders();
+              yield _this3.saveLockfileAndIntegrity(patterns, workspaceLayout);
+              return true;
+            }
+
+            return false;
+          })();
+        }
+
+        /**
+         * Produce empty folders for all used root manifests.
+         */
+
+        createEmptyManifestFolders() {
+          var _this4 = this;
+
+          return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
+            if (_this4.config.modulesFolder) {
+              // already created
+              return;
+            }
+
+            for (
+              var _iterator9 = _this4.rootManifestRegistries,
+                _isArray9 = Array.isArray(_iterator9),
+                _i9 = 0,
+                _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();
+              ;
+
+            ) {
+              var _ref10;
+
+              if (_isArray9) {
+                if (_i9 >= _iterator9.length) break;
+                _ref10 = _iterator9[_i9++];
+              } else {
+                _i9 = _iterator9.next();
+                if (_i9.done) break;
+                _ref10 = _i9.value;
+              }
+
+              const registryName = _ref10;
+              const folder = _this4.config.registries[registryName].folder;
+
+              yield (_fs || _load_fs()).mkdirp(path.join(_this4.config.lockfileFolder, folder));
+            }
+          })();
+        }
+
+        /**
+         * TODO description
+         */
+
+        markIgnored(patterns) {
+          for (
+            var _iterator10 = patterns,
+              _isArray10 = Array.isArray(_iterator10),
+              _i10 = 0,
+              _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();
+            ;
+
+          ) {
+            var _ref11;
+
+            if (_isArray10) {
+              if (_i10 >= _iterator10.length) break;
+              _ref11 = _iterator10[_i10++];
+            } else {
+              _i10 = _iterator10.next();
+              if (_i10.done) break;
+              _ref11 = _i10.value;
+            }
+
+            const pattern = _ref11;
+
+            const manifest = this.resolver.getStrictResolvedPattern(pattern);
+            const ref = manifest._reference;
+            invariant(ref, 'expected package reference');
+
+            // just mark the package as ignored. if the package is used by a required package, the hoister
+            // will take care of that.
+            ref.ignore = true;
+          }
+        }
+
+        /**
+         * helper method that gets only recent manifests
+         * used by global.ls command
+         */
+        getFlattenedDeps() {
+          var _this5 = this;
+
+          return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
+            var _ref12 = yield _this5.fetchRequestFromCwd();
+
+            const depRequests = _ref12.requests,
+              rawPatterns = _ref12.patterns;
+
+            yield _this5.resolver.init(depRequests, {});
+
+            const manifests = yield (_packageFetcher || _load_packageFetcher()).fetch(
+              _this5.resolver.getManifests(),
+              _this5.config
+            );
+            _this5.resolver.updateManifests(manifests);
+
+            return _this5.flatten(rawPatterns);
+          })();
+        }
+
+        /**
+         * TODO description
+         */
+
+        init() {
+          var _this6 = this;
+
+          return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
+            _this6.checkUpdate();
+
+            // warn if we have a shrinkwrap
+            if (
+              yield (_fs || _load_fs()).exists(
+                path.join(
+                  _this6.config.lockfileFolder,
+                  (_constants || _load_constants()).NPM_SHRINKWRAP_FILENAME
+                )
+              )
+            ) {
+              _this6.reporter.warn(_this6.reporter.lang('shrinkwrapWarning'));
+            }
+
+            // warn if we have an npm lockfile
+            if (
+              yield (_fs || _load_fs()).exists(
+                path.join(_this6.config.lockfileFolder, (_constants || _load_constants()).NPM_LOCK_FILENAME)
+              )
+            ) {
+              _this6.reporter.warn(_this6.reporter.lang('npmLockfileWarning'));
+            }
+
+            if (_this6.config.plugnplayEnabled) {
+              _this6.reporter.info(_this6.reporter.lang('plugnplaySuggestV2L1'));
+              _this6.reporter.info(_this6.reporter.lang('plugnplaySuggestV2L2'));
+            }
+
+            let flattenedTopLevelPatterns = [];
+            const steps = [];
+
+            var _ref13 = yield _this6.fetchRequestFromCwd();
+
+            const depRequests = _ref13.requests,
+              rawPatterns = _ref13.patterns,
+              ignorePatterns = _ref13.ignorePatterns,
+              workspaceLayout = _ref13.workspaceLayout,
+              manifest = _ref13.manifest;
+
+            let topLevelPatterns = [];
+
+            const artifacts = yield _this6.integrityChecker.getArtifacts();
+            if (artifacts) {
+              _this6.linker.setArtifacts(artifacts);
+              _this6.scripts.setArtifacts(artifacts);
+            }
+
+            if ((_packageCompatibility || _load_packageCompatibility()).shouldCheck(manifest, _this6.flags)) {
+              steps.push(
+                (() => {
+                  var _ref14 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (
+                    curr,
+                    total
+                  ) {
+                    _this6.reporter.step(
+                      curr,
+                      total,
+                      _this6.reporter.lang('checkingManifest'),
+                      emoji.get('mag')
+                    );
+                    yield _this6.checkCompatibility();
+                  });
+
+                  return function (_x, _x2) {
+                    return _ref14.apply(this, arguments);
+                  };
+                })()
+              );
+            }
+
+            const audit = new (_audit || _load_audit()).default(_this6.config, _this6.reporter, {
+              groups: (_constants || _load_constants()).OWNED_DEPENDENCY_TYPES,
+            });
+            let auditFoundProblems = false;
+
+            steps.push(function (curr, total) {
+              return (0, (_hooks || _load_hooks()).callThroughHook)(
+                'resolveStep',
+                (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
+                  _this6.reporter.step(
+                    curr,
+                    total,
+                    _this6.reporter.lang('resolvingPackages'),
+                    emoji.get('mag')
+                  );
+                  yield _this6.resolver.init(_this6.prepareRequests(depRequests), {
+                    isFlat: _this6.flags.flat,
+                    isFrozen: _this6.flags.frozenLockfile,
+                    workspaceLayout,
+                  });
+                  topLevelPatterns = _this6.preparePatterns(rawPatterns);
+                  flattenedTopLevelPatterns = yield _this6.flatten(topLevelPatterns);
+                  return {
+                    bailout: !_this6.flags.audit && (yield _this6.bailout(topLevelPatterns, workspaceLayout)),
+                  };
+                })
+              );
+            });
+
+            if (_this6.flags.audit) {
+              steps.push(function (curr, total) {
+                return (0, (_hooks || _load_hooks()).callThroughHook)(
+                  'auditStep',
+                  (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
+                    _this6.reporter.step(curr, total, _this6.reporter.lang('auditRunning'), emoji.get('mag'));
+                    if (_this6.flags.offline) {
+                      _this6.reporter.warn(_this6.reporter.lang('auditOffline'));
+                      return { bailout: false };
+                    }
+                    const preparedManifests = yield _this6.prepareManifests();
+                    // $FlowFixMe - Flow considers `m` in the map operation to be "mixed", so does not recognize `m.object`
+                    const mergedManifest = Object.assign(
+                      {},
+                      ...Object.values(preparedManifests).map(function (m) {
+                        return m.object;
+                      })
+                    );
+                    const auditVulnerabilityCounts = yield audit.performAudit(
+                      mergedManifest,
+                      _this6.lockfile,
+                      _this6.resolver,
+                      _this6.linker,
+                      topLevelPatterns
+                    );
+                    auditFoundProblems =
+                      auditVulnerabilityCounts.info ||
+                      auditVulnerabilityCounts.low ||
+                      auditVulnerabilityCounts.moderate ||
+                      auditVulnerabilityCounts.high ||
+                      auditVulnerabilityCounts.critical;
+                    return { bailout: yield _this6.bailout(topLevelPatterns, workspaceLayout) };
+                  })
+                );
+              });
+            }
+
+            steps.push(function (curr, total) {
+              return (0, (_hooks || _load_hooks()).callThroughHook)(
+                'fetchStep',
+                (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
+                  _this6.markIgnored(ignorePatterns);
+                  _this6.reporter.step(
+                    curr,
+                    total,
+                    _this6.reporter.lang('fetchingPackages'),
+                    emoji.get('truck')
+                  );
+                  const manifests = yield (_packageFetcher || _load_packageFetcher()).fetch(
+                    _this6.resolver.getManifests(),
+                    _this6.config
+                  );
+                  _this6.resolver.updateManifests(manifests);
+                  yield (_packageCompatibility || _load_packageCompatibility()).check(
+                    _this6.resolver.getManifests(),
+                    _this6.config,
+                    _this6.flags.ignoreEngines
+                  );
+                })
+              );
+            });
+
+            steps.push(function (curr, total) {
+              return (0, (_hooks || _load_hooks()).callThroughHook)(
+                'linkStep',
+                (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
+                  // remove integrity hash to make this operation atomic
+                  yield _this6.integrityChecker.removeIntegrityFile();
+                  _this6.reporter.step(
+                    curr,
+                    total,
+                    _this6.reporter.lang('linkingDependencies'),
+                    emoji.get('link')
+                  );
+                  flattenedTopLevelPatterns = _this6.preparePatternsForLinking(
+                    flattenedTopLevelPatterns,
+                    manifest,
+                    _this6.config.lockfileFolder === _this6.config.cwd
+                  );
+                  yield _this6.linker.init(flattenedTopLevelPatterns, workspaceLayout, {
+                    linkDuplicates: _this6.flags.linkDuplicates,
+                    ignoreOptional: _this6.flags.ignoreOptional,
+                  });
+                })
+              );
+            });
+
+            if (_this6.config.plugnplayEnabled) {
+              steps.push(function (curr, total) {
+                return (0, (_hooks || _load_hooks()).callThroughHook)(
+                  'pnpStep',
+                  (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
+                    const pnpPath = `${_this6.config.lockfileFolder}/${
+                      (_constants || _load_constants()).PNP_FILENAME
+                    }`;
+
+                    const code = yield (0, (_generatePnpMap || _load_generatePnpMap()).generatePnpMap)(
+                      _this6.config,
+                      flattenedTopLevelPatterns,
+                      {
+                        resolver: _this6.resolver,
+                        reporter: _this6.reporter,
+                        targetPath: pnpPath,
+                        workspaceLayout,
+                      }
+                    );
+
+                    try {
+                      const file = yield (_fs || _load_fs()).readFile(pnpPath);
+                      if (file === code) {
+                        return;
+                      }
+                    } catch (error) {}
+
+                    yield (_fs || _load_fs()).writeFile(pnpPath, code);
+                    yield (_fs || _load_fs()).chmod(pnpPath, 0o755);
+                  })
+                );
+              });
+            }
+
+            steps.push(function (curr, total) {
+              return (0, (_hooks || _load_hooks()).callThroughHook)(
+                'buildStep',
+                (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
+                  _this6.reporter.step(
+                    curr,
+                    total,
+                    _this6.flags.force
+                      ? _this6.reporter.lang('rebuildingPackages')
+                      : _this6.reporter.lang('buildingFreshPackages'),
+                    emoji.get('hammer')
+                  );
+
+                  if (_this6.config.ignoreScripts) {
+                    _this6.reporter.warn(_this6.reporter.lang('ignoredScripts'));
+                  } else {
+                    yield _this6.scripts.init(flattenedTopLevelPatterns);
+                  }
+                })
+              );
+            });
+
+            if (_this6.flags.har) {
+              steps.push(
+                (() => {
+                  var _ref21 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (
+                    curr,
+                    total
+                  ) {
+                    const formattedDate = new Date().toISOString().replace(/:/g, '-');
+                    const filename = `yarn-install_${formattedDate}.har`;
+                    _this6.reporter.step(
+                      curr,
+                      total,
+                      _this6.reporter.lang('savingHar', filename),
+                      emoji.get('black_circle_for_record')
+                    );
+                    yield _this6.config.requestManager.saveHar(filename);
+                  });
+
+                  return function (_x3, _x4) {
+                    return _ref21.apply(this, arguments);
+                  };
+                })()
+              );
+            }
+
+            if (yield _this6.shouldClean()) {
+              steps.push(
+                (() => {
+                  var _ref22 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (
+                    curr,
+                    total
+                  ) {
+                    _this6.reporter.step(
+                      curr,
+                      total,
+                      _this6.reporter.lang('cleaningModules'),
+                      emoji.get('recycle')
+                    );
+                    yield (0, (_autoclean || _load_autoclean()).clean)(_this6.config, _this6.reporter);
+                  });
+
+                  return function (_x5, _x6) {
+                    return _ref22.apply(this, arguments);
+                  };
+                })()
+              );
+            }
+
+            let currentStep = 0;
+            for (
+              var _iterator11 = steps,
+                _isArray11 = Array.isArray(_iterator11),
+                _i11 = 0,
+                _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();
+              ;
+
+            ) {
+              var _ref23;
+
+              if (_isArray11) {
+                if (_i11 >= _iterator11.length) break;
+                _ref23 = _iterator11[_i11++];
+              } else {
+                _i11 = _iterator11.next();
+                if (_i11.done) break;
+                _ref23 = _i11.value;
+              }
+
+              const step = _ref23;
+
+              const stepResult = yield step(++currentStep, steps.length);
+              if (stepResult && stepResult.bailout) {
+                if (_this6.flags.audit) {
+                  audit.summary();
+                }
+                if (auditFoundProblems) {
+                  _this6.reporter.warn(_this6.reporter.lang('auditRunAuditForDetails'));
+                }
+                _this6.maybeOutputUpdate();
+                return flattenedTopLevelPatterns;
+              }
+            }
+
+            // fin!
+            if (_this6.flags.audit) {
+              audit.summary();
+            }
+            if (auditFoundProblems) {
+              _this6.reporter.warn(_this6.reporter.lang('auditRunAuditForDetails'));
+            }
+            yield _this6.saveLockfileAndIntegrity(topLevelPatterns, workspaceLayout);
+            yield _this6.persistChanges();
+            _this6.maybeOutputUpdate();
+            _this6.config.requestManager.clearCache();
+            return flattenedTopLevelPatterns;
+          })();
+        }
+
+        checkCompatibility() {
+          var _this7 = this;
+
+          return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
+            var _ref24 = yield _this7.fetchRequestFromCwd();
+
+            const manifest = _ref24.manifest;
+
+            yield (_packageCompatibility || _load_packageCompatibility()).checkOne(
+              manifest,
+              _this7.config,
+              _this7.flags.ignoreEngines
+            );
+          })();
+        }
+
+        persistChanges() {
+          var _this8 = this;
+
+          return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
+            // get all the different registry manifests in this folder
+            const manifests = yield _this8.config.getRootManifests();
+
+            if (yield _this8.applyChanges(manifests)) {
+              yield _this8.config.saveRootManifests(manifests);
+            }
+          })();
+        }
+
+        applyChanges(manifests) {
+          let hasChanged = false;
+
+          if (this.config.plugnplayPersist) {
+            const object = manifests.npm.object;
+
+            if (typeof object.installConfig !== 'object') {
+              object.installConfig = {};
+            }
+
+            if (this.config.plugnplayEnabled && object.installConfig.pnp !== true) {
+              object.installConfig.pnp = true;
+              hasChanged = true;
+            } else if (!this.config.plugnplayEnabled && typeof object.installConfig.pnp !== 'undefined') {
+              delete object.installConfig.pnp;
+              hasChanged = true;
+            }
+
+            if (Object.keys(object.installConfig).length === 0) {
+              delete object.installConfig;
+            }
+          }
+
+          return Promise.resolve(hasChanged);
+        }
+
+        /**
+         * Check if we should run the cleaning step.
+         */
+
+        shouldClean() {
+          return (_fs || _load_fs()).exists(
+            path.join(this.config.lockfileFolder, (_constants || _load_constants()).CLEAN_FILENAME)
+          );
+        }
+
+        /**
+         * TODO
+         */
+
+        flatten(patterns) {
+          var _this9 = this;
+
+          return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
+            if (!_this9.flags.flat) {
+              return patterns;
+            }
+
+            const flattenedPatterns = [];
+
+            for (
+              var _iterator12 = _this9.resolver.getAllDependencyNamesByLevelOrder(patterns),
+                _isArray12 = Array.isArray(_iterator12),
+                _i12 = 0,
+                _iterator12 = _isArray12 ? _iterator12 : _iterator12[Symbol.iterator]();
+              ;
+
+            ) {
+              var _ref25;
+
+              if (_isArray12) {
+                if (_i12 >= _iterator12.length) break;
+                _ref25 = _iterator12[_i12++];
+              } else {
+                _i12 = _iterator12.next();
+                if (_i12.done) break;
+                _ref25 = _i12.value;
+              }
+
+              const name = _ref25;
+
+              const infos = _this9.resolver.getAllInfoForPackageName(name).filter(function (manifest) {
+                const ref = manifest._reference;
+                invariant(ref, 'expected package reference');
+                return !ref.ignore;
+              });
+
+              if (infos.length === 0) {
+                continue;
+              }
+
+              if (infos.length === 1) {
+                // single version of this package
+                // take out a single pattern as multiple patterns may have resolved to this package
+                flattenedPatterns.push(_this9.resolver.patternsByPackage[name][0]);
+                continue;
+              }
+
+              const options = infos.map(function (info) {
+                const ref = info._reference;
+                invariant(ref, 'expected reference');
+                return {
+                  // TODO `and is required by {PARENT}`,
+                  name: _this9.reporter.lang(
+                    'manualVersionResolutionOption',
+                    ref.patterns.join(', '),
+                    info.version
+                  ),
+
+                  value: info.version,
+                };
+              });
+              const versions = infos.map(function (info) {
+                return info.version;
+              });
+              let version;
+
+              const resolutionVersion = _this9.resolutions[name];
+              if (resolutionVersion && versions.indexOf(resolutionVersion) >= 0) {
+                // use json `resolution` version
+                version = resolutionVersion;
+              } else {
+                version = yield _this9.reporter.select(
+                  _this9.reporter.lang('manualVersionResolution', name),
+                  _this9.reporter.lang('answer'),
+                  options
+                );
+                _this9.resolutions[name] = version;
+              }
+
+              flattenedPatterns.push(_this9.resolver.collapseAllVersionsOfPackage(name, version));
+            }
+
+            // save resolutions to their appropriate root manifest
+            if (Object.keys(_this9.resolutions).length) {
+              const manifests = yield _this9.config.getRootManifests();
+
+              for (const name in _this9.resolutions) {
+                const version = _this9.resolutions[name];
+
+                const patterns = _this9.resolver.patternsByPackage[name];
+                if (!patterns) {
+                  continue;
+                }
+
+                let manifest;
+                for (
+                  var _iterator13 = patterns,
+                    _isArray13 = Array.isArray(_iterator13),
+                    _i13 = 0,
+                    _iterator13 = _isArray13 ? _iterator13 : _iterator13[Symbol.iterator]();
+                  ;
+
+                ) {
+                  var _ref26;
+
+                  if (_isArray13) {
+                    if (_i13 >= _iterator13.length) break;
+                    _ref26 = _iterator13[_i13++];
+                  } else {
+                    _i13 = _iterator13.next();
+                    if (_i13.done) break;
+                    _ref26 = _i13.value;
+                  }
+
+                  const pattern = _ref26;
+
+                  manifest = _this9.resolver.getResolvedPattern(pattern);
+                  if (manifest) {
+                    break;
+                  }
+                }
+                invariant(manifest, 'expected manifest');
+
+                const ref = manifest._reference;
+                invariant(ref, 'expected reference');
+
+                const object = manifests[ref.registry].object;
+                object.resolutions = object.resolutions || {};
+                object.resolutions[name] = version;
+              }
+
+              yield _this9.config.saveRootManifests(manifests);
+            }
+
+            return flattenedPatterns;
+          })();
+        }
+
+        /**
+         * Remove offline tarballs that are no longer required
+         */
+
+        pruneOfflineMirror(lockfile) {
+          var _this10 = this;
+
+          return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
+            const mirror = _this10.config.getOfflineMirrorPath();
+            if (!mirror) {
+              return;
+            }
+
+            const requiredTarballs = new Set();
+            for (const dependency in lockfile) {
+              const resolved = lockfile[dependency].resolved;
+              if (resolved) {
+                const basename = path.basename(resolved.split('#')[0]);
+                if (dependency[0] === '@' && basename[0] !== '@') {
+                  requiredTarballs.add(`${dependency.split('/')[0]}-${basename}`);
+                }
+                requiredTarballs.add(basename);
+              }
+            }
+
+            const mirrorFiles = yield (_fs || _load_fs()).walk(mirror);
+            for (
+              var _iterator14 = mirrorFiles,
+                _isArray14 = Array.isArray(_iterator14),
+                _i14 = 0,
+                _iterator14 = _isArray14 ? _iterator14 : _iterator14[Symbol.iterator]();
+              ;
+
+            ) {
+              var _ref27;
+
+              if (_isArray14) {
+                if (_i14 >= _iterator14.length) break;
+                _ref27 = _iterator14[_i14++];
+              } else {
+                _i14 = _iterator14.next();
+                if (_i14.done) break;
+                _ref27 = _i14.value;
+              }
+
+              const file = _ref27;
+
+              const isTarball = path.extname(file.basename) === '.tgz';
+              // if using experimental-pack-script-packages-in-mirror flag, don't unlink prebuilt packages
+              const hasPrebuiltPackage = file.relative.startsWith('prebuilt/');
+              if (isTarball && !hasPrebuiltPackage && !requiredTarballs.has(file.basename)) {
+                yield (_fs || _load_fs()).unlink(file.absolute);
+              }
+            }
+          })();
+        }
+
+        /**
+         * Save updated integrity and lockfiles.
+         */
+
+        saveLockfileAndIntegrity(patterns, workspaceLayout) {
+          var _this11 = this;
+
+          return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
+            const resolvedPatterns = {};
+            Object.keys(_this11.resolver.patterns).forEach(function (pattern) {
+              if (!workspaceLayout || !workspaceLayout.getManifestByPattern(pattern)) {
+                resolvedPatterns[pattern] = _this11.resolver.patterns[pattern];
+              }
+            });
+
+            // TODO this code is duplicated in a few places, need a common way to filter out workspace patterns from lockfile
+            patterns = patterns.filter(function (p) {
+              return !workspaceLayout || !workspaceLayout.getManifestByPattern(p);
+            });
+
+            const lockfileBasedOnResolver = _this11.lockfile.getLockfile(resolvedPatterns);
+
+            if (_this11.config.pruneOfflineMirror) {
+              yield _this11.pruneOfflineMirror(lockfileBasedOnResolver);
+            }
+
+            // write integrity hash
+            if (!_this11.config.plugnplayEnabled) {
+              yield _this11.integrityChecker.save(
+                patterns,
+                lockfileBasedOnResolver,
+                _this11.flags,
+                workspaceLayout,
+                _this11.scripts.getArtifacts()
+              );
+            }
+
+            // --no-lockfile or --pure-lockfile or --frozen-lockfile
+            if (
+              _this11.flags.lockfile === false ||
+              _this11.flags.pureLockfile ||
+              _this11.flags.frozenLockfile
+            ) {
+              return;
+            }
+
+            const lockFileHasAllPatterns = patterns.every(function (p) {
+              return _this11.lockfile.getLocked(p);
+            });
+            const lockfilePatternsMatch = Object.keys(_this11.lockfile.cache || {}).every(function (p) {
+              return lockfileBasedOnResolver[p];
+            });
+            const resolverPatternsAreSameAsInLockfile = Object.keys(lockfileBasedOnResolver).every(function (
+              pattern
+            ) {
+              const manifest = _this11.lockfile.getLocked(pattern);
+              return (
+                manifest &&
+                manifest.resolved === lockfileBasedOnResolver[pattern].resolved &&
+                deepEqual(manifest.prebuiltVariants, lockfileBasedOnResolver[pattern].prebuiltVariants)
+              );
+            });
+            const integrityPatternsAreSameAsInLockfile = Object.keys(lockfileBasedOnResolver).every(function (
+              pattern
+            ) {
+              const existingIntegrityInfo = lockfileBasedOnResolver[pattern].integrity;
+              if (!existingIntegrityInfo) {
+                // if this entry does not have an integrity, no need to re-write the lockfile because of it
+                return true;
+              }
+              const manifest = _this11.lockfile.getLocked(pattern);
+              if (manifest && manifest.integrity) {
+                const manifestIntegrity = ssri.stringify(manifest.integrity);
+                return manifestIntegrity === existingIntegrityInfo;
+              }
+              return false;
+            });
+
+            // remove command is followed by install with force, lockfile will be rewritten in any case then
+            if (
+              !_this11.flags.force &&
+              _this11.lockfile.parseResultType === 'success' &&
+              lockFileHasAllPatterns &&
+              lockfilePatternsMatch &&
+              resolverPatternsAreSameAsInLockfile &&
+              integrityPatternsAreSameAsInLockfile &&
+              patterns.length
+            ) {
+              return;
+            }
+
+            // build lockfile location
+            const loc = path.join(
+              _this11.config.lockfileFolder,
+              (_constants || _load_constants()).LOCKFILE_FILENAME
+            );
+
+            // write lockfile
+            const lockSource = (0, (_lockfile2 || _load_lockfile2()).stringify)(
+              lockfileBasedOnResolver,
+              false,
+              _this11.config.enableLockfileVersions
+            );
+            yield (_fs || _load_fs()).writeFilePreservingEol(loc, lockSource);
+
+            _this11._logSuccessSaveLockfile();
+          })();
+        }
+
+        _logSuccessSaveLockfile() {
+          this.reporter.success(this.reporter.lang('savedLockfile'));
+        }
+
+        /**
+         * Load the dependency graph of the current install. Only does package resolving and wont write to the cwd.
+         */
+        hydrate(ignoreUnusedPatterns) {
+          var _this12 = this;
+
+          return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
+            const request = yield _this12.fetchRequestFromCwd([], ignoreUnusedPatterns);
+            const depRequests = request.requests,
+              rawPatterns = request.patterns,
+              ignorePatterns = request.ignorePatterns,
+              workspaceLayout = request.workspaceLayout;
+
+            yield _this12.resolver.init(depRequests, {
+              isFlat: _this12.flags.flat,
+              isFrozen: _this12.flags.frozenLockfile,
+              workspaceLayout,
+            });
+            yield _this12.flatten(rawPatterns);
+            _this12.markIgnored(ignorePatterns);
+
+            // fetch packages, should hit cache most of the time
+            const manifests = yield (_packageFetcher || _load_packageFetcher()).fetch(
+              _this12.resolver.getManifests(),
+              _this12.config
+            );
+            _this12.resolver.updateManifests(manifests);
+            yield (_packageCompatibility || _load_packageCompatibility()).check(
+              _this12.resolver.getManifests(),
+              _this12.config,
+              _this12.flags.ignoreEngines
+            );
+
+            // expand minimal manifests
+            for (
+              var _iterator15 = _this12.resolver.getManifests(),
+                _isArray15 = Array.isArray(_iterator15),
+                _i15 = 0,
+                _iterator15 = _isArray15 ? _iterator15 : _iterator15[Symbol.iterator]();
+              ;
+
+            ) {
+              var _ref28;
+
+              if (_isArray15) {
+                if (_i15 >= _iterator15.length) break;
+                _ref28 = _iterator15[_i15++];
+              } else {
+                _i15 = _iterator15.next();
+                if (_i15.done) break;
+                _ref28 = _i15.value;
+              }
+
+              const manifest = _ref28;
+
+              const ref = manifest._reference;
+              invariant(ref, 'expected reference');
+              const type = ref.remote.type;
+              // link specifier won't ever hit cache
+
+              let loc = '';
+              if (type === 'link') {
+                continue;
+              } else if (type === 'workspace') {
+                if (!ref.remote.reference) {
+                  continue;
+                }
+                loc = ref.remote.reference;
+              } else {
+                loc = _this12.config.generateModuleCachePath(ref);
+              }
+              const newPkg = yield _this12.config.readManifest(loc);
+              yield _this12.resolver.updateManifest(ref, newPkg);
+            }
+
+            return request;
+          })();
+        }
+
+        /**
+         * Check for updates every day and output a nag message if there's a newer version.
+         */
+
+        checkUpdate() {
+          if (this.config.nonInteractive) {
+            // don't show upgrade dialog on CI or non-TTY terminals
+            return;
+          }
+
+          // don't check if disabled
+          if (this.config.getOption('disable-self-update-check')) {
+            return;
+          }
+
+          // only check for updates once a day
+          const lastUpdateCheck = Number(this.config.getOption('lastUpdateCheck')) || 0;
+          if (lastUpdateCheck && Date.now() - lastUpdateCheck < ONE_DAY) {
+            return;
+          }
+
+          // don't bug for updates on tagged releases
+          if ((_yarnVersion || _load_yarnVersion()).version.indexOf('-') >= 0) {
+            return;
+          }
+
+          this._checkUpdate().catch(() => {
+            // swallow errors
+          });
+        }
+
+        _checkUpdate() {
+          var _this13 = this;
+
+          return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
+            let latestVersion = yield _this13.config.requestManager.request({
+              url: (_constants || _load_constants()).SELF_UPDATE_VERSION_URL,
+            });
+            invariant(typeof latestVersion === 'string', 'expected string');
+            latestVersion = latestVersion.trim();
+            if (!semver.valid(latestVersion)) {
+              return;
+            }
+
+            // ensure we only check for updates periodically
+            _this13.config.registries.yarn.saveHomeConfig({
+              lastUpdateCheck: Date.now(),
+            });
+
+            if (semver.gt(latestVersion, (_yarnVersion || _load_yarnVersion()).version)) {
+              const installationMethod = yield (0,
+              (_yarnVersion || _load_yarnVersion()).getInstallationMethod)();
+              _this13.maybeOutputUpdate = function () {
+                _this13.reporter.warn(
+                  _this13.reporter.lang(
+                    'yarnOutdated',
+                    latestVersion,
+                    (_yarnVersion || _load_yarnVersion()).version
+                  )
+                );
+
+                const command = getUpdateCommand(installationMethod);
+                if (command) {
+                  _this13.reporter.info(_this13.reporter.lang('yarnOutdatedCommand'));
+                  _this13.reporter.command(command);
+                } else {
+                  const installer = getUpdateInstaller(installationMethod);
+                  if (installer) {
+                    _this13.reporter.info(_this13.reporter.lang('yarnOutdatedInstaller', installer));
+                  }
+                }
+              };
+            }
+          })();
+        }
+
+        /**
+         * Method to override with a possible upgrade message.
+         */
+
+        maybeOutputUpdate() {}
+      }
+
+      exports.Install = Install;
+      function hasWrapper(commander, args) {
+        return true;
+      }
+
+      function setFlags(commander) {
+        commander.description('Yarn install is used to install all dependencies for a project.');
+        commander.usage('install [flags]');
+        commander.option('-A, --audit', 'Run vulnerability audit on installed packages');
+        commander.option('-g, --global', 'DEPRECATED');
+        commander.option('-S, --save', 'DEPRECATED - save package to your `dependencies`');
+        commander.option('-D, --save-dev', 'DEPRECATED - save package to your `devDependencies`');
+        commander.option('-P, --save-peer', 'DEPRECATED - save package to your `peerDependencies`');
+        commander.option('-O, --save-optional', 'DEPRECATED - save package to your `optionalDependencies`');
+        commander.option('-E, --save-exact', 'DEPRECATED');
+        commander.option('-T, --save-tilde', 'DEPRECATED');
+      }
+
+      /***/
+    },
+    /* 35 */
+    /***/ function (module, exports, __webpack_require__) {
+      var isObject = __webpack_require__(53);
+      module.exports = function (it) {
+        if (!isObject(it)) throw TypeError(it + ' is not an object!');
+        return it;
+      };
+
+      /***/
+    },
+    /* 36 */
+    /***/ function (module, __webpack_exports__, __webpack_require__) {
+      'use strict';
+      /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, 'b', function () {
+        return SubjectSubscriber;
+      });
+      /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, 'a', function () {
+        return Subject;
+      });
+      /* unused harmony export AnonymousSubject */
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Observable__ = __webpack_require__(12);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Subscriber__ = __webpack_require__(7);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Subscription__ = __webpack_require__(25);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__ =
+        __webpack_require__(190);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__SubjectSubscription__ = __webpack_require__(422);
+      /* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__internal_symbol_rxSubscriber__ =
+        __webpack_require__(321);
+      /** PURE_IMPORTS_START tslib,_Observable,_Subscriber,_Subscription,_util_ObjectUnsubscribedError,_SubjectSubscription,_internal_symbol_rxSubscriber PURE_IMPORTS_END */
+
+      var SubjectSubscriber = /*@__PURE__*/ (function (_super) {
+        __WEBPACK_IMPORTED_MODULE_0_tslib__['a' /* __extends */](SubjectSubscriber, _super);
+        function SubjectSubscriber(destination) {
+          var _this = _super.call(this, destination) || this;
+          _this.destination = destination;
+          return _this;
+        }
+        return SubjectSubscriber;
+      })(__WEBPACK_IMPORTED_MODULE_2__Subscriber__['a' /* Subscriber */]);
+
+      var Subject = /*@__PURE__*/ (function (_super) {
+        __WEBPACK_IMPORTED_MODULE_0_tslib__['a' /* __extends */](Subject, _super);
+        function Subject() {
+          var _this = _super.call(this) || this;
+          _this.observers = [];
+          _this.closed = false;
+          _this.isStopped = false;
+          _this.hasError = false;
+          _this.thrownError = null;
+          return _this;
+        }
+        Subject.prototype[
+          __WEBPACK_IMPORTED_MODULE_6__internal_symbol_rxSubscriber__['a' /* rxSubscriber */]
+        ] = function () {
+          return new SubjectSubscriber(this);
+        };
+        Subject.prototype.lift = function (operator) {
+          var subject = new AnonymousSubject(this, this);
+          subject.operator = operator;
+          return subject;
+        };
+        Subject.prototype.next = function (value) {
+          if (this.closed) {
+            throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__[
+              'a' /* ObjectUnsubscribedError */
+            ]();
+          }
+          if (!this.isStopped) {
+            var observers = this.observers;
+            var len = observers.length;
+            var copy = observers.slice();
+            for (var i = 0; i < len; i++) {
+              copy[i].next(value);
+            }
+          }
+        };
+        Subject.prototype.error = function (err) {
+          if (this.closed) {
+            throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__[
+              'a' /* ObjectUnsubscribedError */
+            ]();
+          }
+          this.hasError = true;
+          this.thrownError = err;
+          this.isStopped = true;
+          var observers = this.observers;
+          var len = observers.length;
+          var copy = observers.slice();
+          for (var i = 0; i < len; i++) {
+            copy[i].error(err);
+          }
+          this.observers.length = 0;
+        };
+        Subject.prototype.complete = function () {
+          if (this.closed) {
+            throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__[
+              'a' /* ObjectUnsubscribedError */
+            ]();
+          }
+          this.isStopped = true;
+          var observers = this.observers;
+          var len = observers.length;
+          var copy = observers.slice();
+          for (var i = 0; i < len; i++) {
+            copy[i].complete();
+          }
+          this.observers.length = 0;
+        };
+        Subject.prototype.unsubscribe = function () {
+          this.isStopped = true;
+          this.closed = true;
+          this.observers = null;
+        };
+        Subject.prototype._trySubscribe = function (subscriber) {
+          if (this.closed) {
+            throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__[
+              'a' /* ObjectUnsubscribedError */
+            ]();
+          } else {
+            return _super.prototype._trySubscribe.call(this, subscriber);
+          }
+        };
+        Subject.prototype._subscribe = function (subscriber) {
+          if (this.closed) {
+            throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__[
+              'a' /* ObjectUnsubscribedError */
+            ]();
+          } else if (this.hasError) {
+            subscriber.error(this.thrownError);
+            return __WEBPACK_IMPORTED_MODULE_3__Subscription__['a' /* Subscription */].EMPTY;
+          } else if (this.isStopped) {
+            subscriber.complete();
+            return __WEBPACK_IMPORTED_MODULE_3__Subscription__['a' /* Subscription */].EMPTY;
+          } else {
+            this.observers.push(subscriber);
+            return new __WEBPACK_IMPORTED_MODULE_5__SubjectSubscription__['a' /* SubjectSubscription */](
+              this,
+              subscriber
+            );
+          }
+        };
+        Subject.prototype.asObservable = function () {
+          var observable = new __WEBPACK_IMPORTED_MODULE_1__Observable__['a' /* Observable */]();
+          observable.source = this;
+          return observable;
+        };
+        Subject.create = function (destination, source) {
+          return new AnonymousSubject(destination, source);
+        };
+        return Subject;
+      })(__WEBPACK_IMPORTED_MODULE_1__Observable__['a' /* Observable */]);
+
+      var AnonymousSubject = /*@__PURE__*/ (function (_super) {
+        __WEBPACK_IMPORTED_MODULE_0_tslib__['a' /* __extends */](AnonymousSubject, _super);
+        function AnonymousSubject(destination, source) {
+          var _this = _super.call(this) || this;
+          _this.destination = destination;
+          _this.source = source;
+          return _this;
+        }
+        AnonymousSubject.prototype.next = function (value) {
+          var destination = this.destination;
+          if (destination && destination.next) {
+            destination.next(value);
+          }
+        };
+        AnonymousSubject.prototype.error = function (err) {
+          var destination = this.destination;
+          if (destination && destination.error) {
+            this.destination.error(err);
+          }
+        };
+        AnonymousSubject.prototype.complete = function () {
+          var destination = this.destination;
+          if (destination && destination.complete) {
+            this.destination.complete();
+          }
+        };
+        AnonymousSubject.prototype._subscribe = function (subscriber) {
+          var source = this.source;
+          if (source) {
+            return this.source.subscribe(subscriber);
+          } else {
+            return __WEBPACK_IMPORTED_MODULE_3__Subscription__['a' /* Subscription */].EMPTY;
+          }
+        };
+        return AnonymousSubject;
+      })(Subject);
+
+      //# sourceMappingURL=Subject.js.map
+
+      /***/
+    },
+    /* 37 */
+    /***/ function (module, exports, __webpack_require__) {
+      'use strict';
+
+      Object.defineProperty(exports, '__esModule', {
+        value: true,
+      });
+      exports.normalizePattern = normalizePattern;
+
+      /**
+       * Explode and normalize a pattern into its name and range.
+       */
+
+      function normalizePattern(pattern) {
+        let hasVersion = false;
+        let range = 'latest';
+        let name = pattern;
+
+        // if we're a scope then remove the @ and add it back later
+        let isScoped = false;
+        if (name[0] === '@') {
+          isScoped = true;
+          name = name.slice(1);
+        }
+
+        // take first part as the name
+        const parts = name.split('@');
+        if (parts.length > 1) {
+          name = parts.shift();
+          range = parts.join('@');
+
+          if (range) {
+            hasVersion = true;
+          } else {
+            range = '*';
+          }
+        }
+
+        // add back @ scope suffix
+        if (isScoped) {
+          name = `@${name}`;
+        }
+
+        return { name, range, hasVersion };
+      }
+
+      /***/
+    },
+    /* 38 */
+    /***/ function (module, exports, __webpack_require__) {
+      /* WEBPACK VAR INJECTION */ (function (module) {
+        var __WEBPACK_AMD_DEFINE_RESULT__;
+        /**
+         * @license
+         * Lodash 
+         * Copyright JS Foundation and other contributors 
+         * Released under MIT license 
+         * Based on Underscore.js 1.8.3 
+         * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+         */
+        (function () {
+          /** Used as a safe reference for `undefined` in pre-ES5 environments. */
+          var undefined;
+
+          /** Used as the semantic version number. */
+          var VERSION = '4.17.10';
+
+          /** Used as the size to enable large array optimizations. */
+          var LARGE_ARRAY_SIZE = 200;
+
+          /** Error message constants. */
+          var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.',
+            FUNC_ERROR_TEXT = 'Expected a function';
+
+          /** Used to stand-in for `undefined` hash values. */
+          var HASH_UNDEFINED = '__lodash_hash_undefined__';
+
+          /** Used as the maximum memoize cache size. */
+          var MAX_MEMOIZE_SIZE = 500;
+
+          /** Used as the internal argument placeholder. */
+          var PLACEHOLDER = '__lodash_placeholder__';
+
+          /** Used to compose bitmasks for cloning. */
+          var CLONE_DEEP_FLAG = 1,
+            CLONE_FLAT_FLAG = 2,
+            CLONE_SYMBOLS_FLAG = 4;
+
+          /** Used to compose bitmasks for value comparisons. */
+          var COMPARE_PARTIAL_FLAG = 1,
+            COMPARE_UNORDERED_FLAG = 2;
+
+          /** Used to compose bitmasks for function metadata. */
+          var WRAP_BIND_FLAG = 1,
+            WRAP_BIND_KEY_FLAG = 2,
+            WRAP_CURRY_BOUND_FLAG = 4,
+            WRAP_CURRY_FLAG = 8,
+            WRAP_CURRY_RIGHT_FLAG = 16,
+            WRAP_PARTIAL_FLAG = 32,
+            WRAP_PARTIAL_RIGHT_FLAG = 64,
+            WRAP_ARY_FLAG = 128,
+            WRAP_REARG_FLAG = 256,
+            WRAP_FLIP_FLAG = 512;
+
+          /** Used as default options for `_.truncate`. */
+          var DEFAULT_TRUNC_LENGTH = 30,
+            DEFAULT_TRUNC_OMISSION = '...';
+
+          /** Used to detect hot functions by number of calls within a span of milliseconds. */
+          var HOT_COUNT = 800,
+            HOT_SPAN = 16;
+
+          /** Used to indicate the type of lazy iteratees. */
+          var LAZY_FILTER_FLAG = 1,
+            LAZY_MAP_FLAG = 2,
+            LAZY_WHILE_FLAG = 3;
+
+          /** Used as references for various `Number` constants. */
+          var INFINITY = 1 / 0,
+            MAX_SAFE_INTEGER = 9007199254740991,
+            MAX_INTEGER = 1.7976931348623157e308,
+            NAN = 0 / 0;
+
+          /** Used as references for the maximum length and index of an array. */
+          var MAX_ARRAY_LENGTH = 4294967295,
+            MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1,
+            HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;
+
+          /** Used to associate wrap methods with their bit flags. */
+          var wrapFlags = [
+            ['ary', WRAP_ARY_FLAG],
+            ['bind', WRAP_BIND_FLAG],
+            ['bindKey', WRAP_BIND_KEY_FLAG],
+            ['curry', WRAP_CURRY_FLAG],
+            ['curryRight', WRAP_CURRY_RIGHT_FLAG],
+            ['flip', WRAP_FLIP_FLAG],
+            ['partial', WRAP_PARTIAL_FLAG],
+            ['partialRight', WRAP_PARTIAL_RIGHT_FLAG],
+            ['rearg', WRAP_REARG_FLAG],
+          ];
+
+          /** `Object#toString` result references. */
+          var argsTag = '[object Arguments]',
+            arrayTag = '[object Array]',
+            asyncTag = '[object AsyncFunction]',
+            boolTag = '[object Boolean]',
+            dateTag = '[object Date]',
+            domExcTag = '[object DOMException]',
+            errorTag = '[object Error]',
+            funcTag = '[object Function]',
+            genTag = '[object GeneratorFunction]',
+            mapTag = '[object Map]',
+            numberTag = '[object Number]',
+            nullTag = '[object Null]',
+            objectTag = '[object Object]',
+            promiseTag = '[object Promise]',
+            proxyTag = '[object Proxy]',
+            regexpTag = '[object RegExp]',
+            setTag = '[object Set]',
+            stringTag = '[object String]',
+            symbolTag = '[object Symbol]',
+            undefinedTag = '[object Undefined]',
+            weakMapTag = '[object WeakMap]',
+            weakSetTag = '[object WeakSet]';
+
+          var arrayBufferTag = '[object ArrayBuffer]',
+            dataViewTag = '[object DataView]',
+            float32Tag = '[object Float32Array]',
+            float64Tag = '[object Float64Array]',
+            int8Tag = '[object Int8Array]',
+            int16Tag = '[object Int16Array]',
+            int32Tag = '[object Int32Array]',
+            uint8Tag = '[object Uint8Array]',
+            uint8ClampedTag = '[object Uint8ClampedArray]',
+            uint16Tag = '[object Uint16Array]',
+            uint32Tag = '[object Uint32Array]';
+
+          /** Used to match empty string literals in compiled template source. */
+          var reEmptyStringLeading = /\b__p \+= '';/g,
+            reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
+            reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
+
+          /** Used to match HTML entities and HTML characters. */
+          var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g,
+            reUnescapedHtml = /[&<>"']/g,
+            reHasEscapedHtml = RegExp(reEscapedHtml.source),
+            reHasUnescapedHtml = RegExp(reUnescapedHtml.source);
+
+          /** Used to match template delimiters. */
+          var reEscape = /<%-([\s\S]+?)%>/g,
+            reEvaluate = /<%([\s\S]+?)%>/g,
+            reInterpolate = /<%=([\s\S]+?)%>/g;
+
+          /** Used to match property names within property paths. */
+          var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
+            reIsPlainProp = /^\w*$/,
+            rePropName =
+              /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
+
+          /**
+           * Used to match `RegExp`
+           * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
+           */
+          var reRegExpChar = /[\\^$.*+?()[\]{}|]/g,
+            reHasRegExpChar = RegExp(reRegExpChar.source);
+
+          /** Used to match leading and trailing whitespace. */
+          var reTrim = /^\s+|\s+$/g,
+            reTrimStart = /^\s+/,
+            reTrimEnd = /\s+$/;
+
+          /** Used to match wrap detail comments. */
+          var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,
+            reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/,
+            reSplitDetails = /,? & /;
+
+          /** Used to match words composed of alphanumeric characters. */
+          var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
+
+          /** Used to match backslashes in property paths. */
+          var reEscapeChar = /\\(\\)?/g;
+
+          /**
+           * Used to match
+           * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components).
+           */
+          var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
+
+          /** Used to match `RegExp` flags from their coerced string values. */
+          var reFlags = /\w*$/;
+
+          /** Used to detect bad signed hexadecimal string values. */
+          var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
+
+          /** Used to detect binary string values. */
+          var reIsBinary = /^0b[01]+$/i;
+
+          /** Used to detect host constructors (Safari). */
+          var reIsHostCtor = /^\[object .+?Constructor\]$/;
+
+          /** Used to detect octal string values. */
+          var reIsOctal = /^0o[0-7]+$/i;
+
+          /** Used to detect unsigned integer values. */
+          var reIsUint = /^(?:0|[1-9]\d*)$/;
+
+          /** Used to match Latin Unicode letters (excluding mathematical operators). */
+          var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;
+
+          /** Used to ensure capturing order of template delimiters. */
+          var reNoMatch = /($^)/;
+
+          /** Used to match unescaped characters in compiled string literals. */
+          var reUnescapedString = /['\n\r\u2028\u2029\\]/g;
+
+          /** Used to compose unicode character classes. */
+          var rsAstralRange = '\\ud800-\\udfff',
+            rsComboMarksRange = '\\u0300-\\u036f',
+            reComboHalfMarksRange = '\\ufe20-\\ufe2f',
+            rsComboSymbolsRange = '\\u20d0-\\u20ff',
+            rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,
+            rsDingbatRange = '\\u2700-\\u27bf',
+            rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff',
+            rsMathOpRange = '\\xac\\xb1\\xd7\\xf7',
+            rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf',
+            rsPunctuationRange = '\\u2000-\\u206f',
+            rsSpaceRange =
+              ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000',
+            rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde',
+            rsVarRange = '\\ufe0e\\ufe0f',
+            rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange;
+
+          /** Used to compose unicode capture groups. */
+          var rsApos = "['\u2019]",
+            rsAstral = '[' + rsAstralRange + ']',
+            rsBreak = '[' + rsBreakRange + ']',
+            rsCombo = '[' + rsComboRange + ']',
+            rsDigits = '\\d+',
+            rsDingbat = '[' + rsDingbatRange + ']',
+            rsLower = '[' + rsLowerRange + ']',
+            rsMisc =
+              '[^' +
+              rsAstralRange +
+              rsBreakRange +
+              rsDigits +
+              rsDingbatRange +
+              rsLowerRange +
+              rsUpperRange +
+              ']',
+            rsFitz = '\\ud83c[\\udffb-\\udfff]',
+            rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',
+            rsNonAstral = '[^' + rsAstralRange + ']',
+            rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}',
+            rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]',
+            rsUpper = '[' + rsUpperRange + ']',
+            rsZWJ = '\\u200d';
+
+          /** Used to compose unicode regexes. */
+          var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')',
+            rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')',
+            rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?',
+            rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?',
+            reOptMod = rsModifier + '?',
+            rsOptVar = '[' + rsVarRange + ']?',
+            rsOptJoin =
+              '(?:' +
+              rsZWJ +
+              '(?:' +
+              [rsNonAstral, rsRegional, rsSurrPair].join('|') +
+              ')' +
+              rsOptVar +
+              reOptMod +
+              ')*',
+            rsOrdLower = '\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])',
+            rsOrdUpper = '\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])',
+            rsSeq = rsOptVar + reOptMod + rsOptJoin,
+            rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq,
+            rsSymbol =
+              '(?:' +
+              [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') +
+              ')';
+
+          /** Used to match apostrophes. */
+          var reApos = RegExp(rsApos, 'g');
+
+          /**
+           * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
+           * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).
+           */
+          var reComboMark = RegExp(rsCombo, 'g');
+
+          /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */
+          var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');
+
+          /** Used to match complex or compound words. */
+          var reUnicodeWord = RegExp(
+            [
+              rsUpper +
+                '?' +
+                rsLower +
+                '+' +
+                rsOptContrLower +
+                '(?=' +
+                [rsBreak, rsUpper, '$'].join('|') +
+                ')',
+              rsMiscUpper +
+                '+' +
+                rsOptContrUpper +
+                '(?=' +
+                [rsBreak, rsUpper + rsMiscLower, '$'].join('|') +
+                ')',
+              rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower,
+              rsUpper + '+' + rsOptContrUpper,
+              rsOrdUpper,
+              rsOrdLower,
+              rsDigits,
+              rsEmoji,
+            ].join('|'),
+            'g'
+          );
+
+          /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */
+          var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');
+
+          /** Used to detect strings that need a more robust regexp to match words. */
+          var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;
+
+          /** Used to assign default `context` object properties. */
+          var contextProps = [
+            'Array',
+            'Buffer',
+            'DataView',
+            'Date',
+            'Error',
+            'Float32Array',
+            'Float64Array',
+            'Function',
+            'Int8Array',
+            'Int16Array',
+            'Int32Array',
+            'Map',
+            'Math',
+            'Object',
+            'Promise',
+            'RegExp',
+            'Set',
+            'String',
+            'Symbol',
+            'TypeError',
+            'Uint8Array',
+            'Uint8ClampedArray',
+            'Uint16Array',
+            'Uint32Array',
+            'WeakMap',
+            '_',
+            'clearTimeout',
+            'isFinite',
+            'parseInt',
+            'setTimeout',
+          ];
+
+          /** Used to make template sourceURLs easier to identify. */
+          var templateCounter = -1;
+
+          /** Used to identify `toStringTag` values of typed arrays. */
+          var typedArrayTags = {};
+          typedArrayTags[float32Tag] =
+            typedArrayTags[float64Tag] =
+            typedArrayTags[int8Tag] =
+            typedArrayTags[int16Tag] =
+            typedArrayTags[int32Tag] =
+            typedArrayTags[uint8Tag] =
+            typedArrayTags[uint8ClampedTag] =
+            typedArrayTags[uint16Tag] =
+            typedArrayTags[uint32Tag] =
+              true;
+          typedArrayTags[argsTag] =
+            typedArrayTags[arrayTag] =
+            typedArrayTags[arrayBufferTag] =
+            typedArrayTags[boolTag] =
+            typedArrayTags[dataViewTag] =
+            typedArrayTags[dateTag] =
+            typedArrayTags[errorTag] =
+            typedArrayTags[funcTag] =
+            typedArrayTags[mapTag] =
+            typedArrayTags[numberTag] =
+            typedArrayTags[objectTag] =
+            typedArrayTags[regexpTag] =
+            typedArrayTags[setTag] =
+            typedArrayTags[stringTag] =
+            typedArrayTags[weakMapTag] =
+              false;
+
+          /** Used to identify `toStringTag` values supported by `_.clone`. */
+          var cloneableTags = {};
+          cloneableTags[argsTag] =
+            cloneableTags[arrayTag] =
+            cloneableTags[arrayBufferTag] =
+            cloneableTags[dataViewTag] =
+            cloneableTags[boolTag] =
+            cloneableTags[dateTag] =
+            cloneableTags[float32Tag] =
+            cloneableTags[float64Tag] =
+            cloneableTags[int8Tag] =
+            cloneableTags[int16Tag] =
+            cloneableTags[int32Tag] =
+            cloneableTags[mapTag] =
+            cloneableTags[numberTag] =
+            cloneableTags[objectTag] =
+            cloneableTags[regexpTag] =
+            cloneableTags[setTag] =
+            cloneableTags[stringTag] =
+            cloneableTags[symbolTag] =
+            cloneableTags[uint8Tag] =
+            cloneableTags[uint8ClampedTag] =
+            cloneableTags[uint16Tag] =
+            cloneableTags[uint32Tag] =
+              true;
+          cloneableTags[errorTag] = cloneableTags[funcTag] = cloneableTags[weakMapTag] = false;
+
+          /** Used to map Latin Unicode letters to basic Latin letters. */
+          var deburredLetters = {
+            // Latin-1 Supplement block.
+            '\xc0': 'A',
+            '\xc1': 'A',
+            '\xc2': 'A',
+            '\xc3': 'A',
+            '\xc4': 'A',
+            '\xc5': 'A',
+            '\xe0': 'a',
+            '\xe1': 'a',
+            '\xe2': 'a',
+            '\xe3': 'a',
+            '\xe4': 'a',
+            '\xe5': 'a',
+            '\xc7': 'C',
+            '\xe7': 'c',
+            '\xd0': 'D',
+            '\xf0': 'd',
+            '\xc8': 'E',
+            '\xc9': 'E',
+            '\xca': 'E',
+            '\xcb': 'E',
+            '\xe8': 'e',
+            '\xe9': 'e',
+            '\xea': 'e',
+            '\xeb': 'e',
+            '\xcc': 'I',
+            '\xcd': 'I',
+            '\xce': 'I',
+            '\xcf': 'I',
+            '\xec': 'i',
+            '\xed': 'i',
+            '\xee': 'i',
+            '\xef': 'i',
+            '\xd1': 'N',
+            '\xf1': 'n',
+            '\xd2': 'O',
+            '\xd3': 'O',
+            '\xd4': 'O',
+            '\xd5': 'O',
+            '\xd6': 'O',
+            '\xd8': 'O',
+            '\xf2': 'o',
+            '\xf3': 'o',
+            '\xf4': 'o',
+            '\xf5': 'o',
+            '\xf6': 'o',
+            '\xf8': 'o',
+            '\xd9': 'U',
+            '\xda': 'U',
+            '\xdb': 'U',
+            '\xdc': 'U',
+            '\xf9': 'u',
+            '\xfa': 'u',
+            '\xfb': 'u',
+            '\xfc': 'u',
+            '\xdd': 'Y',
+            '\xfd': 'y',
+            '\xff': 'y',
+            '\xc6': 'Ae',
+            '\xe6': 'ae',
+            '\xde': 'Th',
+            '\xfe': 'th',
+            '\xdf': 'ss',
+            // Latin Extended-A block.
+            '\u0100': 'A',
+            '\u0102': 'A',
+            '\u0104': 'A',
+            '\u0101': 'a',
+            '\u0103': 'a',
+            '\u0105': 'a',
+            '\u0106': 'C',
+            '\u0108': 'C',
+            '\u010a': 'C',
+            '\u010c': 'C',
+            '\u0107': 'c',
+            '\u0109': 'c',
+            '\u010b': 'c',
+            '\u010d': 'c',
+            '\u010e': 'D',
+            '\u0110': 'D',
+            '\u010f': 'd',
+            '\u0111': 'd',
+            '\u0112': 'E',
+            '\u0114': 'E',
+            '\u0116': 'E',
+            '\u0118': 'E',
+            '\u011a': 'E',
+            '\u0113': 'e',
+            '\u0115': 'e',
+            '\u0117': 'e',
+            '\u0119': 'e',
+            '\u011b': 'e',
+            '\u011c': 'G',
+            '\u011e': 'G',
+            '\u0120': 'G',
+            '\u0122': 'G',
+            '\u011d': 'g',
+            '\u011f': 'g',
+            '\u0121': 'g',
+            '\u0123': 'g',
+            '\u0124': 'H',
+            '\u0126': 'H',
+            '\u0125': 'h',
+            '\u0127': 'h',
+            '\u0128': 'I',
+            '\u012a': 'I',
+            '\u012c': 'I',
+            '\u012e': 'I',
+            '\u0130': 'I',
+            '\u0129': 'i',
+            '\u012b': 'i',
+            '\u012d': 'i',
+            '\u012f': 'i',
+            '\u0131': 'i',
+            '\u0134': 'J',
+            '\u0135': 'j',
+            '\u0136': 'K',
+            '\u0137': 'k',
+            '\u0138': 'k',
+            '\u0139': 'L',
+            '\u013b': 'L',
+            '\u013d': 'L',
+            '\u013f': 'L',
+            '\u0141': 'L',
+            '\u013a': 'l',
+            '\u013c': 'l',
+            '\u013e': 'l',
+            '\u0140': 'l',
+            '\u0142': 'l',
+            '\u0143': 'N',
+            '\u0145': 'N',
+            '\u0147': 'N',
+            '\u014a': 'N',
+            '\u0144': 'n',
+            '\u0146': 'n',
+            '\u0148': 'n',
+            '\u014b': 'n',
+            '\u014c': 'O',
+            '\u014e': 'O',
+            '\u0150': 'O',
+            '\u014d': 'o',
+            '\u014f': 'o',
+            '\u0151': 'o',
+            '\u0154': 'R',
+            '\u0156': 'R',
+            '\u0158': 'R',
+            '\u0155': 'r',
+            '\u0157': 'r',
+            '\u0159': 'r',
+            '\u015a': 'S',
+            '\u015c': 'S',
+            '\u015e': 'S',
+            '\u0160': 'S',
+            '\u015b': 's',
+            '\u015d': 's',
+            '\u015f': 's',
+            '\u0161': 's',
+            '\u0162': 'T',
+            '\u0164': 'T',
+            '\u0166': 'T',
+            '\u0163': 't',
+            '\u0165': 't',
+            '\u0167': 't',
+            '\u0168': 'U',
+            '\u016a': 'U',
+            '\u016c': 'U',
+            '\u016e': 'U',
+            '\u0170': 'U',
+            '\u0172': 'U',
+            '\u0169': 'u',
+            '\u016b': 'u',
+            '\u016d': 'u',
+            '\u016f': 'u',
+            '\u0171': 'u',
+            '\u0173': 'u',
+            '\u0174': 'W',
+            '\u0175': 'w',
+            '\u0176': 'Y',
+            '\u0177': 'y',
+            '\u0178': 'Y',
+            '\u0179': 'Z',
+            '\u017b': 'Z',
+            '\u017d': 'Z',
+            '\u017a': 'z',
+            '\u017c': 'z',
+            '\u017e': 'z',
+            '\u0132': 'IJ',
+            '\u0133': 'ij',
+            '\u0152': 'Oe',
+            '\u0153': 'oe',
+            '\u0149': "'n",
+            '\u017f': 's',
+          };
+
+          /** Used to map characters to HTML entities. */
+          var htmlEscapes = {
+            '&': '&',
+            '<': '<',
+            '>': '>',
+            '"': '"',
+            "'": ''',
+          };
+
+          /** Used to map HTML entities to characters. */
+          var htmlUnescapes = {
+            '&': '&',
+            '<': '<',
+            '>': '>',
+            '"': '"',
+            ''': "'",
+          };
+
+          /** Used to escape characters for inclusion in compiled string literals. */
+          var stringEscapes = {
+            '\\': '\\',
+            "'": "'",
+            '\n': 'n',
+            '\r': 'r',
+            '\u2028': 'u2028',
+            '\u2029': 'u2029',
+          };
+
+          /** Built-in method references without a dependency on `root`. */
+          var freeParseFloat = parseFloat,
+            freeParseInt = parseInt;
+
+          /** Detect free variable `global` from Node.js. */
+          var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
+
+          /** Detect free variable `self`. */
+          var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
+
+          /** Used as a reference to the global object. */
+          var root = freeGlobal || freeSelf || Function('return this')();
+
+          /** Detect free variable `exports`. */
+          var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;
+
+          /** Detect free variable `module`. */
+          var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;
+
+          /** Detect the popular CommonJS extension `module.exports`. */
+          var moduleExports = freeModule && freeModule.exports === freeExports;
+
+          /** Detect free variable `process` from Node.js. */
+          var freeProcess = moduleExports && freeGlobal.process;
+
+          /** Used to access faster Node.js helpers. */
+          var nodeUtil = (function () {
+            try {
+              // Use `util.types` for Node.js 10+.
+              var types = freeModule && freeModule.require && freeModule.require('util').types;
+
+              if (types) {
+                return types;
+              }
+
+              // Legacy `process.binding('util')` for Node.js < 10.
+              return freeProcess && freeProcess.binding && freeProcess.binding('util');
+            } catch (e) {}
+          })();
+
+          /* Node.js helper references. */
+          var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer,
+            nodeIsDate = nodeUtil && nodeUtil.isDate,
+            nodeIsMap = nodeUtil && nodeUtil.isMap,
+            nodeIsRegExp = nodeUtil && nodeUtil.isRegExp,
+            nodeIsSet = nodeUtil && nodeUtil.isSet,
+            nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;
+
+          /*--------------------------------------------------------------------------*/
+
+          /**
+           * A faster alternative to `Function#apply`, this function invokes `func`
+           * with the `this` binding of `thisArg` and the arguments of `args`.
+           *
+           * @private
+           * @param {Function} func The function to invoke.
+           * @param {*} thisArg The `this` binding of `func`.
+           * @param {Array} args The arguments to invoke `func` with.
+           * @returns {*} Returns the result of `func`.
+           */
+          function apply(func, thisArg, args) {
+            switch (args.length) {
+              case 0:
+                return func.call(thisArg);
+              case 1:
+                return func.call(thisArg, args[0]);
+              case 2:
+                return func.call(thisArg, args[0], args[1]);
+              case 3:
+                return func.call(thisArg, args[0], args[1], args[2]);
+            }
+            return func.apply(thisArg, args);
+          }
+
+          /**
+           * A specialized version of `baseAggregator` for arrays.
+           *
+           * @private
+           * @param {Array} [array] The array to iterate over.
+           * @param {Function} setter The function to set `accumulator` values.
+           * @param {Function} iteratee The iteratee to transform keys.
+           * @param {Object} accumulator The initial aggregated object.
+           * @returns {Function} Returns `accumulator`.
+           */
+          function arrayAggregator(array, setter, iteratee, accumulator) {
+            var index = -1,
+              length = array == null ? 0 : array.length;
+
+            while (++index < length) {
+              var value = array[index];
+              setter(accumulator, value, iteratee(value), array);
+            }
+            return accumulator;
+          }
+
+          /**
+           * A specialized version of `_.forEach` for arrays without support for
+           * iteratee shorthands.
+           *
+           * @private
+           * @param {Array} [array] The array to iterate over.
+           * @param {Function} iteratee The function invoked per iteration.
+           * @returns {Array} Returns `array`.
+           */
+          function arrayEach(array, iteratee) {
+            var index = -1,
+              length = array == null ? 0 : array.length;
+
+            while (++index < length) {
+              if (iteratee(array[index], index, array) === false) {
+                break;
+              }
+            }
+            return array;
+          }
+
+          /**
+           * A specialized version of `_.forEachRight` for arrays without support for
+           * iteratee shorthands.
+           *
+           * @private
+           * @param {Array} [array] The array to iterate over.
+           * @param {Function} iteratee The function invoked per iteration.
+           * @returns {Array} Returns `array`.
+           */
+          function arrayEachRight(array, iteratee) {
+            var length = array == null ? 0 : array.length;
+
+            while (length--) {
+              if (iteratee(array[length], length, array) === false) {
+                break;
+              }
+            }
+            return array;
+          }
+
+          /**
+           * A specialized version of `_.every` for arrays without support for
+           * iteratee shorthands.
+           *
+           * @private
+           * @param {Array} [array] The array to iterate over.
+           * @param {Function} predicate The function invoked per iteration.
+           * @returns {boolean} Returns `true` if all elements pass the predicate check,
+           *  else `false`.
+           */
+          function arrayEvery(array, predicate) {
+            var index = -1,
+              length = array == null ? 0 : array.length;
+
+            while (++index < length) {
+              if (!predicate(array[index], index, array)) {
+                return false;
+              }
+            }
+            return true;
+          }
+
+          /**
+           * A specialized version of `_.filter` for arrays without support for
+           * iteratee shorthands.
+           *
+           * @private
+           * @param {Array} [array] The array to iterate over.
+           * @param {Function} predicate The function invoked per iteration.
+           * @returns {Array} Returns the new filtered array.
+           */
+          function arrayFilter(array, predicate) {
+            var index = -1,
+              length = array == null ? 0 : array.length,
+              resIndex = 0,
+              result = [];
+
+            while (++index < length) {
+              var value = array[index];
+              if (predicate(value, index, array)) {
+                result[resIndex++] = value;
+              }
+            }
+            return result;
+          }
+
+          /**
+           * A specialized version of `_.includes` for arrays without support for
+           * specifying an index to search from.
+           *
+           * @private
+           * @param {Array} [array] The array to inspect.
+           * @param {*} target The value to search for.
+           * @returns {boolean} Returns `true` if `target` is found, else `false`.
+           */
+          function arrayIncludes(array, value) {
+            var length = array == null ? 0 : array.length;
+            return !!length && baseIndexOf(array, value, 0) > -1;
+          }
+
+          /**
+           * This function is like `arrayIncludes` except that it accepts a comparator.
+           *
+           * @private
+           * @param {Array} [array] The array to inspect.
+           * @param {*} target The value to search for.
+           * @param {Function} comparator The comparator invoked per element.
+           * @returns {boolean} Returns `true` if `target` is found, else `false`.
+           */
+          function arrayIncludesWith(array, value, comparator) {
+            var index = -1,
+              length = array == null ? 0 : array.length;
+
+            while (++index < length) {
+              if (comparator(value, array[index])) {
+                return true;
+              }
+            }
+            return false;
+          }
+
+          /**
+           * A specialized version of `_.map` for arrays without support for iteratee
+           * shorthands.
+           *
+           * @private
+           * @param {Array} [array] The array to iterate over.
+           * @param {Function} iteratee The function invoked per iteration.
+           * @returns {Array} Returns the new mapped array.
+           */
+          function arrayMap(array, iteratee) {
+            var index = -1,
+              length = array == null ? 0 : array.length,
+              result = Array(length);
+
+            while (++index < length) {
+              result[index] = iteratee(array[index], index, array);
+            }
+            return result;
+          }
+
+          /**
+           * Appends the elements of `values` to `array`.
+           *
+           * @private
+           * @param {Array} array The array to modify.
+           * @param {Array} values The values to append.
+           * @returns {Array} Returns `array`.
+           */
+          function arrayPush(array, values) {
+            var index = -1,
+              length = values.length,
+              offset = array.length;
+
+            while (++index < length) {
+              array[offset + index] = values[index];
+            }
+            return array;
+          }
+
+          /**
+           * A specialized version of `_.reduce` for arrays without support for
+           * iteratee shorthands.
+           *
+           * @private
+           * @param {Array} [array] The array to iterate over.
+           * @param {Function} iteratee The function invoked per iteration.
+           * @param {*} [accumulator] The initial value.
+           * @param {boolean} [initAccum] Specify using the first element of `array` as
+           *  the initial value.
+           * @returns {*} Returns the accumulated value.
+           */
+          function arrayReduce(array, iteratee, accumulator, initAccum) {
+            var index = -1,
+              length = array == null ? 0 : array.length;
+
+            if (initAccum && length) {
+              accumulator = array[++index];
+            }
+            while (++index < length) {
+              accumulator = iteratee(accumulator, array[index], index, array);
+            }
+            return accumulator;
+          }
+
+          /**
+           * A specialized version of `_.reduceRight` for arrays without support for
+           * iteratee shorthands.
+           *
+           * @private
+           * @param {Array} [array] The array to iterate over.
+           * @param {Function} iteratee The function invoked per iteration.
+           * @param {*} [accumulator] The initial value.
+           * @param {boolean} [initAccum] Specify using the last element of `array` as
+           *  the initial value.
+           * @returns {*} Returns the accumulated value.
+           */
+          function arrayReduceRight(array, iteratee, accumulator, initAccum) {
+            var length = array == null ? 0 : array.length;
+            if (initAccum && length) {
+              accumulator = array[--length];
+            }
+            while (length--) {
+              accumulator = iteratee(accumulator, array[length], length, array);
+            }
+            return accumulator;
+          }
+
+          /**
+           * A specialized version of `_.some` for arrays without support for iteratee
+           * shorthands.
+           *
+           * @private
+           * @param {Array} [array] The array to iterate over.
+           * @param {Function} predicate The function invoked per iteration.
+           * @returns {boolean} Returns `true` if any element passes the predicate check,
+           *  else `false`.
+           */
+          function arraySome(array, predicate) {
+            var index = -1,
+              length = array == null ? 0 : array.length;
+
+            while (++index < length) {
+              if (predicate(array[index], index, array)) {
+                return true;
+              }
+            }
+            return false;
+          }
+
+          /**
+           * Gets the size of an ASCII `string`.
+           *
+           * @private
+           * @param {string} string The string inspect.
+           * @returns {number} Returns the string size.
+           */
+          var asciiSize = baseProperty('length');
+
+          /**
+           * Converts an ASCII `string` to an array.
+           *
+           * @private
+           * @param {string} string The string to convert.
+           * @returns {Array} Returns the converted array.
+           */
+          function asciiToArray(string) {
+            return string.split('');
+          }
+
+          /**
+           * Splits an ASCII `string` into an array of its words.
+           *
+           * @private
+           * @param {string} The string to inspect.
+           * @returns {Array} Returns the words of `string`.
+           */
+          function asciiWords(string) {
+            return string.match(reAsciiWord) || [];
+          }
+
+          /**
+           * The base implementation of methods like `_.findKey` and `_.findLastKey`,
+           * without support for iteratee shorthands, which iterates over `collection`
+           * using `eachFunc`.
+           *
+           * @private
+           * @param {Array|Object} collection The collection to inspect.
+           * @param {Function} predicate The function invoked per iteration.
+           * @param {Function} eachFunc The function to iterate over `collection`.
+           * @returns {*} Returns the found element or its key, else `undefined`.
+           */
+          function baseFindKey(collection, predicate, eachFunc) {
+            var result;
+            eachFunc(collection, function (value, key, collection) {
+              if (predicate(value, key, collection)) {
+                result = key;
+                return false;
+              }
+            });
+            return result;
+          }
+
+          /**
+           * The base implementation of `_.findIndex` and `_.findLastIndex` without
+           * support for iteratee shorthands.
+           *
+           * @private
+           * @param {Array} array The array to inspect.
+           * @param {Function} predicate The function invoked per iteration.
+           * @param {number} fromIndex The index to search from.
+           * @param {boolean} [fromRight] Specify iterating from right to left.
+           * @returns {number} Returns the index of the matched value, else `-1`.
+           */
+          function baseFindIndex(array, predicate, fromIndex, fromRight) {
+            var length = array.length,
+              index = fromIndex + (fromRight ? 1 : -1);
+
+            while (fromRight ? index-- : ++index < length) {
+              if (predicate(array[index], index, array)) {
+                return index;
+              }
+            }
+            return -1;
+          }
+
+          /**
+           * The base implementation of `_.indexOf` without `fromIndex` bounds checks.
+           *
+           * @private
+           * @param {Array} array The array to inspect.
+           * @param {*} value The value to search for.
+           * @param {number} fromIndex The index to search from.
+           * @returns {number} Returns the index of the matched value, else `-1`.
+           */
+          function baseIndexOf(array, value, fromIndex) {
+            return value === value
+              ? strictIndexOf(array, value, fromIndex)
+              : baseFindIndex(array, baseIsNaN, fromIndex);
+          }
+
+          /**
+           * This function is like `baseIndexOf` except that it accepts a comparator.
+           *
+           * @private
+           * @param {Array} array The array to inspect.
+           * @param {*} value The value to search for.
+           * @param {number} fromIndex The index to search from.
+           * @param {Function} comparator The comparator invoked per element.
+           * @returns {number} Returns the index of the matched value, else `-1`.
+           */
+          function baseIndexOfWith(array, value, fromIndex, comparator) {
+            var index = fromIndex - 1,
+              length = array.length;
+
+            while (++index < length) {
+              if (comparator(array[index], value)) {
+                return index;
+              }
+            }
+            return -1;
+          }
+
+          /**
+           * The base implementation of `_.isNaN` without support for number objects.
+           *
+           * @private
+           * @param {*} value The value to check.
+           * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
+           */
+          function baseIsNaN(value) {
+            return value !== value;
+          }
+
+          /**
+           * The base implementation of `_.mean` and `_.meanBy` without support for
+           * iteratee shorthands.
+           *
+           * @private
+           * @param {Array} array The array to iterate over.
+           * @param {Function} iteratee The function invoked per iteration.
+           * @returns {number} Returns the mean.
+           */
+          function baseMean(array, iteratee) {
+            var length = array == null ? 0 : array.length;
+            return length ? baseSum(array, iteratee) / length : NAN;
+          }
+
+          /**
+           * The base implementation of `_.property` without support for deep paths.
+           *
+           * @private
+           * @param {string} key The key of the property to get.
+           * @returns {Function} Returns the new accessor function.
+           */
+          function baseProperty(key) {
+            return function (object) {
+              return object == null ? undefined : object[key];
+            };
+          }
+
+          /**
+           * The base implementation of `_.propertyOf` without support for deep paths.
+           *
+           * @private
+           * @param {Object} object The object to query.
+           * @returns {Function} Returns the new accessor function.
+           */
+          function basePropertyOf(object) {
+            return function (key) {
+              return object == null ? undefined : object[key];
+            };
+          }
+
+          /**
+           * The base implementation of `_.reduce` and `_.reduceRight`, without support
+           * for iteratee shorthands, which iterates over `collection` using `eachFunc`.
+           *
+           * @private
+           * @param {Array|Object} collection The collection to iterate over.
+           * @param {Function} iteratee The function invoked per iteration.
+           * @param {*} accumulator The initial value.
+           * @param {boolean} initAccum Specify using the first or last element of
+           *  `collection` as the initial value.
+           * @param {Function} eachFunc The function to iterate over `collection`.
+           * @returns {*} Returns the accumulated value.
+           */
+          function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) {
+            eachFunc(collection, function (value, index, collection) {
+              accumulator = initAccum
+                ? ((initAccum = false), value)
+                : iteratee(accumulator, value, index, collection);
+            });
+            return accumulator;
+          }
+
+          /**
+           * The base implementation of `_.sortBy` which uses `comparer` to define the
+           * sort order of `array` and replaces criteria objects with their corresponding
+           * values.
+           *
+           * @private
+           * @param {Array} array The array to sort.
+           * @param {Function} comparer The function to define sort order.
+           * @returns {Array} Returns `array`.
+           */
+          function baseSortBy(array, comparer) {
+            var length = array.length;
+
+            array.sort(comparer);
+            while (length--) {
+              array[length] = array[length].value;
+            }
+            return array;
+          }
+
+          /**
+           * The base implementation of `_.sum` and `_.sumBy` without support for
+           * iteratee shorthands.
+           *
+           * @private
+           * @param {Array} array The array to iterate over.
+           * @param {Function} iteratee The function invoked per iteration.
+           * @returns {number} Returns the sum.
+           */
+          function baseSum(array, iteratee) {
+            var result,
+              index = -1,
+              length = array.length;
+
+            while (++index < length) {
+              var current = iteratee(array[index]);
+              if (current !== undefined) {
+                result = result === undefined ? current : result + current;
+              }
+            }
+            return result;
+          }
+
+          /**
+           * The base implementation of `_.times` without support for iteratee shorthands
+           * or max array length checks.
+           *
+           * @private
+           * @param {number} n The number of times to invoke `iteratee`.
+           * @param {Function} iteratee The function invoked per iteration.
+           * @returns {Array} Returns the array of results.
+           */
+          function baseTimes(n, iteratee) {
+            var index = -1,
+              result = Array(n);
+
+            while (++index < n) {
+              result[index] = iteratee(index);
+            }
+            return result;
+          }
+
+          /**
+           * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array
+           * of key-value pairs for `object` corresponding to the property names of `props`.
+           *
+           * @private
+           * @param {Object} object The object to query.
+           * @param {Array} props The property names to get values for.
+           * @returns {Object} Returns the key-value pairs.
+           */
+          function baseToPairs(object, props) {
+            return arrayMap(props, function (key) {
+              return [key, object[key]];
+            });
+          }
+
+          /**
+           * The base implementation of `_.unary` without support for storing metadata.
+           *
+           * @private
+           * @param {Function} func The function to cap arguments for.
+           * @returns {Function} Returns the new capped function.
+           */
+          function baseUnary(func) {
+            return function (value) {
+              return func(value);
+            };
+          }
+
+          /**
+           * The base implementation of `_.values` and `_.valuesIn` which creates an
+           * array of `object` property values corresponding to the property names
+           * of `props`.
+           *
+           * @private
+           * @param {Object} object The object to query.
+           * @param {Array} props The property names to get values for.
+           * @returns {Object} Returns the array of property values.
+           */
+          function baseValues(object, props) {
+            return arrayMap(props, function (key) {
+              return object[key];
+            });
+          }
+
+          /**
+           * Checks if a `cache` value for `key` exists.
+           *
+           * @private
+           * @param {Object} cache The cache to query.
+           * @param {string} key The key of the entry to check.
+           * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+           */
+          function cacheHas(cache, key) {
+            return cache.has(key);
+          }
+
+          /**
+           * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol
+           * that is not found in the character symbols.
+           *
+           * @private
+           * @param {Array} strSymbols The string symbols to inspect.
+           * @param {Array} chrSymbols The character symbols to find.
+           * @returns {number} Returns the index of the first unmatched string symbol.
+           */
+          function charsStartIndex(strSymbols, chrSymbols) {
+            var index = -1,
+              length = strSymbols.length;
+
+            while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
+            return index;
+          }
+
+          /**
+           * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol
+           * that is not found in the character symbols.
+           *
+           * @private
+           * @param {Array} strSymbols The string symbols to inspect.
+           * @param {Array} chrSymbols The character symbols to find.
+           * @returns {number} Returns the index of the last unmatched string symbol.
+           */
+          function charsEndIndex(strSymbols, chrSymbols) {
+            var index = strSymbols.length;
+
+            while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
+            return index;
+          }
+
+          /**
+           * Gets the number of `placeholder` occurrences in `array`.
+           *
+           * @private
+           * @param {Array} array The array to inspect.
+           * @param {*} placeholder The placeholder to search for.
+           * @returns {number} Returns the placeholder count.
+           */
+          function countHolders(array, placeholder) {
+            var length = array.length,
+              result = 0;
+
+            while (length--) {
+              if (array[length] === placeholder) {
+                ++result;
+              }
+            }
+            return result;
+          }
+
+          /**
+           * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A
+           * letters to basic Latin letters.
+           *
+           * @private
+           * @param {string} letter The matched letter to deburr.
+           * @returns {string} Returns the deburred letter.
+           */
+          var deburrLetter = basePropertyOf(deburredLetters);
+
+          /**
+           * Used by `_.escape` to convert characters to HTML entities.
+           *
+           * @private
+           * @param {string} chr The matched character to escape.
+           * @returns {string} Returns the escaped character.
+           */
+          var escapeHtmlChar = basePropertyOf(htmlEscapes);
+
+          /**
+           * Used by `_.template` to escape characters for inclusion in compiled string literals.
+           *
+           * @private
+           * @param {string} chr The matched character to escape.
+           * @returns {string} Returns the escaped character.
+           */
+          function escapeStringChar(chr) {
+            return '\\' + stringEscapes[chr];
+          }
+
+          /**
+           * Gets the value at `key` of `object`.
+           *
+           * @private
+           * @param {Object} [object] The object to query.
+           * @param {string} key The key of the property to get.
+           * @returns {*} Returns the property value.
+           */
+          function getValue(object, key) {
+            return object == null ? undefined : object[key];
+          }
+
+          /**
+           * Checks if `string` contains Unicode symbols.
+           *
+           * @private
+           * @param {string} string The string to inspect.
+           * @returns {boolean} Returns `true` if a symbol is found, else `false`.
+           */
+          function hasUnicode(string) {
+            return reHasUnicode.test(string);
+          }
+
+          /**
+           * Checks if `string` contains a word composed of Unicode symbols.
+           *
+           * @private
+           * @param {string} string The string to inspect.
+           * @returns {boolean} Returns `true` if a word is found, else `false`.
+           */
+          function hasUnicodeWord(string) {
+            return reHasUnicodeWord.test(string);
+          }
+
+          /**
+           * Converts `iterator` to an array.
+           *
+           * @private
+           * @param {Object} iterator The iterator to convert.
+           * @returns {Array} Returns the converted array.
+           */
+          function iteratorToArray(iterator) {
+            var data,
+              result = [];
+
+            while (!(data = iterator.next()).done) {
+              result.push(data.value);
+            }
+            return result;
+          }
+
+          /**
+           * Converts `map` to its key-value pairs.
+           *
+           * @private
+           * @param {Object} map The map to convert.
+           * @returns {Array} Returns the key-value pairs.
+           */
+          function mapToArray(map) {
+            var index = -1,
+              result = Array(map.size);
+
+            map.forEach(function (value, key) {
+              result[++index] = [key, value];
+            });
+            return result;
+          }
+
+          /**
+           * Creates a unary function that invokes `func` with its argument transformed.
+           *
+           * @private
+           * @param {Function} func The function to wrap.
+           * @param {Function} transform The argument transform.
+           * @returns {Function} Returns the new function.
+           */
+          function overArg(func, transform) {
+            return function (arg) {
+              return func(transform(arg));
+            };
+          }
+
+          /**
+           * Replaces all `placeholder` elements in `array` with an internal placeholder
+           * and returns an array of their indexes.
+           *
+           * @private
+           * @param {Array} array The array to modify.
+           * @param {*} placeholder The placeholder to replace.
+           * @returns {Array} Returns the new array of placeholder indexes.
+           */
+          function replaceHolders(array, placeholder) {
+            var index = -1,
+              length = array.length,
+              resIndex = 0,
+              result = [];
+
+            while (++index < length) {
+              var value = array[index];
+              if (value === placeholder || value === PLACEHOLDER) {
+                array[index] = PLACEHOLDER;
+                result[resIndex++] = index;
+              }
+            }
+            return result;
+          }
+
+          /**
+           * Gets the value at `key`, unless `key` is "__proto__".
+           *
+           * @private
+           * @param {Object} object The object to query.
+           * @param {string} key The key of the property to get.
+           * @returns {*} Returns the property value.
+           */
+          function safeGet(object, key) {
+            return key == '__proto__' ? undefined : object[key];
+          }
+
+          /**
+           * Converts `set` to an array of its values.
+           *
+           * @private
+           * @param {Object} set The set to convert.
+           * @returns {Array} Returns the values.
+           */
+          function setToArray(set) {
+            var index = -1,
+              result = Array(set.size);
+
+            set.forEach(function (value) {
+              result[++index] = value;
+            });
+            return result;
+          }
+
+          /**
+           * Converts `set` to its value-value pairs.
+           *
+           * @private
+           * @param {Object} set The set to convert.
+           * @returns {Array} Returns the value-value pairs.
+           */
+          function setToPairs(set) {
+            var index = -1,
+              result = Array(set.size);
+
+            set.forEach(function (value) {
+              result[++index] = [value, value];
+            });
+            return result;
+          }
+
+          /**
+           * A specialized version of `_.indexOf` which performs strict equality
+           * comparisons of values, i.e. `===`.
+           *
+           * @private
+           * @param {Array} array The array to inspect.
+           * @param {*} value The value to search for.
+           * @param {number} fromIndex The index to search from.
+           * @returns {number} Returns the index of the matched value, else `-1`.
+           */
+          function strictIndexOf(array, value, fromIndex) {
+            var index = fromIndex - 1,
+              length = array.length;
+
+            while (++index < length) {
+              if (array[index] === value) {
+                return index;
+              }
+            }
+            return -1;
+          }
+
+          /**
+           * A specialized version of `_.lastIndexOf` which performs strict equality
+           * comparisons of values, i.e. `===`.
+           *
+           * @private
+           * @param {Array} array The array to inspect.
+           * @param {*} value The value to search for.
+           * @param {number} fromIndex The index to search from.
+           * @returns {number} Returns the index of the matched value, else `-1`.
+           */
+          function strictLastIndexOf(array, value, fromIndex) {
+            var index = fromIndex + 1;
+            while (index--) {
+              if (array[index] === value) {
+                return index;
+              }
+            }
+            return index;
+          }
+
+          /**
+           * Gets the number of symbols in `string`.
+           *
+           * @private
+           * @param {string} string The string to inspect.
+           * @returns {number} Returns the string size.
+           */
+          function stringSize(string) {
+            return hasUnicode(string) ? unicodeSize(string) : asciiSize(string);
+          }
+
+          /**
+           * Converts `string` to an array.
+           *
+           * @private
+           * @param {string} string The string to convert.
+           * @returns {Array} Returns the converted array.
+           */
+          function stringToArray(string) {
+            return hasUnicode(string) ? unicodeToArray(string) : asciiToArray(string);
+          }
+
+          /**
+           * Used by `_.unescape` to convert HTML entities to characters.
+           *
+           * @private
+           * @param {string} chr The matched character to unescape.
+           * @returns {string} Returns the unescaped character.
+           */
+          var unescapeHtmlChar = basePropertyOf(htmlUnescapes);
+
+          /**
+           * Gets the size of a Unicode `string`.
+           *
+           * @private
+           * @param {string} string The string inspect.
+           * @returns {number} Returns the string size.
+           */
+          function unicodeSize(string) {
+            var result = (reUnicode.lastIndex = 0);
+            while (reUnicode.test(string)) {
+              ++result;
+            }
+            return result;
+          }
+
+          /**
+           * Converts a Unicode `string` to an array.
+           *
+           * @private
+           * @param {string} string The string to convert.
+           * @returns {Array} Returns the converted array.
+           */
+          function unicodeToArray(string) {
+            return string.match(reUnicode) || [];
+          }
+
+          /**
+           * Splits a Unicode `string` into an array of its words.
+           *
+           * @private
+           * @param {string} The string to inspect.
+           * @returns {Array} Returns the words of `string`.
+           */
+          function unicodeWords(string) {
+            return string.match(reUnicodeWord) || [];
+          }
+
+          /*--------------------------------------------------------------------------*/
+
+          /**
+           * Create a new pristine `lodash` function using the `context` object.
+           *
+           * @static
+           * @memberOf _
+           * @since 1.1.0
+           * @category Util
+           * @param {Object} [context=root] The context object.
+           * @returns {Function} Returns a new `lodash` function.
+           * @example
+           *
+           * _.mixin({ 'foo': _.constant('foo') });
+           *
+           * var lodash = _.runInContext();
+           * lodash.mixin({ 'bar': lodash.constant('bar') });
+           *
+           * _.isFunction(_.foo);
+           * // => true
+           * _.isFunction(_.bar);
+           * // => false
+           *
+           * lodash.isFunction(lodash.foo);
+           * // => false
+           * lodash.isFunction(lodash.bar);
+           * // => true
+           *
+           * // Create a suped-up `defer` in Node.js.
+           * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer;
+           */
+          var runInContext = function runInContext(context) {
+            context = context == null ? root : _.defaults(root.Object(), context, _.pick(root, contextProps));
+
+            /** Built-in constructor references. */
+            var Array = context.Array,
+              Date = context.Date,
+              Error = context.Error,
+              Function = context.Function,
+              Math = context.Math,
+              Object = context.Object,
+              RegExp = context.RegExp,
+              String = context.String,
+              TypeError = context.TypeError;
+
+            /** Used for built-in method references. */
+            var arrayProto = Array.prototype,
+              funcProto = Function.prototype,
+              objectProto = Object.prototype;
+
+            /** Used to detect overreaching core-js shims. */
+            var coreJsData = context['__core-js_shared__'];
+
+            /** Used to resolve the decompiled source of functions. */
+            var funcToString = funcProto.toString;
+
+            /** Used to check objects for own properties. */
+            var hasOwnProperty = objectProto.hasOwnProperty;
+
+            /** Used to generate unique IDs. */
+            var idCounter = 0;
+
+            /** Used to detect methods masquerading as native. */
+            var maskSrcKey = (function () {
+              var uid = /[^.]+$/.exec((coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO) || '');
+              return uid ? 'Symbol(src)_1.' + uid : '';
+            })();
+
+            /**
+             * Used to resolve the
+             * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+             * of values.
+             */
+            var nativeObjectToString = objectProto.toString;
+
+            /** Used to infer the `Object` constructor. */
+            var objectCtorString = funcToString.call(Object);
+
+            /** Used to restore the original `_` reference in `_.noConflict`. */
+            var oldDash = root._;
+
+            /** Used to detect if a method is native. */
+            var reIsNative = RegExp(
+              '^' +
+                funcToString
+                  .call(hasOwnProperty)
+                  .replace(reRegExpChar, '\\$&')
+                  .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') +
+                '$'
+            );
+
+            /** Built-in value references. */
+            var Buffer = moduleExports ? context.Buffer : undefined,
+              Symbol = context.Symbol,
+              Uint8Array = context.Uint8Array,
+              allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined,
+              getPrototype = overArg(Object.getPrototypeOf, Object),
+              objectCreate = Object.create,
+              propertyIsEnumerable = objectProto.propertyIsEnumerable,
+              splice = arrayProto.splice,
+              spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined,
+              symIterator = Symbol ? Symbol.iterator : undefined,
+              symToStringTag = Symbol ? Symbol.toStringTag : undefined;
+
+            var defineProperty = (function () {
+              try {
+                var func = getNative(Object, 'defineProperty');
+                func({}, '', {});
+                return func;
+              } catch (e) {}
+            })();
+
+            /** Mocked built-ins. */
+            var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout,
+              ctxNow = Date && Date.now !== root.Date.now && Date.now,
+              ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout;
+
+            /* Built-in method references for those with the same name as other `lodash` methods. */
+            var nativeCeil = Math.ceil,
+              nativeFloor = Math.floor,
+              nativeGetSymbols = Object.getOwnPropertySymbols,
+              nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined,
+              nativeIsFinite = context.isFinite,
+              nativeJoin = arrayProto.join,
+              nativeKeys = overArg(Object.keys, Object),
+              nativeMax = Math.max,
+              nativeMin = Math.min,
+              nativeNow = Date.now,
+              nativeParseInt = context.parseInt,
+              nativeRandom = Math.random,
+              nativeReverse = arrayProto.reverse;
+
+            /* Built-in method references that are verified to be native. */
+            var DataView = getNative(context, 'DataView'),
+              Map = getNative(context, 'Map'),
+              Promise = getNative(context, 'Promise'),
+              Set = getNative(context, 'Set'),
+              WeakMap = getNative(context, 'WeakMap'),
+              nativeCreate = getNative(Object, 'create');
+
+            /** Used to store function metadata. */
+            var metaMap = WeakMap && new WeakMap();
+
+            /** Used to lookup unminified function names. */
+            var realNames = {};
+
+            /** Used to detect maps, sets, and weakmaps. */
+            var dataViewCtorString = toSource(DataView),
+              mapCtorString = toSource(Map),
+              promiseCtorString = toSource(Promise),
+              setCtorString = toSource(Set),
+              weakMapCtorString = toSource(WeakMap);
+
+            /** Used to convert symbols to primitives and strings. */
+            var symbolProto = Symbol ? Symbol.prototype : undefined,
+              symbolValueOf = symbolProto ? symbolProto.valueOf : undefined,
+              symbolToString = symbolProto ? symbolProto.toString : undefined;
+
+            /*------------------------------------------------------------------------*/
+
+            /**
+             * Creates a `lodash` object which wraps `value` to enable implicit method
+             * chain sequences. Methods that operate on and return arrays, collections,
+             * and functions can be chained together. Methods that retrieve a single value
+             * or may return a primitive value will automatically end the chain sequence
+             * and return the unwrapped value. Otherwise, the value must be unwrapped
+             * with `_#value`.
+             *
+             * Explicit chain sequences, which must be unwrapped with `_#value`, may be
+             * enabled using `_.chain`.
+             *
+             * The execution of chained methods is lazy, that is, it's deferred until
+             * `_#value` is implicitly or explicitly called.
+             *
+             * Lazy evaluation allows several methods to support shortcut fusion.
+             * Shortcut fusion is an optimization to merge iteratee calls; this avoids
+             * the creation of intermediate arrays and can greatly reduce the number of
+             * iteratee executions. Sections of a chain sequence qualify for shortcut
+             * fusion if the section is applied to an array and iteratees accept only
+             * one argument. The heuristic for whether a section qualifies for shortcut
+             * fusion is subject to change.
+             *
+             * Chaining is supported in custom builds as long as the `_#value` method is
+             * directly or indirectly included in the build.
+             *
+             * In addition to lodash methods, wrappers have `Array` and `String` methods.
+             *
+             * The wrapper `Array` methods are:
+             * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift`
+             *
+             * The wrapper `String` methods are:
+             * `replace` and `split`
+             *
+             * The wrapper methods that support shortcut fusion are:
+             * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`,
+             * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`,
+             * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray`
+             *
+             * The chainable wrapper methods are:
+             * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`,
+             * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`,
+             * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`,
+             * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`,
+             * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`,
+             * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`,
+             * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`,
+             * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`,
+             * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`,
+             * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`,
+             * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`,
+             * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`,
+             * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`,
+             * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`,
+             * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`,
+             * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`,
+             * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`,
+             * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`,
+             * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`,
+             * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`,
+             * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`,
+             * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`,
+             * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`,
+             * `zipObject`, `zipObjectDeep`, and `zipWith`
+             *
+             * The wrapper methods that are **not** chainable by default are:
+             * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`,
+             * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`,
+             * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`,
+             * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`,
+             * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`,
+             * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`,
+             * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`,
+             * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`,
+             * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`,
+             * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`,
+             * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`,
+             * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`,
+             * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`,
+             * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`,
+             * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`,
+             * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`,
+             * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`,
+             * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`,
+             * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`,
+             * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`,
+             * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`,
+             * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`,
+             * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`,
+             * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`,
+             * `upperFirst`, `value`, and `words`
+             *
+             * @name _
+             * @constructor
+             * @category Seq
+             * @param {*} value The value to wrap in a `lodash` instance.
+             * @returns {Object} Returns the new `lodash` wrapper instance.
+             * @example
+             *
+             * function square(n) {
+             *   return n * n;
+             * }
+             *
+             * var wrapped = _([1, 2, 3]);
+             *
+             * // Returns an unwrapped value.
+             * wrapped.reduce(_.add);
+             * // => 6
+             *
+             * // Returns a wrapped value.
+             * var squares = wrapped.map(square);
+             *
+             * _.isArray(squares);
+             * // => false
+             *
+             * _.isArray(squares.value());
+             * // => true
+             */
+            function lodash(value) {
+              if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) {
+                if (value instanceof LodashWrapper) {
+                  return value;
+                }
+                if (hasOwnProperty.call(value, '__wrapped__')) {
+                  return wrapperClone(value);
+                }
+              }
+              return new LodashWrapper(value);
+            }
+
+            /**
+             * The base implementation of `_.create` without support for assigning
+             * properties to the created object.
+             *
+             * @private
+             * @param {Object} proto The object to inherit from.
+             * @returns {Object} Returns the new object.
+             */
+            var baseCreate = (function () {
+              function object() {}
+              return function (proto) {
+                if (!isObject(proto)) {
+                  return {};
+                }
+                if (objectCreate) {
+                  return objectCreate(proto);
+                }
+                object.prototype = proto;
+                var result = new object();
+                object.prototype = undefined;
+                return result;
+              };
+            })();
+
+            /**
+             * The function whose prototype chain sequence wrappers inherit from.
+             *
+             * @private
+             */
+            function baseLodash() {
+              // No operation performed.
+            }
+
+            /**
+             * The base constructor for creating `lodash` wrapper objects.
+             *
+             * @private
+             * @param {*} value The value to wrap.
+             * @param {boolean} [chainAll] Enable explicit method chain sequences.
+             */
+            function LodashWrapper(value, chainAll) {
+              this.__wrapped__ = value;
+              this.__actions__ = [];
+              this.__chain__ = !!chainAll;
+              this.__index__ = 0;
+              this.__values__ = undefined;
+            }
+
+            /**
+             * By default, the template delimiters used by lodash are like those in
+             * embedded Ruby (ERB) as well as ES2015 template strings. Change the
+             * following template settings to use alternative delimiters.
+             *
+             * @static
+             * @memberOf _
+             * @type {Object}
+             */
+            lodash.templateSettings = {
+              /**
+               * Used to detect `data` property values to be HTML-escaped.
+               *
+               * @memberOf _.templateSettings
+               * @type {RegExp}
+               */
+              escape: reEscape,
+
+              /**
+               * Used to detect code to be evaluated.
+               *
+               * @memberOf _.templateSettings
+               * @type {RegExp}
+               */
+              evaluate: reEvaluate,
+
+              /**
+               * Used to detect `data` property values to inject.
+               *
+               * @memberOf _.templateSettings
+               * @type {RegExp}
+               */
+              interpolate: reInterpolate,
+
+              /**
+               * Used to reference the data object in the template text.
+               *
+               * @memberOf _.templateSettings
+               * @type {string}
+               */
+              variable: '',
+
+              /**
+               * Used to import variables into the compiled template.
+               *
+               * @memberOf _.templateSettings
+               * @type {Object}
+               */
+              imports: {
+                /**
+                 * A reference to the `lodash` function.
+                 *
+                 * @memberOf _.templateSettings.imports
+                 * @type {Function}
+                 */
+                _: lodash,
+              },
+            };
+
+            // Ensure wrappers are instances of `baseLodash`.
+            lodash.prototype = baseLodash.prototype;
+            lodash.prototype.constructor = lodash;
+
+            LodashWrapper.prototype = baseCreate(baseLodash.prototype);
+            LodashWrapper.prototype.constructor = LodashWrapper;
+
+            /*------------------------------------------------------------------------*/
+
+            /**
+             * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
+             *
+             * @private
+             * @constructor
+             * @param {*} value The value to wrap.
+             */
+            function LazyWrapper(value) {
+              this.__wrapped__ = value;
+              this.__actions__ = [];
+              this.__dir__ = 1;
+              this.__filtered__ = false;
+              this.__iteratees__ = [];
+              this.__takeCount__ = MAX_ARRAY_LENGTH;
+              this.__views__ = [];
+            }
+
+            /**
+             * Creates a clone of the lazy wrapper object.
+             *
+             * @private
+             * @name clone
+             * @memberOf LazyWrapper
+             * @returns {Object} Returns the cloned `LazyWrapper` object.
+             */
+            function lazyClone() {
+              var result = new LazyWrapper(this.__wrapped__);
+              result.__actions__ = copyArray(this.__actions__);
+              result.__dir__ = this.__dir__;
+              result.__filtered__ = this.__filtered__;
+              result.__iteratees__ = copyArray(this.__iteratees__);
+              result.__takeCount__ = this.__takeCount__;
+              result.__views__ = copyArray(this.__views__);
+              return result;
+            }
+
+            /**
+             * Reverses the direction of lazy iteration.
+             *
+             * @private
+             * @name reverse
+             * @memberOf LazyWrapper
+             * @returns {Object} Returns the new reversed `LazyWrapper` object.
+             */
+            function lazyReverse() {
+              if (this.__filtered__) {
+                var result = new LazyWrapper(this);
+                result.__dir__ = -1;
+                result.__filtered__ = true;
+              } else {
+                result = this.clone();
+                result.__dir__ *= -1;
+              }
+              return result;
+            }
+
+            /**
+             * Extracts the unwrapped value from its lazy wrapper.
+             *
+             * @private
+             * @name value
+             * @memberOf LazyWrapper
+             * @returns {*} Returns the unwrapped value.
+             */
+            function lazyValue() {
+              var array = this.__wrapped__.value(),
+                dir = this.__dir__,
+                isArr = isArray(array),
+                isRight = dir < 0,
+                arrLength = isArr ? array.length : 0,
+                view = getView(0, arrLength, this.__views__),
+                start = view.start,
+                end = view.end,
+                length = end - start,
+                index = isRight ? end : start - 1,
+                iteratees = this.__iteratees__,
+                iterLength = iteratees.length,
+                resIndex = 0,
+                takeCount = nativeMin(length, this.__takeCount__);
+
+              if (!isArr || (!isRight && arrLength == length && takeCount == length)) {
+                return baseWrapperValue(array, this.__actions__);
+              }
+              var result = [];
+
+              outer: while (length-- && resIndex < takeCount) {
+                index += dir;
+
+                var iterIndex = -1,
+                  value = array[index];
+
+                while (++iterIndex < iterLength) {
+                  var data = iteratees[iterIndex],
+                    iteratee = data.iteratee,
+                    type = data.type,
+                    computed = iteratee(value);
+
+                  if (type == LAZY_MAP_FLAG) {
+                    value = computed;
+                  } else if (!computed) {
+                    if (type == LAZY_FILTER_FLAG) {
+                      continue outer;
+                    } else {
+                      break outer;
+                    }
+                  }
+                }
+                result[resIndex++] = value;
+              }
+              return result;
+            }
+
+            // Ensure `LazyWrapper` is an instance of `baseLodash`.
+            LazyWrapper.prototype = baseCreate(baseLodash.prototype);
+            LazyWrapper.prototype.constructor = LazyWrapper;
+
+            /*------------------------------------------------------------------------*/
+
+            /**
+             * Creates a hash object.
+             *
+             * @private
+             * @constructor
+             * @param {Array} [entries] The key-value pairs to cache.
+             */
+            function Hash(entries) {
+              var index = -1,
+                length = entries == null ? 0 : entries.length;
+
+              this.clear();
+              while (++index < length) {
+                var entry = entries[index];
+                this.set(entry[0], entry[1]);
+              }
+            }
+
+            /**
+             * Removes all key-value entries from the hash.
+             *
+             * @private
+             * @name clear
+             * @memberOf Hash
+             */
+            function hashClear() {
+              this.__data__ = nativeCreate ? nativeCreate(null) : {};
+              this.size = 0;
+            }
+
+            /**
+             * Removes `key` and its value from the hash.
+             *
+             * @private
+             * @name delete
+             * @memberOf Hash
+             * @param {Object} hash The hash to modify.
+             * @param {string} key The key of the value to remove.
+             * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+             */
+            function hashDelete(key) {
+              var result = this.has(key) && delete this.__data__[key];
+              this.size -= result ? 1 : 0;
+              return result;
+            }
+
+            /**
+             * Gets the hash value for `key`.
+             *
+             * @private
+             * @name get
+             * @memberOf Hash
+             * @param {string} key The key of the value to get.
+             * @returns {*} Returns the entry value.
+             */
+            function hashGet(key) {
+              var data = this.__data__;
+              if (nativeCreate) {
+                var result = data[key];
+                return result === HASH_UNDEFINED ? undefined : result;
+              }
+              return hasOwnProperty.call(data, key) ? data[key] : undefined;
+            }
+
+            /**
+             * Checks if a hash value for `key` exists.
+             *
+             * @private
+             * @name has
+             * @memberOf Hash
+             * @param {string} key The key of the entry to check.
+             * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+             */
+            function hashHas(key) {
+              var data = this.__data__;
+              return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key);
+            }
+
+            /**
+             * Sets the hash `key` to `value`.
+             *
+             * @private
+             * @name set
+             * @memberOf Hash
+             * @param {string} key The key of the value to set.
+             * @param {*} value The value to set.
+             * @returns {Object} Returns the hash instance.
+             */
+            function hashSet(key, value) {
+              var data = this.__data__;
+              this.size += this.has(key) ? 0 : 1;
+              data[key] = nativeCreate && value === undefined ? HASH_UNDEFINED : value;
+              return this;
+            }
+
+            // Add methods to `Hash`.
+            Hash.prototype.clear = hashClear;
+            Hash.prototype['delete'] = hashDelete;
+            Hash.prototype.get = hashGet;
+            Hash.prototype.has = hashHas;
+            Hash.prototype.set = hashSet;
+
+            /*------------------------------------------------------------------------*/
+
+            /**
+             * Creates an list cache object.
+             *
+             * @private
+             * @constructor
+             * @param {Array} [entries] The key-value pairs to cache.
+             */
+            function ListCache(entries) {
+              var index = -1,
+                length = entries == null ? 0 : entries.length;
+
+              this.clear();
+              while (++index < length) {
+                var entry = entries[index];
+                this.set(entry[0], entry[1]);
+              }
+            }
+
+            /**
+             * Removes all key-value entries from the list cache.
+             *
+             * @private
+             * @name clear
+             * @memberOf ListCache
+             */
+            function listCacheClear() {
+              this.__data__ = [];
+              this.size = 0;
+            }
+
+            /**
+             * Removes `key` and its value from the list cache.
+             *
+             * @private
+             * @name delete
+             * @memberOf ListCache
+             * @param {string} key The key of the value to remove.
+             * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+             */
+            function listCacheDelete(key) {
+              var data = this.__data__,
+                index = assocIndexOf(data, key);
+
+              if (index < 0) {
+                return false;
+              }
+              var lastIndex = data.length - 1;
+              if (index == lastIndex) {
+                data.pop();
+              } else {
+                splice.call(data, index, 1);
+              }
+              --this.size;
+              return true;
+            }
+
+            /**
+             * Gets the list cache value for `key`.
+             *
+             * @private
+             * @name get
+             * @memberOf ListCache
+             * @param {string} key The key of the value to get.
+             * @returns {*} Returns the entry value.
+             */
+            function listCacheGet(key) {
+              var data = this.__data__,
+                index = assocIndexOf(data, key);
+
+              return index < 0 ? undefined : data[index][1];
+            }
+
+            /**
+             * Checks if a list cache value for `key` exists.
+             *
+             * @private
+             * @name has
+             * @memberOf ListCache
+             * @param {string} key The key of the entry to check.
+             * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+             */
+            function listCacheHas(key) {
+              return assocIndexOf(this.__data__, key) > -1;
+            }
+
+            /**
+             * Sets the list cache `key` to `value`.
+             *
+             * @private
+             * @name set
+             * @memberOf ListCache
+             * @param {string} key The key of the value to set.
+             * @param {*} value The value to set.
+             * @returns {Object} Returns the list cache instance.
+             */
+            function listCacheSet(key, value) {
+              var data = this.__data__,
+                index = assocIndexOf(data, key);
+
+              if (index < 0) {
+                ++this.size;
+                data.push([key, value]);
+              } else {
+                data[index][1] = value;
+              }
+              return this;
+            }
+
+            // Add methods to `ListCache`.
+            ListCache.prototype.clear = listCacheClear;
+            ListCache.prototype['delete'] = listCacheDelete;
+            ListCache.prototype.get = listCacheGet;
+            ListCache.prototype.has = listCacheHas;
+            ListCache.prototype.set = listCacheSet;
+
+            /*------------------------------------------------------------------------*/
+
+            /**
+             * Creates a map cache object to store key-value pairs.
+             *
+             * @private
+             * @constructor
+             * @param {Array} [entries] The key-value pairs to cache.
+             */
+            function MapCache(entries) {
+              var index = -1,
+                length = entries == null ? 0 : entries.length;
+
+              this.clear();
+              while (++index < length) {
+                var entry = entries[index];
+                this.set(entry[0], entry[1]);
+              }
+            }
+
+            /**
+             * Removes all key-value entries from the map.
+             *
+             * @private
+             * @name clear
+             * @memberOf MapCache
+             */
+            function mapCacheClear() {
+              this.size = 0;
+              this.__data__ = {
+                hash: new Hash(),
+                map: new (Map || ListCache)(),
+                string: new Hash(),
+              };
+            }
+
+            /**
+             * Removes `key` and its value from the map.
+             *
+             * @private
+             * @name delete
+             * @memberOf MapCache
+             * @param {string} key The key of the value to remove.
+             * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+             */
+            function mapCacheDelete(key) {
+              var result = getMapData(this, key)['delete'](key);
+              this.size -= result ? 1 : 0;
+              return result;
+            }
+
+            /**
+             * Gets the map value for `key`.
+             *
+             * @private
+             * @name get
+             * @memberOf MapCache
+             * @param {string} key The key of the value to get.
+             * @returns {*} Returns the entry value.
+             */
+            function mapCacheGet(key) {
+              return getMapData(this, key).get(key);
+            }
+
+            /**
+             * Checks if a map value for `key` exists.
+             *
+             * @private
+             * @name has
+             * @memberOf MapCache
+             * @param {string} key The key of the entry to check.
+             * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+             */
+            function mapCacheHas(key) {
+              return getMapData(this, key).has(key);
+            }
+
+            /**
+             * Sets the map `key` to `value`.
+             *
+             * @private
+             * @name set
+             * @memberOf MapCache
+             * @param {string} key The key of the value to set.
+             * @param {*} value The value to set.
+             * @returns {Object} Returns the map cache instance.
+             */
+            function mapCacheSet(key, value) {
+              var data = getMapData(this, key),
+                size = data.size;
+
+              data.set(key, value);
+              this.size += data.size == size ? 0 : 1;
+              return this;
+            }
+
+            // Add methods to `MapCache`.
+            MapCache.prototype.clear = mapCacheClear;
+            MapCache.prototype['delete'] = mapCacheDelete;
+            MapCache.prototype.get = mapCacheGet;
+            MapCache.prototype.has = mapCacheHas;
+            MapCache.prototype.set = mapCacheSet;
+
+            /*------------------------------------------------------------------------*/
+
+            /**
+             *
+             * Creates an array cache object to store unique values.
+             *
+             * @private
+             * @constructor
+             * @param {Array} [values] The values to cache.
+             */
+            function SetCache(values) {
+              var index = -1,
+                length = values == null ? 0 : values.length;
+
+              this.__data__ = new MapCache();
+              while (++index < length) {
+                this.add(values[index]);
+              }
+            }
+
+            /**
+             * Adds `value` to the array cache.
+             *
+             * @private
+             * @name add
+             * @memberOf SetCache
+             * @alias push
+             * @param {*} value The value to cache.
+             * @returns {Object} Returns the cache instance.
+             */
+            function setCacheAdd(value) {
+              this.__data__.set(value, HASH_UNDEFINED);
+              return this;
+            }
+
+            /**
+             * Checks if `value` is in the array cache.
+             *
+             * @private
+             * @name has
+             * @memberOf SetCache
+             * @param {*} value The value to search for.
+             * @returns {number} Returns `true` if `value` is found, else `false`.
+             */
+            function setCacheHas(value) {
+              return this.__data__.has(value);
+            }
+
+            // Add methods to `SetCache`.
+            SetCache.prototype.add = SetCache.prototype.push = setCacheAdd;
+            SetCache.prototype.has = setCacheHas;
+
+            /*------------------------------------------------------------------------*/
+
+            /**
+             * Creates a stack cache object to store key-value pairs.
+             *
+             * @private
+             * @constructor
+             * @param {Array} [entries] The key-value pairs to cache.
+             */
+            function Stack(entries) {
+              var data = (this.__data__ = new ListCache(entries));
+              this.size = data.size;
+            }
+
+            /**
+             * Removes all key-value entries from the stack.
+             *
+             * @private
+             * @name clear
+             * @memberOf Stack
+             */
+            function stackClear() {
+              this.__data__ = new ListCache();
+              this.size = 0;
+            }
+
+            /**
+             * Removes `key` and its value from the stack.
+             *
+             * @private
+             * @name delete
+             * @memberOf Stack
+             * @param {string} key The key of the value to remove.
+             * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+             */
+            function stackDelete(key) {
+              var data = this.__data__,
+                result = data['delete'](key);
+
+              this.size = data.size;
+              return result;
+            }
+
+            /**
+             * Gets the stack value for `key`.
+             *
+             * @private
+             * @name get
+             * @memberOf Stack
+             * @param {string} key The key of the value to get.
+             * @returns {*} Returns the entry value.
+             */
+            function stackGet(key) {
+              return this.__data__.get(key);
+            }
+
+            /**
+             * Checks if a stack value for `key` exists.
+             *
+             * @private
+             * @name has
+             * @memberOf Stack
+             * @param {string} key The key of the entry to check.
+             * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+             */
+            function stackHas(key) {
+              return this.__data__.has(key);
+            }
+
+            /**
+             * Sets the stack `key` to `value`.
+             *
+             * @private
+             * @name set
+             * @memberOf Stack
+             * @param {string} key The key of the value to set.
+             * @param {*} value The value to set.
+             * @returns {Object} Returns the stack cache instance.
+             */
+            function stackSet(key, value) {
+              var data = this.__data__;
+              if (data instanceof ListCache) {
+                var pairs = data.__data__;
+                if (!Map || pairs.length < LARGE_ARRAY_SIZE - 1) {
+                  pairs.push([key, value]);
+                  this.size = ++data.size;
+                  return this;
+                }
+                data = this.__data__ = new MapCache(pairs);
+              }
+              data.set(key, value);
+              this.size = data.size;
+              return this;
+            }
+
+            // Add methods to `Stack`.
+            Stack.prototype.clear = stackClear;
+            Stack.prototype['delete'] = stackDelete;
+            Stack.prototype.get = stackGet;
+            Stack.prototype.has = stackHas;
+            Stack.prototype.set = stackSet;
+
+            /*------------------------------------------------------------------------*/
+
+            /**
+             * Creates an array of the enumerable property names of the array-like `value`.
+             *
+             * @private
+             * @param {*} value The value to query.
+             * @param {boolean} inherited Specify returning inherited property names.
+             * @returns {Array} Returns the array of property names.
+             */
+            function arrayLikeKeys(value, inherited) {
+              var isArr = isArray(value),
+                isArg = !isArr && isArguments(value),
+                isBuff = !isArr && !isArg && isBuffer(value),
+                isType = !isArr && !isArg && !isBuff && isTypedArray(value),
+                skipIndexes = isArr || isArg || isBuff || isType,
+                result = skipIndexes ? baseTimes(value.length, String) : [],
+                length = result.length;
+
+              for (var key in value) {
+                if (
+                  (inherited || hasOwnProperty.call(value, key)) &&
+                  !(
+                    skipIndexes &&
+                    // Safari 9 has enumerable `arguments.length` in strict mode.
+                    (key == 'length' ||
+                      // Node.js 0.10 has enumerable non-index properties on buffers.
+                      (isBuff && (key == 'offset' || key == 'parent')) ||
+                      // PhantomJS 2 has enumerable non-index properties on typed arrays.
+                      (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||
+                      // Skip index properties.
+                      isIndex(key, length))
+                  )
+                ) {
+                  result.push(key);
+                }
+              }
+              return result;
+            }
+
+            /**
+             * A specialized version of `_.sample` for arrays.
+             *
+             * @private
+             * @param {Array} array The array to sample.
+             * @returns {*} Returns the random element.
+             */
+            function arraySample(array) {
+              var length = array.length;
+              return length ? array[baseRandom(0, length - 1)] : undefined;
+            }
+
+            /**
+             * A specialized version of `_.sampleSize` for arrays.
+             *
+             * @private
+             * @param {Array} array The array to sample.
+             * @param {number} n The number of elements to sample.
+             * @returns {Array} Returns the random elements.
+             */
+            function arraySampleSize(array, n) {
+              return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length));
+            }
+
+            /**
+             * A specialized version of `_.shuffle` for arrays.
+             *
+             * @private
+             * @param {Array} array The array to shuffle.
+             * @returns {Array} Returns the new shuffled array.
+             */
+            function arrayShuffle(array) {
+              return shuffleSelf(copyArray(array));
+            }
+
+            /**
+             * This function is like `assignValue` except that it doesn't assign
+             * `undefined` values.
+             *
+             * @private
+             * @param {Object} object The object to modify.
+             * @param {string} key The key of the property to assign.
+             * @param {*} value The value to assign.
+             */
+            function assignMergeValue(object, key, value) {
+              if (
+                (value !== undefined && !eq(object[key], value)) ||
+                (value === undefined && !(key in object))
+              ) {
+                baseAssignValue(object, key, value);
+              }
+            }
+
+            /**
+             * Assigns `value` to `key` of `object` if the existing value is not equivalent
+             * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+             * for equality comparisons.
+             *
+             * @private
+             * @param {Object} object The object to modify.
+             * @param {string} key The key of the property to assign.
+             * @param {*} value The value to assign.
+             */
+            function assignValue(object, key, value) {
+              var objValue = object[key];
+              if (
+                !(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
+                (value === undefined && !(key in object))
+              ) {
+                baseAssignValue(object, key, value);
+              }
+            }
+
+            /**
+             * Gets the index at which the `key` is found in `array` of key-value pairs.
+             *
+             * @private
+             * @param {Array} array The array to inspect.
+             * @param {*} key The key to search for.
+             * @returns {number} Returns the index of the matched value, else `-1`.
+             */
+            function assocIndexOf(array, key) {
+              var length = array.length;
+              while (length--) {
+                if (eq(array[length][0], key)) {
+                  return length;
+                }
+              }
+              return -1;
+            }
+
+            /**
+             * Aggregates elements of `collection` on `accumulator` with keys transformed
+             * by `iteratee` and values set by `setter`.
+             *
+             * @private
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} setter The function to set `accumulator` values.
+             * @param {Function} iteratee The iteratee to transform keys.
+             * @param {Object} accumulator The initial aggregated object.
+             * @returns {Function} Returns `accumulator`.
+             */
+            function baseAggregator(collection, setter, iteratee, accumulator) {
+              baseEach(collection, function (value, key, collection) {
+                setter(accumulator, value, iteratee(value), collection);
+              });
+              return accumulator;
+            }
+
+            /**
+             * The base implementation of `_.assign` without support for multiple sources
+             * or `customizer` functions.
+             *
+             * @private
+             * @param {Object} object The destination object.
+             * @param {Object} source The source object.
+             * @returns {Object} Returns `object`.
+             */
+            function baseAssign(object, source) {
+              return object && copyObject(source, keys(source), object);
+            }
+
+            /**
+             * The base implementation of `_.assignIn` without support for multiple sources
+             * or `customizer` functions.
+             *
+             * @private
+             * @param {Object} object The destination object.
+             * @param {Object} source The source object.
+             * @returns {Object} Returns `object`.
+             */
+            function baseAssignIn(object, source) {
+              return object && copyObject(source, keysIn(source), object);
+            }
+
+            /**
+             * The base implementation of `assignValue` and `assignMergeValue` without
+             * value checks.
+             *
+             * @private
+             * @param {Object} object The object to modify.
+             * @param {string} key The key of the property to assign.
+             * @param {*} value The value to assign.
+             */
+            function baseAssignValue(object, key, value) {
+              if (key == '__proto__' && defineProperty) {
+                defineProperty(object, key, {
+                  configurable: true,
+                  enumerable: true,
+                  value: value,
+                  writable: true,
+                });
+              } else {
+                object[key] = value;
+              }
+            }
+
+            /**
+             * The base implementation of `_.at` without support for individual paths.
+             *
+             * @private
+             * @param {Object} object The object to iterate over.
+             * @param {string[]} paths The property paths to pick.
+             * @returns {Array} Returns the picked elements.
+             */
+            function baseAt(object, paths) {
+              var index = -1,
+                length = paths.length,
+                result = Array(length),
+                skip = object == null;
+
+              while (++index < length) {
+                result[index] = skip ? undefined : get(object, paths[index]);
+              }
+              return result;
+            }
+
+            /**
+             * The base implementation of `_.clamp` which doesn't coerce arguments.
+             *
+             * @private
+             * @param {number} number The number to clamp.
+             * @param {number} [lower] The lower bound.
+             * @param {number} upper The upper bound.
+             * @returns {number} Returns the clamped number.
+             */
+            function baseClamp(number, lower, upper) {
+              if (number === number) {
+                if (upper !== undefined) {
+                  number = number <= upper ? number : upper;
+                }
+                if (lower !== undefined) {
+                  number = number >= lower ? number : lower;
+                }
+              }
+              return number;
+            }
+
+            /**
+             * The base implementation of `_.clone` and `_.cloneDeep` which tracks
+             * traversed objects.
+             *
+             * @private
+             * @param {*} value The value to clone.
+             * @param {boolean} bitmask The bitmask flags.
+             *  1 - Deep clone
+             *  2 - Flatten inherited properties
+             *  4 - Clone symbols
+             * @param {Function} [customizer] The function to customize cloning.
+             * @param {string} [key] The key of `value`.
+             * @param {Object} [object] The parent object of `value`.
+             * @param {Object} [stack] Tracks traversed objects and their clone counterparts.
+             * @returns {*} Returns the cloned value.
+             */
+            function baseClone(value, bitmask, customizer, key, object, stack) {
+              var result,
+                isDeep = bitmask & CLONE_DEEP_FLAG,
+                isFlat = bitmask & CLONE_FLAT_FLAG,
+                isFull = bitmask & CLONE_SYMBOLS_FLAG;
+
+              if (customizer) {
+                result = object ? customizer(value, key, object, stack) : customizer(value);
+              }
+              if (result !== undefined) {
+                return result;
+              }
+              if (!isObject(value)) {
+                return value;
+              }
+              var isArr = isArray(value);
+              if (isArr) {
+                result = initCloneArray(value);
+                if (!isDeep) {
+                  return copyArray(value, result);
+                }
+              } else {
+                var tag = getTag(value),
+                  isFunc = tag == funcTag || tag == genTag;
+
+                if (isBuffer(value)) {
+                  return cloneBuffer(value, isDeep);
+                }
+                if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
+                  result = isFlat || isFunc ? {} : initCloneObject(value);
+                  if (!isDeep) {
+                    return isFlat
+                      ? copySymbolsIn(value, baseAssignIn(result, value))
+                      : copySymbols(value, baseAssign(result, value));
+                  }
+                } else {
+                  if (!cloneableTags[tag]) {
+                    return object ? value : {};
+                  }
+                  result = initCloneByTag(value, tag, isDeep);
+                }
+              }
+              // Check for circular references and return its corresponding clone.
+              stack || (stack = new Stack());
+              var stacked = stack.get(value);
+              if (stacked) {
+                return stacked;
+              }
+              stack.set(value, result);
+
+              if (isSet(value)) {
+                value.forEach(function (subValue) {
+                  result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack));
+                });
+
+                return result;
+              }
+
+              if (isMap(value)) {
+                value.forEach(function (subValue, key) {
+                  result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack));
+                });
+
+                return result;
+              }
+
+              var keysFunc = isFull ? (isFlat ? getAllKeysIn : getAllKeys) : isFlat ? keysIn : keys;
+
+              var props = isArr ? undefined : keysFunc(value);
+              arrayEach(props || value, function (subValue, key) {
+                if (props) {
+                  key = subValue;
+                  subValue = value[key];
+                }
+                // Recursively populate clone (susceptible to call stack limits).
+                assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack));
+              });
+              return result;
+            }
+
+            /**
+             * The base implementation of `_.conforms` which doesn't clone `source`.
+             *
+             * @private
+             * @param {Object} source The object of property predicates to conform to.
+             * @returns {Function} Returns the new spec function.
+             */
+            function baseConforms(source) {
+              var props = keys(source);
+              return function (object) {
+                return baseConformsTo(object, source, props);
+              };
+            }
+
+            /**
+             * The base implementation of `_.conformsTo` which accepts `props` to check.
+             *
+             * @private
+             * @param {Object} object The object to inspect.
+             * @param {Object} source The object of property predicates to conform to.
+             * @returns {boolean} Returns `true` if `object` conforms, else `false`.
+             */
+            function baseConformsTo(object, source, props) {
+              var length = props.length;
+              if (object == null) {
+                return !length;
+              }
+              object = Object(object);
+              while (length--) {
+                var key = props[length],
+                  predicate = source[key],
+                  value = object[key];
+
+                if ((value === undefined && !(key in object)) || !predicate(value)) {
+                  return false;
+                }
+              }
+              return true;
+            }
+
+            /**
+             * The base implementation of `_.delay` and `_.defer` which accepts `args`
+             * to provide to `func`.
+             *
+             * @private
+             * @param {Function} func The function to delay.
+             * @param {number} wait The number of milliseconds to delay invocation.
+             * @param {Array} args The arguments to provide to `func`.
+             * @returns {number|Object} Returns the timer id or timeout object.
+             */
+            function baseDelay(func, wait, args) {
+              if (typeof func != 'function') {
+                throw new TypeError(FUNC_ERROR_TEXT);
+              }
+              return setTimeout(function () {
+                func.apply(undefined, args);
+              }, wait);
+            }
+
+            /**
+             * The base implementation of methods like `_.difference` without support
+             * for excluding multiple arrays or iteratee shorthands.
+             *
+             * @private
+             * @param {Array} array The array to inspect.
+             * @param {Array} values The values to exclude.
+             * @param {Function} [iteratee] The iteratee invoked per element.
+             * @param {Function} [comparator] The comparator invoked per element.
+             * @returns {Array} Returns the new array of filtered values.
+             */
+            function baseDifference(array, values, iteratee, comparator) {
+              var index = -1,
+                includes = arrayIncludes,
+                isCommon = true,
+                length = array.length,
+                result = [],
+                valuesLength = values.length;
+
+              if (!length) {
+                return result;
+              }
+              if (iteratee) {
+                values = arrayMap(values, baseUnary(iteratee));
+              }
+              if (comparator) {
+                includes = arrayIncludesWith;
+                isCommon = false;
+              } else if (values.length >= LARGE_ARRAY_SIZE) {
+                includes = cacheHas;
+                isCommon = false;
+                values = new SetCache(values);
+              }
+              outer: while (++index < length) {
+                var value = array[index],
+                  computed = iteratee == null ? value : iteratee(value);
+
+                value = comparator || value !== 0 ? value : 0;
+                if (isCommon && computed === computed) {
+                  var valuesIndex = valuesLength;
+                  while (valuesIndex--) {
+                    if (values[valuesIndex] === computed) {
+                      continue outer;
+                    }
+                  }
+                  result.push(value);
+                } else if (!includes(values, computed, comparator)) {
+                  result.push(value);
+                }
+              }
+              return result;
+            }
+
+            /**
+             * The base implementation of `_.forEach` without support for iteratee shorthands.
+             *
+             * @private
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} iteratee The function invoked per iteration.
+             * @returns {Array|Object} Returns `collection`.
+             */
+            var baseEach = createBaseEach(baseForOwn);
+
+            /**
+             * The base implementation of `_.forEachRight` without support for iteratee shorthands.
+             *
+             * @private
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} iteratee The function invoked per iteration.
+             * @returns {Array|Object} Returns `collection`.
+             */
+            var baseEachRight = createBaseEach(baseForOwnRight, true);
+
+            /**
+             * The base implementation of `_.every` without support for iteratee shorthands.
+             *
+             * @private
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} predicate The function invoked per iteration.
+             * @returns {boolean} Returns `true` if all elements pass the predicate check,
+             *  else `false`
+             */
+            function baseEvery(collection, predicate) {
+              var result = true;
+              baseEach(collection, function (value, index, collection) {
+                result = !!predicate(value, index, collection);
+                return result;
+              });
+              return result;
+            }
+
+            /**
+             * The base implementation of methods like `_.max` and `_.min` which accepts a
+             * `comparator` to determine the extremum value.
+             *
+             * @private
+             * @param {Array} array The array to iterate over.
+             * @param {Function} iteratee The iteratee invoked per iteration.
+             * @param {Function} comparator The comparator used to compare values.
+             * @returns {*} Returns the extremum value.
+             */
+            function baseExtremum(array, iteratee, comparator) {
+              var index = -1,
+                length = array.length;
+
+              while (++index < length) {
+                var value = array[index],
+                  current = iteratee(value);
+
+                if (
+                  current != null &&
+                  (computed === undefined
+                    ? current === current && !isSymbol(current)
+                    : comparator(current, computed))
+                ) {
+                  var computed = current,
+                    result = value;
+                }
+              }
+              return result;
+            }
+
+            /**
+             * The base implementation of `_.fill` without an iteratee call guard.
+             *
+             * @private
+             * @param {Array} array The array to fill.
+             * @param {*} value The value to fill `array` with.
+             * @param {number} [start=0] The start position.
+             * @param {number} [end=array.length] The end position.
+             * @returns {Array} Returns `array`.
+             */
+            function baseFill(array, value, start, end) {
+              var length = array.length;
+
+              start = toInteger(start);
+              if (start < 0) {
+                start = -start > length ? 0 : length + start;
+              }
+              end = end === undefined || end > length ? length : toInteger(end);
+              if (end < 0) {
+                end += length;
+              }
+              end = start > end ? 0 : toLength(end);
+              while (start < end) {
+                array[start++] = value;
+              }
+              return array;
+            }
+
+            /**
+             * The base implementation of `_.filter` without support for iteratee shorthands.
+             *
+             * @private
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} predicate The function invoked per iteration.
+             * @returns {Array} Returns the new filtered array.
+             */
+            function baseFilter(collection, predicate) {
+              var result = [];
+              baseEach(collection, function (value, index, collection) {
+                if (predicate(value, index, collection)) {
+                  result.push(value);
+                }
+              });
+              return result;
+            }
+
+            /**
+             * The base implementation of `_.flatten` with support for restricting flattening.
+             *
+             * @private
+             * @param {Array} array The array to flatten.
+             * @param {number} depth The maximum recursion depth.
+             * @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
+             * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
+             * @param {Array} [result=[]] The initial result value.
+             * @returns {Array} Returns the new flattened array.
+             */
+            function baseFlatten(array, depth, predicate, isStrict, result) {
+              var index = -1,
+                length = array.length;
+
+              predicate || (predicate = isFlattenable);
+              result || (result = []);
+
+              while (++index < length) {
+                var value = array[index];
+                if (depth > 0 && predicate(value)) {
+                  if (depth > 1) {
+                    // Recursively flatten arrays (susceptible to call stack limits).
+                    baseFlatten(value, depth - 1, predicate, isStrict, result);
+                  } else {
+                    arrayPush(result, value);
+                  }
+                } else if (!isStrict) {
+                  result[result.length] = value;
+                }
+              }
+              return result;
+            }
+
+            /**
+             * The base implementation of `baseForOwn` which iterates over `object`
+             * properties returned by `keysFunc` and invokes `iteratee` for each property.
+             * Iteratee functions may exit iteration early by explicitly returning `false`.
+             *
+             * @private
+             * @param {Object} object The object to iterate over.
+             * @param {Function} iteratee The function invoked per iteration.
+             * @param {Function} keysFunc The function to get the keys of `object`.
+             * @returns {Object} Returns `object`.
+             */
+            var baseFor = createBaseFor();
+
+            /**
+             * This function is like `baseFor` except that it iterates over properties
+             * in the opposite order.
+             *
+             * @private
+             * @param {Object} object The object to iterate over.
+             * @param {Function} iteratee The function invoked per iteration.
+             * @param {Function} keysFunc The function to get the keys of `object`.
+             * @returns {Object} Returns `object`.
+             */
+            var baseForRight = createBaseFor(true);
+
+            /**
+             * The base implementation of `_.forOwn` without support for iteratee shorthands.
+             *
+             * @private
+             * @param {Object} object The object to iterate over.
+             * @param {Function} iteratee The function invoked per iteration.
+             * @returns {Object} Returns `object`.
+             */
+            function baseForOwn(object, iteratee) {
+              return object && baseFor(object, iteratee, keys);
+            }
+
+            /**
+             * The base implementation of `_.forOwnRight` without support for iteratee shorthands.
+             *
+             * @private
+             * @param {Object} object The object to iterate over.
+             * @param {Function} iteratee The function invoked per iteration.
+             * @returns {Object} Returns `object`.
+             */
+            function baseForOwnRight(object, iteratee) {
+              return object && baseForRight(object, iteratee, keys);
+            }
+
+            /**
+             * The base implementation of `_.functions` which creates an array of
+             * `object` function property names filtered from `props`.
+             *
+             * @private
+             * @param {Object} object The object to inspect.
+             * @param {Array} props The property names to filter.
+             * @returns {Array} Returns the function names.
+             */
+            function baseFunctions(object, props) {
+              return arrayFilter(props, function (key) {
+                return isFunction(object[key]);
+              });
+            }
+
+            /**
+             * The base implementation of `_.get` without support for default values.
+             *
+             * @private
+             * @param {Object} object The object to query.
+             * @param {Array|string} path The path of the property to get.
+             * @returns {*} Returns the resolved value.
+             */
+            function baseGet(object, path) {
+              path = castPath(path, object);
+
+              var index = 0,
+                length = path.length;
+
+              while (object != null && index < length) {
+                object = object[toKey(path[index++])];
+              }
+              return index && index == length ? object : undefined;
+            }
+
+            /**
+             * The base implementation of `getAllKeys` and `getAllKeysIn` which uses
+             * `keysFunc` and `symbolsFunc` to get the enumerable property names and
+             * symbols of `object`.
+             *
+             * @private
+             * @param {Object} object The object to query.
+             * @param {Function} keysFunc The function to get the keys of `object`.
+             * @param {Function} symbolsFunc The function to get the symbols of `object`.
+             * @returns {Array} Returns the array of property names and symbols.
+             */
+            function baseGetAllKeys(object, keysFunc, symbolsFunc) {
+              var result = keysFunc(object);
+              return isArray(object) ? result : arrayPush(result, symbolsFunc(object));
+            }
+
+            /**
+             * The base implementation of `getTag` without fallbacks for buggy environments.
+             *
+             * @private
+             * @param {*} value The value to query.
+             * @returns {string} Returns the `toStringTag`.
+             */
+            function baseGetTag(value) {
+              if (value == null) {
+                return value === undefined ? undefinedTag : nullTag;
+              }
+              return symToStringTag && symToStringTag in Object(value)
+                ? getRawTag(value)
+                : objectToString(value);
+            }
+
+            /**
+             * The base implementation of `_.gt` which doesn't coerce arguments.
+             *
+             * @private
+             * @param {*} value The value to compare.
+             * @param {*} other The other value to compare.
+             * @returns {boolean} Returns `true` if `value` is greater than `other`,
+             *  else `false`.
+             */
+            function baseGt(value, other) {
+              return value > other;
+            }
+
+            /**
+             * The base implementation of `_.has` without support for deep paths.
+             *
+             * @private
+             * @param {Object} [object] The object to query.
+             * @param {Array|string} key The key to check.
+             * @returns {boolean} Returns `true` if `key` exists, else `false`.
+             */
+            function baseHas(object, key) {
+              return object != null && hasOwnProperty.call(object, key);
+            }
+
+            /**
+             * The base implementation of `_.hasIn` without support for deep paths.
+             *
+             * @private
+             * @param {Object} [object] The object to query.
+             * @param {Array|string} key The key to check.
+             * @returns {boolean} Returns `true` if `key` exists, else `false`.
+             */
+            function baseHasIn(object, key) {
+              return object != null && key in Object(object);
+            }
+
+            /**
+             * The base implementation of `_.inRange` which doesn't coerce arguments.
+             *
+             * @private
+             * @param {number} number The number to check.
+             * @param {number} start The start of the range.
+             * @param {number} end The end of the range.
+             * @returns {boolean} Returns `true` if `number` is in the range, else `false`.
+             */
+            function baseInRange(number, start, end) {
+              return number >= nativeMin(start, end) && number < nativeMax(start, end);
+            }
+
+            /**
+             * The base implementation of methods like `_.intersection`, without support
+             * for iteratee shorthands, that accepts an array of arrays to inspect.
+             *
+             * @private
+             * @param {Array} arrays The arrays to inspect.
+             * @param {Function} [iteratee] The iteratee invoked per element.
+             * @param {Function} [comparator] The comparator invoked per element.
+             * @returns {Array} Returns the new array of shared values.
+             */
+            function baseIntersection(arrays, iteratee, comparator) {
+              var includes = comparator ? arrayIncludesWith : arrayIncludes,
+                length = arrays[0].length,
+                othLength = arrays.length,
+                othIndex = othLength,
+                caches = Array(othLength),
+                maxLength = Infinity,
+                result = [];
+
+              while (othIndex--) {
+                var array = arrays[othIndex];
+                if (othIndex && iteratee) {
+                  array = arrayMap(array, baseUnary(iteratee));
+                }
+                maxLength = nativeMin(array.length, maxLength);
+                caches[othIndex] =
+                  !comparator && (iteratee || (length >= 120 && array.length >= 120))
+                    ? new SetCache(othIndex && array)
+                    : undefined;
+              }
+              array = arrays[0];
+
+              var index = -1,
+                seen = caches[0];
+
+              outer: while (++index < length && result.length < maxLength) {
+                var value = array[index],
+                  computed = iteratee ? iteratee(value) : value;
+
+                value = comparator || value !== 0 ? value : 0;
+                if (!(seen ? cacheHas(seen, computed) : includes(result, computed, comparator))) {
+                  othIndex = othLength;
+                  while (--othIndex) {
+                    var cache = caches[othIndex];
+                    if (
+                      !(cache ? cacheHas(cache, computed) : includes(arrays[othIndex], computed, comparator))
+                    ) {
+                      continue outer;
+                    }
+                  }
+                  if (seen) {
+                    seen.push(computed);
+                  }
+                  result.push(value);
+                }
+              }
+              return result;
+            }
+
+            /**
+             * The base implementation of `_.invert` and `_.invertBy` which inverts
+             * `object` with values transformed by `iteratee` and set by `setter`.
+             *
+             * @private
+             * @param {Object} object The object to iterate over.
+             * @param {Function} setter The function to set `accumulator` values.
+             * @param {Function} iteratee The iteratee to transform values.
+             * @param {Object} accumulator The initial inverted object.
+             * @returns {Function} Returns `accumulator`.
+             */
+            function baseInverter(object, setter, iteratee, accumulator) {
+              baseForOwn(object, function (value, key, object) {
+                setter(accumulator, iteratee(value), key, object);
+              });
+              return accumulator;
+            }
+
+            /**
+             * The base implementation of `_.invoke` without support for individual
+             * method arguments.
+             *
+             * @private
+             * @param {Object} object The object to query.
+             * @param {Array|string} path The path of the method to invoke.
+             * @param {Array} args The arguments to invoke the method with.
+             * @returns {*} Returns the result of the invoked method.
+             */
+            function baseInvoke(object, path, args) {
+              path = castPath(path, object);
+              object = parent(object, path);
+              var func = object == null ? object : object[toKey(last(path))];
+              return func == null ? undefined : apply(func, object, args);
+            }
+
+            /**
+             * The base implementation of `_.isArguments`.
+             *
+             * @private
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is an `arguments` object,
+             */
+            function baseIsArguments(value) {
+              return isObjectLike(value) && baseGetTag(value) == argsTag;
+            }
+
+            /**
+             * The base implementation of `_.isArrayBuffer` without Node.js optimizations.
+             *
+             * @private
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
+             */
+            function baseIsArrayBuffer(value) {
+              return isObjectLike(value) && baseGetTag(value) == arrayBufferTag;
+            }
+
+            /**
+             * The base implementation of `_.isDate` without Node.js optimizations.
+             *
+             * @private
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a date object, else `false`.
+             */
+            function baseIsDate(value) {
+              return isObjectLike(value) && baseGetTag(value) == dateTag;
+            }
+
+            /**
+             * The base implementation of `_.isEqual` which supports partial comparisons
+             * and tracks traversed objects.
+             *
+             * @private
+             * @param {*} value The value to compare.
+             * @param {*} other The other value to compare.
+             * @param {boolean} bitmask The bitmask flags.
+             *  1 - Unordered comparison
+             *  2 - Partial comparison
+             * @param {Function} [customizer] The function to customize comparisons.
+             * @param {Object} [stack] Tracks traversed `value` and `other` objects.
+             * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+             */
+            function baseIsEqual(value, other, bitmask, customizer, stack) {
+              if (value === other) {
+                return true;
+              }
+              if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) {
+                return value !== value && other !== other;
+              }
+              return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack);
+            }
+
+            /**
+             * A specialized version of `baseIsEqual` for arrays and objects which performs
+             * deep comparisons and tracks traversed objects enabling objects with circular
+             * references to be compared.
+             *
+             * @private
+             * @param {Object} object The object to compare.
+             * @param {Object} other The other object to compare.
+             * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
+             * @param {Function} customizer The function to customize comparisons.
+             * @param {Function} equalFunc The function to determine equivalents of values.
+             * @param {Object} [stack] Tracks traversed `object` and `other` objects.
+             * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+             */
+            function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {
+              var objIsArr = isArray(object),
+                othIsArr = isArray(other),
+                objTag = objIsArr ? arrayTag : getTag(object),
+                othTag = othIsArr ? arrayTag : getTag(other);
+
+              objTag = objTag == argsTag ? objectTag : objTag;
+              othTag = othTag == argsTag ? objectTag : othTag;
+
+              var objIsObj = objTag == objectTag,
+                othIsObj = othTag == objectTag,
+                isSameTag = objTag == othTag;
+
+              if (isSameTag && isBuffer(object)) {
+                if (!isBuffer(other)) {
+                  return false;
+                }
+                objIsArr = true;
+                objIsObj = false;
+              }
+              if (isSameTag && !objIsObj) {
+                stack || (stack = new Stack());
+                return objIsArr || isTypedArray(object)
+                  ? equalArrays(object, other, bitmask, customizer, equalFunc, stack)
+                  : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);
+              }
+              if (!(bitmask & COMPARE_PARTIAL_FLAG)) {
+                var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
+                  othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
+
+                if (objIsWrapped || othIsWrapped) {
+                  var objUnwrapped = objIsWrapped ? object.value() : object,
+                    othUnwrapped = othIsWrapped ? other.value() : other;
+
+                  stack || (stack = new Stack());
+                  return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);
+                }
+              }
+              if (!isSameTag) {
+                return false;
+              }
+              stack || (stack = new Stack());
+              return equalObjects(object, other, bitmask, customizer, equalFunc, stack);
+            }
+
+            /**
+             * The base implementation of `_.isMap` without Node.js optimizations.
+             *
+             * @private
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a map, else `false`.
+             */
+            function baseIsMap(value) {
+              return isObjectLike(value) && getTag(value) == mapTag;
+            }
+
+            /**
+             * The base implementation of `_.isMatch` without support for iteratee shorthands.
+             *
+             * @private
+             * @param {Object} object The object to inspect.
+             * @param {Object} source The object of property values to match.
+             * @param {Array} matchData The property names, values, and compare flags to match.
+             * @param {Function} [customizer] The function to customize comparisons.
+             * @returns {boolean} Returns `true` if `object` is a match, else `false`.
+             */
+            function baseIsMatch(object, source, matchData, customizer) {
+              var index = matchData.length,
+                length = index,
+                noCustomizer = !customizer;
+
+              if (object == null) {
+                return !length;
+              }
+              object = Object(object);
+              while (index--) {
+                var data = matchData[index];
+                if (noCustomizer && data[2] ? data[1] !== object[data[0]] : !(data[0] in object)) {
+                  return false;
+                }
+              }
+              while (++index < length) {
+                data = matchData[index];
+                var key = data[0],
+                  objValue = object[key],
+                  srcValue = data[1];
+
+                if (noCustomizer && data[2]) {
+                  if (objValue === undefined && !(key in object)) {
+                    return false;
+                  }
+                } else {
+                  var stack = new Stack();
+                  if (customizer) {
+                    var result = customizer(objValue, srcValue, key, object, source, stack);
+                  }
+                  if (
+                    !(result === undefined
+                      ? baseIsEqual(
+                          srcValue,
+                          objValue,
+                          COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG,
+                          customizer,
+                          stack
+                        )
+                      : result)
+                  ) {
+                    return false;
+                  }
+                }
+              }
+              return true;
+            }
+
+            /**
+             * The base implementation of `_.isNative` without bad shim checks.
+             *
+             * @private
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a native function,
+             *  else `false`.
+             */
+            function baseIsNative(value) {
+              if (!isObject(value) || isMasked(value)) {
+                return false;
+              }
+              var pattern = isFunction(value) ? reIsNative : reIsHostCtor;
+              return pattern.test(toSource(value));
+            }
+
+            /**
+             * The base implementation of `_.isRegExp` without Node.js optimizations.
+             *
+             * @private
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
+             */
+            function baseIsRegExp(value) {
+              return isObjectLike(value) && baseGetTag(value) == regexpTag;
+            }
+
+            /**
+             * The base implementation of `_.isSet` without Node.js optimizations.
+             *
+             * @private
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a set, else `false`.
+             */
+            function baseIsSet(value) {
+              return isObjectLike(value) && getTag(value) == setTag;
+            }
+
+            /**
+             * The base implementation of `_.isTypedArray` without Node.js optimizations.
+             *
+             * @private
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
+             */
+            function baseIsTypedArray(value) {
+              return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[baseGetTag(value)];
+            }
+
+            /**
+             * The base implementation of `_.iteratee`.
+             *
+             * @private
+             * @param {*} [value=_.identity] The value to convert to an iteratee.
+             * @returns {Function} Returns the iteratee.
+             */
+            function baseIteratee(value) {
+              // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9.
+              // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details.
+              if (typeof value == 'function') {
+                return value;
+              }
+              if (value == null) {
+                return identity;
+              }
+              if (typeof value == 'object') {
+                return isArray(value) ? baseMatchesProperty(value[0], value[1]) : baseMatches(value);
+              }
+              return property(value);
+            }
+
+            /**
+             * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.
+             *
+             * @private
+             * @param {Object} object The object to query.
+             * @returns {Array} Returns the array of property names.
+             */
+            function baseKeys(object) {
+              if (!isPrototype(object)) {
+                return nativeKeys(object);
+              }
+              var result = [];
+              for (var key in Object(object)) {
+                if (hasOwnProperty.call(object, key) && key != 'constructor') {
+                  result.push(key);
+                }
+              }
+              return result;
+            }
+
+            /**
+             * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense.
+             *
+             * @private
+             * @param {Object} object The object to query.
+             * @returns {Array} Returns the array of property names.
+             */
+            function baseKeysIn(object) {
+              if (!isObject(object)) {
+                return nativeKeysIn(object);
+              }
+              var isProto = isPrototype(object),
+                result = [];
+
+              for (var key in object) {
+                if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
+                  result.push(key);
+                }
+              }
+              return result;
+            }
+
+            /**
+             * The base implementation of `_.lt` which doesn't coerce arguments.
+             *
+             * @private
+             * @param {*} value The value to compare.
+             * @param {*} other The other value to compare.
+             * @returns {boolean} Returns `true` if `value` is less than `other`,
+             *  else `false`.
+             */
+            function baseLt(value, other) {
+              return value < other;
+            }
+
+            /**
+             * The base implementation of `_.map` without support for iteratee shorthands.
+             *
+             * @private
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} iteratee The function invoked per iteration.
+             * @returns {Array} Returns the new mapped array.
+             */
+            function baseMap(collection, iteratee) {
+              var index = -1,
+                result = isArrayLike(collection) ? Array(collection.length) : [];
+
+              baseEach(collection, function (value, key, collection) {
+                result[++index] = iteratee(value, key, collection);
+              });
+              return result;
+            }
+
+            /**
+             * The base implementation of `_.matches` which doesn't clone `source`.
+             *
+             * @private
+             * @param {Object} source The object of property values to match.
+             * @returns {Function} Returns the new spec function.
+             */
+            function baseMatches(source) {
+              var matchData = getMatchData(source);
+              if (matchData.length == 1 && matchData[0][2]) {
+                return matchesStrictComparable(matchData[0][0], matchData[0][1]);
+              }
+              return function (object) {
+                return object === source || baseIsMatch(object, source, matchData);
+              };
+            }
+
+            /**
+             * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`.
+             *
+             * @private
+             * @param {string} path The path of the property to get.
+             * @param {*} srcValue The value to match.
+             * @returns {Function} Returns the new spec function.
+             */
+            function baseMatchesProperty(path, srcValue) {
+              if (isKey(path) && isStrictComparable(srcValue)) {
+                return matchesStrictComparable(toKey(path), srcValue);
+              }
+              return function (object) {
+                var objValue = get(object, path);
+                return objValue === undefined && objValue === srcValue
+                  ? hasIn(object, path)
+                  : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG);
+              };
+            }
+
+            /**
+             * The base implementation of `_.merge` without support for multiple sources.
+             *
+             * @private
+             * @param {Object} object The destination object.
+             * @param {Object} source The source object.
+             * @param {number} srcIndex The index of `source`.
+             * @param {Function} [customizer] The function to customize merged values.
+             * @param {Object} [stack] Tracks traversed source values and their merged
+             *  counterparts.
+             */
+            function baseMerge(object, source, srcIndex, customizer, stack) {
+              if (object === source) {
+                return;
+              }
+              baseFor(
+                source,
+                function (srcValue, key) {
+                  if (isObject(srcValue)) {
+                    stack || (stack = new Stack());
+                    baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
+                  } else {
+                    var newValue = customizer
+                      ? customizer(safeGet(object, key), srcValue, key + '', object, source, stack)
+                      : undefined;
+
+                    if (newValue === undefined) {
+                      newValue = srcValue;
+                    }
+                    assignMergeValue(object, key, newValue);
+                  }
+                },
+                keysIn
+              );
+            }
+
+            /**
+             * A specialized version of `baseMerge` for arrays and objects which performs
+             * deep merges and tracks traversed objects enabling objects with circular
+             * references to be merged.
+             *
+             * @private
+             * @param {Object} object The destination object.
+             * @param {Object} source The source object.
+             * @param {string} key The key of the value to merge.
+             * @param {number} srcIndex The index of `source`.
+             * @param {Function} mergeFunc The function to merge values.
+             * @param {Function} [customizer] The function to customize assigned values.
+             * @param {Object} [stack] Tracks traversed source values and their merged
+             *  counterparts.
+             */
+            function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {
+              var objValue = safeGet(object, key),
+                srcValue = safeGet(source, key),
+                stacked = stack.get(srcValue);
+
+              if (stacked) {
+                assignMergeValue(object, key, stacked);
+                return;
+              }
+              var newValue = customizer
+                ? customizer(objValue, srcValue, key + '', object, source, stack)
+                : undefined;
+
+              var isCommon = newValue === undefined;
+
+              if (isCommon) {
+                var isArr = isArray(srcValue),
+                  isBuff = !isArr && isBuffer(srcValue),
+                  isTyped = !isArr && !isBuff && isTypedArray(srcValue);
+
+                newValue = srcValue;
+                if (isArr || isBuff || isTyped) {
+                  if (isArray(objValue)) {
+                    newValue = objValue;
+                  } else if (isArrayLikeObject(objValue)) {
+                    newValue = copyArray(objValue);
+                  } else if (isBuff) {
+                    isCommon = false;
+                    newValue = cloneBuffer(srcValue, true);
+                  } else if (isTyped) {
+                    isCommon = false;
+                    newValue = cloneTypedArray(srcValue, true);
+                  } else {
+                    newValue = [];
+                  }
+                } else if (isPlainObject(srcValue) || isArguments(srcValue)) {
+                  newValue = objValue;
+                  if (isArguments(objValue)) {
+                    newValue = toPlainObject(objValue);
+                  } else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) {
+                    newValue = initCloneObject(srcValue);
+                  }
+                } else {
+                  isCommon = false;
+                }
+              }
+              if (isCommon) {
+                // Recursively merge objects and arrays (susceptible to call stack limits).
+                stack.set(srcValue, newValue);
+                mergeFunc(newValue, srcValue, srcIndex, customizer, stack);
+                stack['delete'](srcValue);
+              }
+              assignMergeValue(object, key, newValue);
+            }
+
+            /**
+             * The base implementation of `_.nth` which doesn't coerce arguments.
+             *
+             * @private
+             * @param {Array} array The array to query.
+             * @param {number} n The index of the element to return.
+             * @returns {*} Returns the nth element of `array`.
+             */
+            function baseNth(array, n) {
+              var length = array.length;
+              if (!length) {
+                return;
+              }
+              n += n < 0 ? length : 0;
+              return isIndex(n, length) ? array[n] : undefined;
+            }
+
+            /**
+             * The base implementation of `_.orderBy` without param guards.
+             *
+             * @private
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by.
+             * @param {string[]} orders The sort orders of `iteratees`.
+             * @returns {Array} Returns the new sorted array.
+             */
+            function baseOrderBy(collection, iteratees, orders) {
+              var index = -1;
+              iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(getIteratee()));
+
+              var result = baseMap(collection, function (value, key, collection) {
+                var criteria = arrayMap(iteratees, function (iteratee) {
+                  return iteratee(value);
+                });
+                return { criteria: criteria, index: ++index, value: value };
+              });
+
+              return baseSortBy(result, function (object, other) {
+                return compareMultiple(object, other, orders);
+              });
+            }
+
+            /**
+             * The base implementation of `_.pick` without support for individual
+             * property identifiers.
+             *
+             * @private
+             * @param {Object} object The source object.
+             * @param {string[]} paths The property paths to pick.
+             * @returns {Object} Returns the new object.
+             */
+            function basePick(object, paths) {
+              return basePickBy(object, paths, function (value, path) {
+                return hasIn(object, path);
+              });
+            }
+
+            /**
+             * The base implementation of  `_.pickBy` without support for iteratee shorthands.
+             *
+             * @private
+             * @param {Object} object The source object.
+             * @param {string[]} paths The property paths to pick.
+             * @param {Function} predicate The function invoked per property.
+             * @returns {Object} Returns the new object.
+             */
+            function basePickBy(object, paths, predicate) {
+              var index = -1,
+                length = paths.length,
+                result = {};
+
+              while (++index < length) {
+                var path = paths[index],
+                  value = baseGet(object, path);
+
+                if (predicate(value, path)) {
+                  baseSet(result, castPath(path, object), value);
+                }
+              }
+              return result;
+            }
+
+            /**
+             * A specialized version of `baseProperty` which supports deep paths.
+             *
+             * @private
+             * @param {Array|string} path The path of the property to get.
+             * @returns {Function} Returns the new accessor function.
+             */
+            function basePropertyDeep(path) {
+              return function (object) {
+                return baseGet(object, path);
+              };
+            }
+
+            /**
+             * The base implementation of `_.pullAllBy` without support for iteratee
+             * shorthands.
+             *
+             * @private
+             * @param {Array} array The array to modify.
+             * @param {Array} values The values to remove.
+             * @param {Function} [iteratee] The iteratee invoked per element.
+             * @param {Function} [comparator] The comparator invoked per element.
+             * @returns {Array} Returns `array`.
+             */
+            function basePullAll(array, values, iteratee, comparator) {
+              var indexOf = comparator ? baseIndexOfWith : baseIndexOf,
+                index = -1,
+                length = values.length,
+                seen = array;
+
+              if (array === values) {
+                values = copyArray(values);
+              }
+              if (iteratee) {
+                seen = arrayMap(array, baseUnary(iteratee));
+              }
+              while (++index < length) {
+                var fromIndex = 0,
+                  value = values[index],
+                  computed = iteratee ? iteratee(value) : value;
+
+                while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) {
+                  if (seen !== array) {
+                    splice.call(seen, fromIndex, 1);
+                  }
+                  splice.call(array, fromIndex, 1);
+                }
+              }
+              return array;
+            }
+
+            /**
+             * The base implementation of `_.pullAt` without support for individual
+             * indexes or capturing the removed elements.
+             *
+             * @private
+             * @param {Array} array The array to modify.
+             * @param {number[]} indexes The indexes of elements to remove.
+             * @returns {Array} Returns `array`.
+             */
+            function basePullAt(array, indexes) {
+              var length = array ? indexes.length : 0,
+                lastIndex = length - 1;
+
+              while (length--) {
+                var index = indexes[length];
+                if (length == lastIndex || index !== previous) {
+                  var previous = index;
+                  if (isIndex(index)) {
+                    splice.call(array, index, 1);
+                  } else {
+                    baseUnset(array, index);
+                  }
+                }
+              }
+              return array;
+            }
+
+            /**
+             * The base implementation of `_.random` without support for returning
+             * floating-point numbers.
+             *
+             * @private
+             * @param {number} lower The lower bound.
+             * @param {number} upper The upper bound.
+             * @returns {number} Returns the random number.
+             */
+            function baseRandom(lower, upper) {
+              return lower + nativeFloor(nativeRandom() * (upper - lower + 1));
+            }
+
+            /**
+             * The base implementation of `_.range` and `_.rangeRight` which doesn't
+             * coerce arguments.
+             *
+             * @private
+             * @param {number} start The start of the range.
+             * @param {number} end The end of the range.
+             * @param {number} step The value to increment or decrement by.
+             * @param {boolean} [fromRight] Specify iterating from right to left.
+             * @returns {Array} Returns the range of numbers.
+             */
+            function baseRange(start, end, step, fromRight) {
+              var index = -1,
+                length = nativeMax(nativeCeil((end - start) / (step || 1)), 0),
+                result = Array(length);
+
+              while (length--) {
+                result[fromRight ? length : ++index] = start;
+                start += step;
+              }
+              return result;
+            }
+
+            /**
+             * The base implementation of `_.repeat` which doesn't coerce arguments.
+             *
+             * @private
+             * @param {string} string The string to repeat.
+             * @param {number} n The number of times to repeat the string.
+             * @returns {string} Returns the repeated string.
+             */
+            function baseRepeat(string, n) {
+              var result = '';
+              if (!string || n < 1 || n > MAX_SAFE_INTEGER) {
+                return result;
+              }
+              // Leverage the exponentiation by squaring algorithm for a faster repeat.
+              // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details.
+              do {
+                if (n % 2) {
+                  result += string;
+                }
+                n = nativeFloor(n / 2);
+                if (n) {
+                  string += string;
+                }
+              } while (n);
+
+              return result;
+            }
+
+            /**
+             * The base implementation of `_.rest` which doesn't validate or coerce arguments.
+             *
+             * @private
+             * @param {Function} func The function to apply a rest parameter to.
+             * @param {number} [start=func.length-1] The start position of the rest parameter.
+             * @returns {Function} Returns the new function.
+             */
+            function baseRest(func, start) {
+              return setToString(overRest(func, start, identity), func + '');
+            }
+
+            /**
+             * The base implementation of `_.sample`.
+             *
+             * @private
+             * @param {Array|Object} collection The collection to sample.
+             * @returns {*} Returns the random element.
+             */
+            function baseSample(collection) {
+              return arraySample(values(collection));
+            }
+
+            /**
+             * The base implementation of `_.sampleSize` without param guards.
+             *
+             * @private
+             * @param {Array|Object} collection The collection to sample.
+             * @param {number} n The number of elements to sample.
+             * @returns {Array} Returns the random elements.
+             */
+            function baseSampleSize(collection, n) {
+              var array = values(collection);
+              return shuffleSelf(array, baseClamp(n, 0, array.length));
+            }
+
+            /**
+             * The base implementation of `_.set`.
+             *
+             * @private
+             * @param {Object} object The object to modify.
+             * @param {Array|string} path The path of the property to set.
+             * @param {*} value The value to set.
+             * @param {Function} [customizer] The function to customize path creation.
+             * @returns {Object} Returns `object`.
+             */
+            function baseSet(object, path, value, customizer) {
+              if (!isObject(object)) {
+                return object;
+              }
+              path = castPath(path, object);
+
+              var index = -1,
+                length = path.length,
+                lastIndex = length - 1,
+                nested = object;
+
+              while (nested != null && ++index < length) {
+                var key = toKey(path[index]),
+                  newValue = value;
+
+                if (index != lastIndex) {
+                  var objValue = nested[key];
+                  newValue = customizer ? customizer(objValue, key, nested) : undefined;
+                  if (newValue === undefined) {
+                    newValue = isObject(objValue) ? objValue : isIndex(path[index + 1]) ? [] : {};
+                  }
+                }
+                assignValue(nested, key, newValue);
+                nested = nested[key];
+              }
+              return object;
+            }
+
+            /**
+             * The base implementation of `setData` without support for hot loop shorting.
+             *
+             * @private
+             * @param {Function} func The function to associate metadata with.
+             * @param {*} data The metadata.
+             * @returns {Function} Returns `func`.
+             */
+            var baseSetData = !metaMap
+              ? identity
+              : function (func, data) {
+                  metaMap.set(func, data);
+                  return func;
+                };
+
+            /**
+             * The base implementation of `setToString` without support for hot loop shorting.
+             *
+             * @private
+             * @param {Function} func The function to modify.
+             * @param {Function} string The `toString` result.
+             * @returns {Function} Returns `func`.
+             */
+            var baseSetToString = !defineProperty
+              ? identity
+              : function (func, string) {
+                  return defineProperty(func, 'toString', {
+                    configurable: true,
+                    enumerable: false,
+                    value: constant(string),
+                    writable: true,
+                  });
+                };
+
+            /**
+             * The base implementation of `_.shuffle`.
+             *
+             * @private
+             * @param {Array|Object} collection The collection to shuffle.
+             * @returns {Array} Returns the new shuffled array.
+             */
+            function baseShuffle(collection) {
+              return shuffleSelf(values(collection));
+            }
+
+            /**
+             * The base implementation of `_.slice` without an iteratee call guard.
+             *
+             * @private
+             * @param {Array} array The array to slice.
+             * @param {number} [start=0] The start position.
+             * @param {number} [end=array.length] The end position.
+             * @returns {Array} Returns the slice of `array`.
+             */
+            function baseSlice(array, start, end) {
+              var index = -1,
+                length = array.length;
+
+              if (start < 0) {
+                start = -start > length ? 0 : length + start;
+              }
+              end = end > length ? length : end;
+              if (end < 0) {
+                end += length;
+              }
+              length = start > end ? 0 : (end - start) >>> 0;
+              start >>>= 0;
+
+              var result = Array(length);
+              while (++index < length) {
+                result[index] = array[index + start];
+              }
+              return result;
+            }
+
+            /**
+             * The base implementation of `_.some` without support for iteratee shorthands.
+             *
+             * @private
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} predicate The function invoked per iteration.
+             * @returns {boolean} Returns `true` if any element passes the predicate check,
+             *  else `false`.
+             */
+            function baseSome(collection, predicate) {
+              var result;
+
+              baseEach(collection, function (value, index, collection) {
+                result = predicate(value, index, collection);
+                return !result;
+              });
+              return !!result;
+            }
+
+            /**
+             * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which
+             * performs a binary search of `array` to determine the index at which `value`
+             * should be inserted into `array` in order to maintain its sort order.
+             *
+             * @private
+             * @param {Array} array The sorted array to inspect.
+             * @param {*} value The value to evaluate.
+             * @param {boolean} [retHighest] Specify returning the highest qualified index.
+             * @returns {number} Returns the index at which `value` should be inserted
+             *  into `array`.
+             */
+            function baseSortedIndex(array, value, retHighest) {
+              var low = 0,
+                high = array == null ? low : array.length;
+
+              if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
+                while (low < high) {
+                  var mid = (low + high) >>> 1,
+                    computed = array[mid];
+
+                  if (
+                    computed !== null &&
+                    !isSymbol(computed) &&
+                    (retHighest ? computed <= value : computed < value)
+                  ) {
+                    low = mid + 1;
+                  } else {
+                    high = mid;
+                  }
+                }
+                return high;
+              }
+              return baseSortedIndexBy(array, value, identity, retHighest);
+            }
+
+            /**
+             * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy`
+             * which invokes `iteratee` for `value` and each element of `array` to compute
+             * their sort ranking. The iteratee is invoked with one argument; (value).
+             *
+             * @private
+             * @param {Array} array The sorted array to inspect.
+             * @param {*} value The value to evaluate.
+             * @param {Function} iteratee The iteratee invoked per element.
+             * @param {boolean} [retHighest] Specify returning the highest qualified index.
+             * @returns {number} Returns the index at which `value` should be inserted
+             *  into `array`.
+             */
+            function baseSortedIndexBy(array, value, iteratee, retHighest) {
+              value = iteratee(value);
+
+              var low = 0,
+                high = array == null ? 0 : array.length,
+                valIsNaN = value !== value,
+                valIsNull = value === null,
+                valIsSymbol = isSymbol(value),
+                valIsUndefined = value === undefined;
+
+              while (low < high) {
+                var mid = nativeFloor((low + high) / 2),
+                  computed = iteratee(array[mid]),
+                  othIsDefined = computed !== undefined,
+                  othIsNull = computed === null,
+                  othIsReflexive = computed === computed,
+                  othIsSymbol = isSymbol(computed);
+
+                if (valIsNaN) {
+                  var setLow = retHighest || othIsReflexive;
+                } else if (valIsUndefined) {
+                  setLow = othIsReflexive && (retHighest || othIsDefined);
+                } else if (valIsNull) {
+                  setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull);
+                } else if (valIsSymbol) {
+                  setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol);
+                } else if (othIsNull || othIsSymbol) {
+                  setLow = false;
+                } else {
+                  setLow = retHighest ? computed <= value : computed < value;
+                }
+                if (setLow) {
+                  low = mid + 1;
+                } else {
+                  high = mid;
+                }
+              }
+              return nativeMin(high, MAX_ARRAY_INDEX);
+            }
+
+            /**
+             * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without
+             * support for iteratee shorthands.
+             *
+             * @private
+             * @param {Array} array The array to inspect.
+             * @param {Function} [iteratee] The iteratee invoked per element.
+             * @returns {Array} Returns the new duplicate free array.
+             */
+            function baseSortedUniq(array, iteratee) {
+              var index = -1,
+                length = array.length,
+                resIndex = 0,
+                result = [];
+
+              while (++index < length) {
+                var value = array[index],
+                  computed = iteratee ? iteratee(value) : value;
+
+                if (!index || !eq(computed, seen)) {
+                  var seen = computed;
+                  result[resIndex++] = value === 0 ? 0 : value;
+                }
+              }
+              return result;
+            }
+
+            /**
+             * The base implementation of `_.toNumber` which doesn't ensure correct
+             * conversions of binary, hexadecimal, or octal string values.
+             *
+             * @private
+             * @param {*} value The value to process.
+             * @returns {number} Returns the number.
+             */
+            function baseToNumber(value) {
+              if (typeof value == 'number') {
+                return value;
+              }
+              if (isSymbol(value)) {
+                return NAN;
+              }
+              return +value;
+            }
+
+            /**
+             * The base implementation of `_.toString` which doesn't convert nullish
+             * values to empty strings.
+             *
+             * @private
+             * @param {*} value The value to process.
+             * @returns {string} Returns the string.
+             */
+            function baseToString(value) {
+              // Exit early for strings to avoid a performance hit in some environments.
+              if (typeof value == 'string') {
+                return value;
+              }
+              if (isArray(value)) {
+                // Recursively convert values (susceptible to call stack limits).
+                return arrayMap(value, baseToString) + '';
+              }
+              if (isSymbol(value)) {
+                return symbolToString ? symbolToString.call(value) : '';
+              }
+              var result = value + '';
+              return result == '0' && 1 / value == -INFINITY ? '-0' : result;
+            }
+
+            /**
+             * The base implementation of `_.uniqBy` without support for iteratee shorthands.
+             *
+             * @private
+             * @param {Array} array The array to inspect.
+             * @param {Function} [iteratee] The iteratee invoked per element.
+             * @param {Function} [comparator] The comparator invoked per element.
+             * @returns {Array} Returns the new duplicate free array.
+             */
+            function baseUniq(array, iteratee, comparator) {
+              var index = -1,
+                includes = arrayIncludes,
+                length = array.length,
+                isCommon = true,
+                result = [],
+                seen = result;
+
+              if (comparator) {
+                isCommon = false;
+                includes = arrayIncludesWith;
+              } else if (length >= LARGE_ARRAY_SIZE) {
+                var set = iteratee ? null : createSet(array);
+                if (set) {
+                  return setToArray(set);
+                }
+                isCommon = false;
+                includes = cacheHas;
+                seen = new SetCache();
+              } else {
+                seen = iteratee ? [] : result;
+              }
+              outer: while (++index < length) {
+                var value = array[index],
+                  computed = iteratee ? iteratee(value) : value;
+
+                value = comparator || value !== 0 ? value : 0;
+                if (isCommon && computed === computed) {
+                  var seenIndex = seen.length;
+                  while (seenIndex--) {
+                    if (seen[seenIndex] === computed) {
+                      continue outer;
+                    }
+                  }
+                  if (iteratee) {
+                    seen.push(computed);
+                  }
+                  result.push(value);
+                } else if (!includes(seen, computed, comparator)) {
+                  if (seen !== result) {
+                    seen.push(computed);
+                  }
+                  result.push(value);
+                }
+              }
+              return result;
+            }
+
+            /**
+             * The base implementation of `_.unset`.
+             *
+             * @private
+             * @param {Object} object The object to modify.
+             * @param {Array|string} path The property path to unset.
+             * @returns {boolean} Returns `true` if the property is deleted, else `false`.
+             */
+            function baseUnset(object, path) {
+              path = castPath(path, object);
+              object = parent(object, path);
+              return object == null || delete object[toKey(last(path))];
+            }
+
+            /**
+             * The base implementation of `_.update`.
+             *
+             * @private
+             * @param {Object} object The object to modify.
+             * @param {Array|string} path The path of the property to update.
+             * @param {Function} updater The function to produce the updated value.
+             * @param {Function} [customizer] The function to customize path creation.
+             * @returns {Object} Returns `object`.
+             */
+            function baseUpdate(object, path, updater, customizer) {
+              return baseSet(object, path, updater(baseGet(object, path)), customizer);
+            }
+
+            /**
+             * The base implementation of methods like `_.dropWhile` and `_.takeWhile`
+             * without support for iteratee shorthands.
+             *
+             * @private
+             * @param {Array} array The array to query.
+             * @param {Function} predicate The function invoked per iteration.
+             * @param {boolean} [isDrop] Specify dropping elements instead of taking them.
+             * @param {boolean} [fromRight] Specify iterating from right to left.
+             * @returns {Array} Returns the slice of `array`.
+             */
+            function baseWhile(array, predicate, isDrop, fromRight) {
+              var length = array.length,
+                index = fromRight ? length : -1;
+
+              while ((fromRight ? index-- : ++index < length) && predicate(array[index], index, array)) {}
+
+              return isDrop
+                ? baseSlice(array, fromRight ? 0 : index, fromRight ? index + 1 : length)
+                : baseSlice(array, fromRight ? index + 1 : 0, fromRight ? length : index);
+            }
+
+            /**
+             * The base implementation of `wrapperValue` which returns the result of
+             * performing a sequence of actions on the unwrapped `value`, where each
+             * successive action is supplied the return value of the previous.
+             *
+             * @private
+             * @param {*} value The unwrapped value.
+             * @param {Array} actions Actions to perform to resolve the unwrapped value.
+             * @returns {*} Returns the resolved value.
+             */
+            function baseWrapperValue(value, actions) {
+              var result = value;
+              if (result instanceof LazyWrapper) {
+                result = result.value();
+              }
+              return arrayReduce(
+                actions,
+                function (result, action) {
+                  return action.func.apply(action.thisArg, arrayPush([result], action.args));
+                },
+                result
+              );
+            }
+
+            /**
+             * The base implementation of methods like `_.xor`, without support for
+             * iteratee shorthands, that accepts an array of arrays to inspect.
+             *
+             * @private
+             * @param {Array} arrays The arrays to inspect.
+             * @param {Function} [iteratee] The iteratee invoked per element.
+             * @param {Function} [comparator] The comparator invoked per element.
+             * @returns {Array} Returns the new array of values.
+             */
+            function baseXor(arrays, iteratee, comparator) {
+              var length = arrays.length;
+              if (length < 2) {
+                return length ? baseUniq(arrays[0]) : [];
+              }
+              var index = -1,
+                result = Array(length);
+
+              while (++index < length) {
+                var array = arrays[index],
+                  othIndex = -1;
+
+                while (++othIndex < length) {
+                  if (othIndex != index) {
+                    result[index] = baseDifference(
+                      result[index] || array,
+                      arrays[othIndex],
+                      iteratee,
+                      comparator
+                    );
+                  }
+                }
+              }
+              return baseUniq(baseFlatten(result, 1), iteratee, comparator);
+            }
+
+            /**
+             * This base implementation of `_.zipObject` which assigns values using `assignFunc`.
+             *
+             * @private
+             * @param {Array} props The property identifiers.
+             * @param {Array} values The property values.
+             * @param {Function} assignFunc The function to assign values.
+             * @returns {Object} Returns the new object.
+             */
+            function baseZipObject(props, values, assignFunc) {
+              var index = -1,
+                length = props.length,
+                valsLength = values.length,
+                result = {};
+
+              while (++index < length) {
+                var value = index < valsLength ? values[index] : undefined;
+                assignFunc(result, props[index], value);
+              }
+              return result;
+            }
+
+            /**
+             * Casts `value` to an empty array if it's not an array like object.
+             *
+             * @private
+             * @param {*} value The value to inspect.
+             * @returns {Array|Object} Returns the cast array-like object.
+             */
+            function castArrayLikeObject(value) {
+              return isArrayLikeObject(value) ? value : [];
+            }
+
+            /**
+             * Casts `value` to `identity` if it's not a function.
+             *
+             * @private
+             * @param {*} value The value to inspect.
+             * @returns {Function} Returns cast function.
+             */
+            function castFunction(value) {
+              return typeof value == 'function' ? value : identity;
+            }
+
+            /**
+             * Casts `value` to a path array if it's not one.
+             *
+             * @private
+             * @param {*} value The value to inspect.
+             * @param {Object} [object] The object to query keys on.
+             * @returns {Array} Returns the cast property path array.
+             */
+            function castPath(value, object) {
+              if (isArray(value)) {
+                return value;
+              }
+              return isKey(value, object) ? [value] : stringToPath(toString(value));
+            }
+
+            /**
+             * A `baseRest` alias which can be replaced with `identity` by module
+             * replacement plugins.
+             *
+             * @private
+             * @type {Function}
+             * @param {Function} func The function to apply a rest parameter to.
+             * @returns {Function} Returns the new function.
+             */
+            var castRest = baseRest;
+
+            /**
+             * Casts `array` to a slice if it's needed.
+             *
+             * @private
+             * @param {Array} array The array to inspect.
+             * @param {number} start The start position.
+             * @param {number} [end=array.length] The end position.
+             * @returns {Array} Returns the cast slice.
+             */
+            function castSlice(array, start, end) {
+              var length = array.length;
+              end = end === undefined ? length : end;
+              return !start && end >= length ? array : baseSlice(array, start, end);
+            }
+
+            /**
+             * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout).
+             *
+             * @private
+             * @param {number|Object} id The timer id or timeout object of the timer to clear.
+             */
+            var clearTimeout =
+              ctxClearTimeout ||
+              function (id) {
+                return root.clearTimeout(id);
+              };
+
+            /**
+             * Creates a clone of  `buffer`.
+             *
+             * @private
+             * @param {Buffer} buffer The buffer to clone.
+             * @param {boolean} [isDeep] Specify a deep clone.
+             * @returns {Buffer} Returns the cloned buffer.
+             */
+            function cloneBuffer(buffer, isDeep) {
+              if (isDeep) {
+                return buffer.slice();
+              }
+              var length = buffer.length,
+                result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length);
+
+              buffer.copy(result);
+              return result;
+            }
+
+            /**
+             * Creates a clone of `arrayBuffer`.
+             *
+             * @private
+             * @param {ArrayBuffer} arrayBuffer The array buffer to clone.
+             * @returns {ArrayBuffer} Returns the cloned array buffer.
+             */
+            function cloneArrayBuffer(arrayBuffer) {
+              var result = new arrayBuffer.constructor(arrayBuffer.byteLength);
+              new Uint8Array(result).set(new Uint8Array(arrayBuffer));
+              return result;
+            }
+
+            /**
+             * Creates a clone of `dataView`.
+             *
+             * @private
+             * @param {Object} dataView The data view to clone.
+             * @param {boolean} [isDeep] Specify a deep clone.
+             * @returns {Object} Returns the cloned data view.
+             */
+            function cloneDataView(dataView, isDeep) {
+              var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;
+              return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);
+            }
+
+            /**
+             * Creates a clone of `regexp`.
+             *
+             * @private
+             * @param {Object} regexp The regexp to clone.
+             * @returns {Object} Returns the cloned regexp.
+             */
+            function cloneRegExp(regexp) {
+              var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));
+              result.lastIndex = regexp.lastIndex;
+              return result;
+            }
+
+            /**
+             * Creates a clone of the `symbol` object.
+             *
+             * @private
+             * @param {Object} symbol The symbol object to clone.
+             * @returns {Object} Returns the cloned symbol object.
+             */
+            function cloneSymbol(symbol) {
+              return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};
+            }
+
+            /**
+             * Creates a clone of `typedArray`.
+             *
+             * @private
+             * @param {Object} typedArray The typed array to clone.
+             * @param {boolean} [isDeep] Specify a deep clone.
+             * @returns {Object} Returns the cloned typed array.
+             */
+            function cloneTypedArray(typedArray, isDeep) {
+              var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;
+              return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
+            }
+
+            /**
+             * Compares values to sort them in ascending order.
+             *
+             * @private
+             * @param {*} value The value to compare.
+             * @param {*} other The other value to compare.
+             * @returns {number} Returns the sort order indicator for `value`.
+             */
+            function compareAscending(value, other) {
+              if (value !== other) {
+                var valIsDefined = value !== undefined,
+                  valIsNull = value === null,
+                  valIsReflexive = value === value,
+                  valIsSymbol = isSymbol(value);
+
+                var othIsDefined = other !== undefined,
+                  othIsNull = other === null,
+                  othIsReflexive = other === other,
+                  othIsSymbol = isSymbol(other);
+
+                if (
+                  (!othIsNull && !othIsSymbol && !valIsSymbol && value > other) ||
+                  (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) ||
+                  (valIsNull && othIsDefined && othIsReflexive) ||
+                  (!valIsDefined && othIsReflexive) ||
+                  !valIsReflexive
+                ) {
+                  return 1;
+                }
+                if (
+                  (!valIsNull && !valIsSymbol && !othIsSymbol && value < other) ||
+                  (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) ||
+                  (othIsNull && valIsDefined && valIsReflexive) ||
+                  (!othIsDefined && valIsReflexive) ||
+                  !othIsReflexive
+                ) {
+                  return -1;
+                }
+              }
+              return 0;
+            }
+
+            /**
+             * Used by `_.orderBy` to compare multiple properties of a value to another
+             * and stable sort them.
+             *
+             * If `orders` is unspecified, all values are sorted in ascending order. Otherwise,
+             * specify an order of "desc" for descending or "asc" for ascending sort order
+             * of corresponding values.
+             *
+             * @private
+             * @param {Object} object The object to compare.
+             * @param {Object} other The other object to compare.
+             * @param {boolean[]|string[]} orders The order to sort by for each property.
+             * @returns {number} Returns the sort order indicator for `object`.
+             */
+            function compareMultiple(object, other, orders) {
+              var index = -1,
+                objCriteria = object.criteria,
+                othCriteria = other.criteria,
+                length = objCriteria.length,
+                ordersLength = orders.length;
+
+              while (++index < length) {
+                var result = compareAscending(objCriteria[index], othCriteria[index]);
+                if (result) {
+                  if (index >= ordersLength) {
+                    return result;
+                  }
+                  var order = orders[index];
+                  return result * (order == 'desc' ? -1 : 1);
+                }
+              }
+              // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
+              // that causes it, under certain circumstances, to provide the same value for
+              // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247
+              // for more details.
+              //
+              // This also ensures a stable sort in V8 and other engines.
+              // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details.
+              return object.index - other.index;
+            }
+
+            /**
+             * Creates an array that is the composition of partially applied arguments,
+             * placeholders, and provided arguments into a single array of arguments.
+             *
+             * @private
+             * @param {Array} args The provided arguments.
+             * @param {Array} partials The arguments to prepend to those provided.
+             * @param {Array} holders The `partials` placeholder indexes.
+             * @params {boolean} [isCurried] Specify composing for a curried function.
+             * @returns {Array} Returns the new array of composed arguments.
+             */
+            function composeArgs(args, partials, holders, isCurried) {
+              var argsIndex = -1,
+                argsLength = args.length,
+                holdersLength = holders.length,
+                leftIndex = -1,
+                leftLength = partials.length,
+                rangeLength = nativeMax(argsLength - holdersLength, 0),
+                result = Array(leftLength + rangeLength),
+                isUncurried = !isCurried;
+
+              while (++leftIndex < leftLength) {
+                result[leftIndex] = partials[leftIndex];
+              }
+              while (++argsIndex < holdersLength) {
+                if (isUncurried || argsIndex < argsLength) {
+                  result[holders[argsIndex]] = args[argsIndex];
+                }
+              }
+              while (rangeLength--) {
+                result[leftIndex++] = args[argsIndex++];
+              }
+              return result;
+            }
+
+            /**
+             * This function is like `composeArgs` except that the arguments composition
+             * is tailored for `_.partialRight`.
+             *
+             * @private
+             * @param {Array} args The provided arguments.
+             * @param {Array} partials The arguments to append to those provided.
+             * @param {Array} holders The `partials` placeholder indexes.
+             * @params {boolean} [isCurried] Specify composing for a curried function.
+             * @returns {Array} Returns the new array of composed arguments.
+             */
+            function composeArgsRight(args, partials, holders, isCurried) {
+              var argsIndex = -1,
+                argsLength = args.length,
+                holdersIndex = -1,
+                holdersLength = holders.length,
+                rightIndex = -1,
+                rightLength = partials.length,
+                rangeLength = nativeMax(argsLength - holdersLength, 0),
+                result = Array(rangeLength + rightLength),
+                isUncurried = !isCurried;
+
+              while (++argsIndex < rangeLength) {
+                result[argsIndex] = args[argsIndex];
+              }
+              var offset = argsIndex;
+              while (++rightIndex < rightLength) {
+                result[offset + rightIndex] = partials[rightIndex];
+              }
+              while (++holdersIndex < holdersLength) {
+                if (isUncurried || argsIndex < argsLength) {
+                  result[offset + holders[holdersIndex]] = args[argsIndex++];
+                }
+              }
+              return result;
+            }
+
+            /**
+             * Copies the values of `source` to `array`.
+             *
+             * @private
+             * @param {Array} source The array to copy values from.
+             * @param {Array} [array=[]] The array to copy values to.
+             * @returns {Array} Returns `array`.
+             */
+            function copyArray(source, array) {
+              var index = -1,
+                length = source.length;
+
+              array || (array = Array(length));
+              while (++index < length) {
+                array[index] = source[index];
+              }
+              return array;
+            }
+
+            /**
+             * Copies properties of `source` to `object`.
+             *
+             * @private
+             * @param {Object} source The object to copy properties from.
+             * @param {Array} props The property identifiers to copy.
+             * @param {Object} [object={}] The object to copy properties to.
+             * @param {Function} [customizer] The function to customize copied values.
+             * @returns {Object} Returns `object`.
+             */
+            function copyObject(source, props, object, customizer) {
+              var isNew = !object;
+              object || (object = {});
+
+              var index = -1,
+                length = props.length;
+
+              while (++index < length) {
+                var key = props[index];
+
+                var newValue = customizer
+                  ? customizer(object[key], source[key], key, object, source)
+                  : undefined;
+
+                if (newValue === undefined) {
+                  newValue = source[key];
+                }
+                if (isNew) {
+                  baseAssignValue(object, key, newValue);
+                } else {
+                  assignValue(object, key, newValue);
+                }
+              }
+              return object;
+            }
+
+            /**
+             * Copies own symbols of `source` to `object`.
+             *
+             * @private
+             * @param {Object} source The object to copy symbols from.
+             * @param {Object} [object={}] The object to copy symbols to.
+             * @returns {Object} Returns `object`.
+             */
+            function copySymbols(source, object) {
+              return copyObject(source, getSymbols(source), object);
+            }
+
+            /**
+             * Copies own and inherited symbols of `source` to `object`.
+             *
+             * @private
+             * @param {Object} source The object to copy symbols from.
+             * @param {Object} [object={}] The object to copy symbols to.
+             * @returns {Object} Returns `object`.
+             */
+            function copySymbolsIn(source, object) {
+              return copyObject(source, getSymbolsIn(source), object);
+            }
+
+            /**
+             * Creates a function like `_.groupBy`.
+             *
+             * @private
+             * @param {Function} setter The function to set accumulator values.
+             * @param {Function} [initializer] The accumulator object initializer.
+             * @returns {Function} Returns the new aggregator function.
+             */
+            function createAggregator(setter, initializer) {
+              return function (collection, iteratee) {
+                var func = isArray(collection) ? arrayAggregator : baseAggregator,
+                  accumulator = initializer ? initializer() : {};
+
+                return func(collection, setter, getIteratee(iteratee, 2), accumulator);
+              };
+            }
+
+            /**
+             * Creates a function like `_.assign`.
+             *
+             * @private
+             * @param {Function} assigner The function to assign values.
+             * @returns {Function} Returns the new assigner function.
+             */
+            function createAssigner(assigner) {
+              return baseRest(function (object, sources) {
+                var index = -1,
+                  length = sources.length,
+                  customizer = length > 1 ? sources[length - 1] : undefined,
+                  guard = length > 2 ? sources[2] : undefined;
+
+                customizer =
+                  assigner.length > 3 && typeof customizer == 'function' ? (length--, customizer) : undefined;
+
+                if (guard && isIterateeCall(sources[0], sources[1], guard)) {
+                  customizer = length < 3 ? undefined : customizer;
+                  length = 1;
+                }
+                object = Object(object);
+                while (++index < length) {
+                  var source = sources[index];
+                  if (source) {
+                    assigner(object, source, index, customizer);
+                  }
+                }
+                return object;
+              });
+            }
+
+            /**
+             * Creates a `baseEach` or `baseEachRight` function.
+             *
+             * @private
+             * @param {Function} eachFunc The function to iterate over a collection.
+             * @param {boolean} [fromRight] Specify iterating from right to left.
+             * @returns {Function} Returns the new base function.
+             */
+            function createBaseEach(eachFunc, fromRight) {
+              return function (collection, iteratee) {
+                if (collection == null) {
+                  return collection;
+                }
+                if (!isArrayLike(collection)) {
+                  return eachFunc(collection, iteratee);
+                }
+                var length = collection.length,
+                  index = fromRight ? length : -1,
+                  iterable = Object(collection);
+
+                while (fromRight ? index-- : ++index < length) {
+                  if (iteratee(iterable[index], index, iterable) === false) {
+                    break;
+                  }
+                }
+                return collection;
+              };
+            }
+
+            /**
+             * Creates a base function for methods like `_.forIn` and `_.forOwn`.
+             *
+             * @private
+             * @param {boolean} [fromRight] Specify iterating from right to left.
+             * @returns {Function} Returns the new base function.
+             */
+            function createBaseFor(fromRight) {
+              return function (object, iteratee, keysFunc) {
+                var index = -1,
+                  iterable = Object(object),
+                  props = keysFunc(object),
+                  length = props.length;
+
+                while (length--) {
+                  var key = props[fromRight ? length : ++index];
+                  if (iteratee(iterable[key], key, iterable) === false) {
+                    break;
+                  }
+                }
+                return object;
+              };
+            }
+
+            /**
+             * Creates a function that wraps `func` to invoke it with the optional `this`
+             * binding of `thisArg`.
+             *
+             * @private
+             * @param {Function} func The function to wrap.
+             * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+             * @param {*} [thisArg] The `this` binding of `func`.
+             * @returns {Function} Returns the new wrapped function.
+             */
+            function createBind(func, bitmask, thisArg) {
+              var isBind = bitmask & WRAP_BIND_FLAG,
+                Ctor = createCtor(func);
+
+              function wrapper() {
+                var fn = this && this !== root && this instanceof wrapper ? Ctor : func;
+                return fn.apply(isBind ? thisArg : this, arguments);
+              }
+              return wrapper;
+            }
+
+            /**
+             * Creates a function like `_.lowerFirst`.
+             *
+             * @private
+             * @param {string} methodName The name of the `String` case method to use.
+             * @returns {Function} Returns the new case function.
+             */
+            function createCaseFirst(methodName) {
+              return function (string) {
+                string = toString(string);
+
+                var strSymbols = hasUnicode(string) ? stringToArray(string) : undefined;
+
+                var chr = strSymbols ? strSymbols[0] : string.charAt(0);
+
+                var trailing = strSymbols ? castSlice(strSymbols, 1).join('') : string.slice(1);
+
+                return chr[methodName]() + trailing;
+              };
+            }
+
+            /**
+             * Creates a function like `_.camelCase`.
+             *
+             * @private
+             * @param {Function} callback The function to combine each word.
+             * @returns {Function} Returns the new compounder function.
+             */
+            function createCompounder(callback) {
+              return function (string) {
+                return arrayReduce(words(deburr(string).replace(reApos, '')), callback, '');
+              };
+            }
+
+            /**
+             * Creates a function that produces an instance of `Ctor` regardless of
+             * whether it was invoked as part of a `new` expression or by `call` or `apply`.
+             *
+             * @private
+             * @param {Function} Ctor The constructor to wrap.
+             * @returns {Function} Returns the new wrapped function.
+             */
+            function createCtor(Ctor) {
+              return function () {
+                // Use a `switch` statement to work with class constructors. See
+                // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
+                // for more details.
+                var args = arguments;
+                switch (args.length) {
+                  case 0:
+                    return new Ctor();
+                  case 1:
+                    return new Ctor(args[0]);
+                  case 2:
+                    return new Ctor(args[0], args[1]);
+                  case 3:
+                    return new Ctor(args[0], args[1], args[2]);
+                  case 4:
+                    return new Ctor(args[0], args[1], args[2], args[3]);
+                  case 5:
+                    return new Ctor(args[0], args[1], args[2], args[3], args[4]);
+                  case 6:
+                    return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]);
+                  case 7:
+                    return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
+                }
+                var thisBinding = baseCreate(Ctor.prototype),
+                  result = Ctor.apply(thisBinding, args);
+
+                // Mimic the constructor's `return` behavior.
+                // See https://es5.github.io/#x13.2.2 for more details.
+                return isObject(result) ? result : thisBinding;
+              };
+            }
+
+            /**
+             * Creates a function that wraps `func` to enable currying.
+             *
+             * @private
+             * @param {Function} func The function to wrap.
+             * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+             * @param {number} arity The arity of `func`.
+             * @returns {Function} Returns the new wrapped function.
+             */
+            function createCurry(func, bitmask, arity) {
+              var Ctor = createCtor(func);
+
+              function wrapper() {
+                var length = arguments.length,
+                  args = Array(length),
+                  index = length,
+                  placeholder = getHolder(wrapper);
+
+                while (index--) {
+                  args[index] = arguments[index];
+                }
+                var holders =
+                  length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder
+                    ? []
+                    : replaceHolders(args, placeholder);
+
+                length -= holders.length;
+                if (length < arity) {
+                  return createRecurry(
+                    func,
+                    bitmask,
+                    createHybrid,
+                    wrapper.placeholder,
+                    undefined,
+                    args,
+                    holders,
+                    undefined,
+                    undefined,
+                    arity - length
+                  );
+                }
+                var fn = this && this !== root && this instanceof wrapper ? Ctor : func;
+                return apply(fn, this, args);
+              }
+              return wrapper;
+            }
+
+            /**
+             * Creates a `_.find` or `_.findLast` function.
+             *
+             * @private
+             * @param {Function} findIndexFunc The function to find the collection index.
+             * @returns {Function} Returns the new find function.
+             */
+            function createFind(findIndexFunc) {
+              return function (collection, predicate, fromIndex) {
+                var iterable = Object(collection);
+                if (!isArrayLike(collection)) {
+                  var iteratee = getIteratee(predicate, 3);
+                  collection = keys(collection);
+                  predicate = function (key) {
+                    return iteratee(iterable[key], key, iterable);
+                  };
+                }
+                var index = findIndexFunc(collection, predicate, fromIndex);
+                return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined;
+              };
+            }
+
+            /**
+             * Creates a `_.flow` or `_.flowRight` function.
+             *
+             * @private
+             * @param {boolean} [fromRight] Specify iterating from right to left.
+             * @returns {Function} Returns the new flow function.
+             */
+            function createFlow(fromRight) {
+              return flatRest(function (funcs) {
+                var length = funcs.length,
+                  index = length,
+                  prereq = LodashWrapper.prototype.thru;
+
+                if (fromRight) {
+                  funcs.reverse();
+                }
+                while (index--) {
+                  var func = funcs[index];
+                  if (typeof func != 'function') {
+                    throw new TypeError(FUNC_ERROR_TEXT);
+                  }
+                  if (prereq && !wrapper && getFuncName(func) == 'wrapper') {
+                    var wrapper = new LodashWrapper([], true);
+                  }
+                }
+                index = wrapper ? index : length;
+                while (++index < length) {
+                  func = funcs[index];
+
+                  var funcName = getFuncName(func),
+                    data = funcName == 'wrapper' ? getData(func) : undefined;
+
+                  if (
+                    data &&
+                    isLaziable(data[0]) &&
+                    data[1] == (WRAP_ARY_FLAG | WRAP_CURRY_FLAG | WRAP_PARTIAL_FLAG | WRAP_REARG_FLAG) &&
+                    !data[4].length &&
+                    data[9] == 1
+                  ) {
+                    wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]);
+                  } else {
+                    wrapper = func.length == 1 && isLaziable(func) ? wrapper[funcName]() : wrapper.thru(func);
+                  }
+                }
+                return function () {
+                  var args = arguments,
+                    value = args[0];
+
+                  if (wrapper && args.length == 1 && isArray(value)) {
+                    return wrapper.plant(value).value();
+                  }
+                  var index = 0,
+                    result = length ? funcs[index].apply(this, args) : value;
+
+                  while (++index < length) {
+                    result = funcs[index].call(this, result);
+                  }
+                  return result;
+                };
+              });
+            }
+
+            /**
+             * Creates a function that wraps `func` to invoke it with optional `this`
+             * binding of `thisArg`, partial application, and currying.
+             *
+             * @private
+             * @param {Function|string} func The function or method name to wrap.
+             * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+             * @param {*} [thisArg] The `this` binding of `func`.
+             * @param {Array} [partials] The arguments to prepend to those provided to
+             *  the new function.
+             * @param {Array} [holders] The `partials` placeholder indexes.
+             * @param {Array} [partialsRight] The arguments to append to those provided
+             *  to the new function.
+             * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
+             * @param {Array} [argPos] The argument positions of the new function.
+             * @param {number} [ary] The arity cap of `func`.
+             * @param {number} [arity] The arity of `func`.
+             * @returns {Function} Returns the new wrapped function.
+             */
+            function createHybrid(
+              func,
+              bitmask,
+              thisArg,
+              partials,
+              holders,
+              partialsRight,
+              holdersRight,
+              argPos,
+              ary,
+              arity
+            ) {
+              var isAry = bitmask & WRAP_ARY_FLAG,
+                isBind = bitmask & WRAP_BIND_FLAG,
+                isBindKey = bitmask & WRAP_BIND_KEY_FLAG,
+                isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG),
+                isFlip = bitmask & WRAP_FLIP_FLAG,
+                Ctor = isBindKey ? undefined : createCtor(func);
+
+              function wrapper() {
+                var length = arguments.length,
+                  args = Array(length),
+                  index = length;
+
+                while (index--) {
+                  args[index] = arguments[index];
+                }
+                if (isCurried) {
+                  var placeholder = getHolder(wrapper),
+                    holdersCount = countHolders(args, placeholder);
+                }
+                if (partials) {
+                  args = composeArgs(args, partials, holders, isCurried);
+                }
+                if (partialsRight) {
+                  args = composeArgsRight(args, partialsRight, holdersRight, isCurried);
+                }
+                length -= holdersCount;
+                if (isCurried && length < arity) {
+                  var newHolders = replaceHolders(args, placeholder);
+                  return createRecurry(
+                    func,
+                    bitmask,
+                    createHybrid,
+                    wrapper.placeholder,
+                    thisArg,
+                    args,
+                    newHolders,
+                    argPos,
+                    ary,
+                    arity - length
+                  );
+                }
+                var thisBinding = isBind ? thisArg : this,
+                  fn = isBindKey ? thisBinding[func] : func;
+
+                length = args.length;
+                if (argPos) {
+                  args = reorder(args, argPos);
+                } else if (isFlip && length > 1) {
+                  args.reverse();
+                }
+                if (isAry && ary < length) {
+                  args.length = ary;
+                }
+                if (this && this !== root && this instanceof wrapper) {
+                  fn = Ctor || createCtor(fn);
+                }
+                return fn.apply(thisBinding, args);
+              }
+              return wrapper;
+            }
+
+            /**
+             * Creates a function like `_.invertBy`.
+             *
+             * @private
+             * @param {Function} setter The function to set accumulator values.
+             * @param {Function} toIteratee The function to resolve iteratees.
+             * @returns {Function} Returns the new inverter function.
+             */
+            function createInverter(setter, toIteratee) {
+              return function (object, iteratee) {
+                return baseInverter(object, setter, toIteratee(iteratee), {});
+              };
+            }
+
+            /**
+             * Creates a function that performs a mathematical operation on two values.
+             *
+             * @private
+             * @param {Function} operator The function to perform the operation.
+             * @param {number} [defaultValue] The value used for `undefined` arguments.
+             * @returns {Function} Returns the new mathematical operation function.
+             */
+            function createMathOperation(operator, defaultValue) {
+              return function (value, other) {
+                var result;
+                if (value === undefined && other === undefined) {
+                  return defaultValue;
+                }
+                if (value !== undefined) {
+                  result = value;
+                }
+                if (other !== undefined) {
+                  if (result === undefined) {
+                    return other;
+                  }
+                  if (typeof value == 'string' || typeof other == 'string') {
+                    value = baseToString(value);
+                    other = baseToString(other);
+                  } else {
+                    value = baseToNumber(value);
+                    other = baseToNumber(other);
+                  }
+                  result = operator(value, other);
+                }
+                return result;
+              };
+            }
+
+            /**
+             * Creates a function like `_.over`.
+             *
+             * @private
+             * @param {Function} arrayFunc The function to iterate over iteratees.
+             * @returns {Function} Returns the new over function.
+             */
+            function createOver(arrayFunc) {
+              return flatRest(function (iteratees) {
+                iteratees = arrayMap(iteratees, baseUnary(getIteratee()));
+                return baseRest(function (args) {
+                  var thisArg = this;
+                  return arrayFunc(iteratees, function (iteratee) {
+                    return apply(iteratee, thisArg, args);
+                  });
+                });
+              });
+            }
+
+            /**
+             * Creates the padding for `string` based on `length`. The `chars` string
+             * is truncated if the number of characters exceeds `length`.
+             *
+             * @private
+             * @param {number} length The padding length.
+             * @param {string} [chars=' '] The string used as padding.
+             * @returns {string} Returns the padding for `string`.
+             */
+            function createPadding(length, chars) {
+              chars = chars === undefined ? ' ' : baseToString(chars);
+
+              var charsLength = chars.length;
+              if (charsLength < 2) {
+                return charsLength ? baseRepeat(chars, length) : chars;
+              }
+              var result = baseRepeat(chars, nativeCeil(length / stringSize(chars)));
+              return hasUnicode(chars)
+                ? castSlice(stringToArray(result), 0, length).join('')
+                : result.slice(0, length);
+            }
+
+            /**
+             * Creates a function that wraps `func` to invoke it with the `this` binding
+             * of `thisArg` and `partials` prepended to the arguments it receives.
+             *
+             * @private
+             * @param {Function} func The function to wrap.
+             * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+             * @param {*} thisArg The `this` binding of `func`.
+             * @param {Array} partials The arguments to prepend to those provided to
+             *  the new function.
+             * @returns {Function} Returns the new wrapped function.
+             */
+            function createPartial(func, bitmask, thisArg, partials) {
+              var isBind = bitmask & WRAP_BIND_FLAG,
+                Ctor = createCtor(func);
+
+              function wrapper() {
+                var argsIndex = -1,
+                  argsLength = arguments.length,
+                  leftIndex = -1,
+                  leftLength = partials.length,
+                  args = Array(leftLength + argsLength),
+                  fn = this && this !== root && this instanceof wrapper ? Ctor : func;
+
+                while (++leftIndex < leftLength) {
+                  args[leftIndex] = partials[leftIndex];
+                }
+                while (argsLength--) {
+                  args[leftIndex++] = arguments[++argsIndex];
+                }
+                return apply(fn, isBind ? thisArg : this, args);
+              }
+              return wrapper;
+            }
+
+            /**
+             * Creates a `_.range` or `_.rangeRight` function.
+             *
+             * @private
+             * @param {boolean} [fromRight] Specify iterating from right to left.
+             * @returns {Function} Returns the new range function.
+             */
+            function createRange(fromRight) {
+              return function (start, end, step) {
+                if (step && typeof step != 'number' && isIterateeCall(start, end, step)) {
+                  end = step = undefined;
+                }
+                // Ensure the sign of `-0` is preserved.
+                start = toFinite(start);
+                if (end === undefined) {
+                  end = start;
+                  start = 0;
+                } else {
+                  end = toFinite(end);
+                }
+                step = step === undefined ? (start < end ? 1 : -1) : toFinite(step);
+                return baseRange(start, end, step, fromRight);
+              };
+            }
+
+            /**
+             * Creates a function that performs a relational operation on two values.
+             *
+             * @private
+             * @param {Function} operator The function to perform the operation.
+             * @returns {Function} Returns the new relational operation function.
+             */
+            function createRelationalOperation(operator) {
+              return function (value, other) {
+                if (!(typeof value == 'string' && typeof other == 'string')) {
+                  value = toNumber(value);
+                  other = toNumber(other);
+                }
+                return operator(value, other);
+              };
+            }
+
+            /**
+             * Creates a function that wraps `func` to continue currying.
+             *
+             * @private
+             * @param {Function} func The function to wrap.
+             * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+             * @param {Function} wrapFunc The function to create the `func` wrapper.
+             * @param {*} placeholder The placeholder value.
+             * @param {*} [thisArg] The `this` binding of `func`.
+             * @param {Array} [partials] The arguments to prepend to those provided to
+             *  the new function.
+             * @param {Array} [holders] The `partials` placeholder indexes.
+             * @param {Array} [argPos] The argument positions of the new function.
+             * @param {number} [ary] The arity cap of `func`.
+             * @param {number} [arity] The arity of `func`.
+             * @returns {Function} Returns the new wrapped function.
+             */
+            function createRecurry(
+              func,
+              bitmask,
+              wrapFunc,
+              placeholder,
+              thisArg,
+              partials,
+              holders,
+              argPos,
+              ary,
+              arity
+            ) {
+              var isCurry = bitmask & WRAP_CURRY_FLAG,
+                newHolders = isCurry ? holders : undefined,
+                newHoldersRight = isCurry ? undefined : holders,
+                newPartials = isCurry ? partials : undefined,
+                newPartialsRight = isCurry ? undefined : partials;
+
+              bitmask |= isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG;
+              bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG);
+
+              if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) {
+                bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG);
+              }
+              var newData = [
+                func,
+                bitmask,
+                thisArg,
+                newPartials,
+                newHolders,
+                newPartialsRight,
+                newHoldersRight,
+                argPos,
+                ary,
+                arity,
+              ];
+
+              var result = wrapFunc.apply(undefined, newData);
+              if (isLaziable(func)) {
+                setData(result, newData);
+              }
+              result.placeholder = placeholder;
+              return setWrapToString(result, func, bitmask);
+            }
+
+            /**
+             * Creates a function like `_.round`.
+             *
+             * @private
+             * @param {string} methodName The name of the `Math` method to use when rounding.
+             * @returns {Function} Returns the new round function.
+             */
+            function createRound(methodName) {
+              var func = Math[methodName];
+              return function (number, precision) {
+                number = toNumber(number);
+                precision = precision == null ? 0 : nativeMin(toInteger(precision), 292);
+                if (precision) {
+                  // Shift with exponential notation to avoid floating-point issues.
+                  // See [MDN](https://mdn.io/round#Examples) for more details.
+                  var pair = (toString(number) + 'e').split('e'),
+                    value = func(pair[0] + 'e' + (+pair[1] + precision));
+
+                  pair = (toString(value) + 'e').split('e');
+                  return +(pair[0] + 'e' + (+pair[1] - precision));
+                }
+                return func(number);
+              };
+            }
+
+            /**
+             * Creates a set object of `values`.
+             *
+             * @private
+             * @param {Array} values The values to add to the set.
+             * @returns {Object} Returns the new set.
+             */
+            var createSet = !(Set && 1 / setToArray(new Set([, -0]))[1] == INFINITY)
+              ? noop
+              : function (values) {
+                  return new Set(values);
+                };
+
+            /**
+             * Creates a `_.toPairs` or `_.toPairsIn` function.
+             *
+             * @private
+             * @param {Function} keysFunc The function to get the keys of a given object.
+             * @returns {Function} Returns the new pairs function.
+             */
+            function createToPairs(keysFunc) {
+              return function (object) {
+                var tag = getTag(object);
+                if (tag == mapTag) {
+                  return mapToArray(object);
+                }
+                if (tag == setTag) {
+                  return setToPairs(object);
+                }
+                return baseToPairs(object, keysFunc(object));
+              };
+            }
+
+            /**
+             * Creates a function that either curries or invokes `func` with optional
+             * `this` binding and partially applied arguments.
+             *
+             * @private
+             * @param {Function|string} func The function or method name to wrap.
+             * @param {number} bitmask The bitmask flags.
+             *    1 - `_.bind`
+             *    2 - `_.bindKey`
+             *    4 - `_.curry` or `_.curryRight` of a bound function
+             *    8 - `_.curry`
+             *   16 - `_.curryRight`
+             *   32 - `_.partial`
+             *   64 - `_.partialRight`
+             *  128 - `_.rearg`
+             *  256 - `_.ary`
+             *  512 - `_.flip`
+             * @param {*} [thisArg] The `this` binding of `func`.
+             * @param {Array} [partials] The arguments to be partially applied.
+             * @param {Array} [holders] The `partials` placeholder indexes.
+             * @param {Array} [argPos] The argument positions of the new function.
+             * @param {number} [ary] The arity cap of `func`.
+             * @param {number} [arity] The arity of `func`.
+             * @returns {Function} Returns the new wrapped function.
+             */
+            function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
+              var isBindKey = bitmask & WRAP_BIND_KEY_FLAG;
+              if (!isBindKey && typeof func != 'function') {
+                throw new TypeError(FUNC_ERROR_TEXT);
+              }
+              var length = partials ? partials.length : 0;
+              if (!length) {
+                bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG);
+                partials = holders = undefined;
+              }
+              ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0);
+              arity = arity === undefined ? arity : toInteger(arity);
+              length -= holders ? holders.length : 0;
+
+              if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) {
+                var partialsRight = partials,
+                  holdersRight = holders;
+
+                partials = holders = undefined;
+              }
+              var data = isBindKey ? undefined : getData(func);
+
+              var newData = [
+                func,
+                bitmask,
+                thisArg,
+                partials,
+                holders,
+                partialsRight,
+                holdersRight,
+                argPos,
+                ary,
+                arity,
+              ];
+
+              if (data) {
+                mergeData(newData, data);
+              }
+              func = newData[0];
+              bitmask = newData[1];
+              thisArg = newData[2];
+              partials = newData[3];
+              holders = newData[4];
+              arity = newData[9] =
+                newData[9] === undefined ? (isBindKey ? 0 : func.length) : nativeMax(newData[9] - length, 0);
+
+              if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) {
+                bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG);
+              }
+              if (!bitmask || bitmask == WRAP_BIND_FLAG) {
+                var result = createBind(func, bitmask, thisArg);
+              } else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) {
+                result = createCurry(func, bitmask, arity);
+              } else if (
+                (bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) &&
+                !holders.length
+              ) {
+                result = createPartial(func, bitmask, thisArg, partials);
+              } else {
+                result = createHybrid.apply(undefined, newData);
+              }
+              var setter = data ? baseSetData : setData;
+              return setWrapToString(setter(result, newData), func, bitmask);
+            }
+
+            /**
+             * Used by `_.defaults` to customize its `_.assignIn` use to assign properties
+             * of source objects to the destination object for all destination properties
+             * that resolve to `undefined`.
+             *
+             * @private
+             * @param {*} objValue The destination value.
+             * @param {*} srcValue The source value.
+             * @param {string} key The key of the property to assign.
+             * @param {Object} object The parent object of `objValue`.
+             * @returns {*} Returns the value to assign.
+             */
+            function customDefaultsAssignIn(objValue, srcValue, key, object) {
+              if (
+                objValue === undefined ||
+                (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))
+              ) {
+                return srcValue;
+              }
+              return objValue;
+            }
+
+            /**
+             * Used by `_.defaultsDeep` to customize its `_.merge` use to merge source
+             * objects into destination objects that are passed thru.
+             *
+             * @private
+             * @param {*} objValue The destination value.
+             * @param {*} srcValue The source value.
+             * @param {string} key The key of the property to merge.
+             * @param {Object} object The parent object of `objValue`.
+             * @param {Object} source The parent object of `srcValue`.
+             * @param {Object} [stack] Tracks traversed source values and their merged
+             *  counterparts.
+             * @returns {*} Returns the value to assign.
+             */
+            function customDefaultsMerge(objValue, srcValue, key, object, source, stack) {
+              if (isObject(objValue) && isObject(srcValue)) {
+                // Recursively merge objects and arrays (susceptible to call stack limits).
+                stack.set(srcValue, objValue);
+                baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack);
+                stack['delete'](srcValue);
+              }
+              return objValue;
+            }
+
+            /**
+             * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain
+             * objects.
+             *
+             * @private
+             * @param {*} value The value to inspect.
+             * @param {string} key The key of the property to inspect.
+             * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`.
+             */
+            function customOmitClone(value) {
+              return isPlainObject(value) ? undefined : value;
+            }
+
+            /**
+             * A specialized version of `baseIsEqualDeep` for arrays with support for
+             * partial deep comparisons.
+             *
+             * @private
+             * @param {Array} array The array to compare.
+             * @param {Array} other The other array to compare.
+             * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
+             * @param {Function} customizer The function to customize comparisons.
+             * @param {Function} equalFunc The function to determine equivalents of values.
+             * @param {Object} stack Tracks traversed `array` and `other` objects.
+             * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
+             */
+            function equalArrays(array, other, bitmask, customizer, equalFunc, stack) {
+              var isPartial = bitmask & COMPARE_PARTIAL_FLAG,
+                arrLength = array.length,
+                othLength = other.length;
+
+              if (arrLength != othLength && !(isPartial && othLength > arrLength)) {
+                return false;
+              }
+              // Assume cyclic values are equal.
+              var stacked = stack.get(array);
+              if (stacked && stack.get(other)) {
+                return stacked == other;
+              }
+              var index = -1,
+                result = true,
+                seen = bitmask & COMPARE_UNORDERED_FLAG ? new SetCache() : undefined;
+
+              stack.set(array, other);
+              stack.set(other, array);
+
+              // Ignore non-index properties.
+              while (++index < arrLength) {
+                var arrValue = array[index],
+                  othValue = other[index];
+
+                if (customizer) {
+                  var compared = isPartial
+                    ? customizer(othValue, arrValue, index, other, array, stack)
+                    : customizer(arrValue, othValue, index, array, other, stack);
+                }
+                if (compared !== undefined) {
+                  if (compared) {
+                    continue;
+                  }
+                  result = false;
+                  break;
+                }
+                // Recursively compare arrays (susceptible to call stack limits).
+                if (seen) {
+                  if (
+                    !arraySome(other, function (othValue, othIndex) {
+                      if (
+                        !cacheHas(seen, othIndex) &&
+                        (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))
+                      ) {
+                        return seen.push(othIndex);
+                      }
+                    })
+                  ) {
+                    result = false;
+                    break;
+                  }
+                } else if (
+                  !(arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))
+                ) {
+                  result = false;
+                  break;
+                }
+              }
+              stack['delete'](array);
+              stack['delete'](other);
+              return result;
+            }
+
+            /**
+             * A specialized version of `baseIsEqualDeep` for comparing objects of
+             * the same `toStringTag`.
+             *
+             * **Note:** This function only supports comparing values with tags of
+             * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
+             *
+             * @private
+             * @param {Object} object The object to compare.
+             * @param {Object} other The other object to compare.
+             * @param {string} tag The `toStringTag` of the objects to compare.
+             * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
+             * @param {Function} customizer The function to customize comparisons.
+             * @param {Function} equalFunc The function to determine equivalents of values.
+             * @param {Object} stack Tracks traversed `object` and `other` objects.
+             * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+             */
+            function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) {
+              switch (tag) {
+                case dataViewTag:
+                  if (object.byteLength != other.byteLength || object.byteOffset != other.byteOffset) {
+                    return false;
+                  }
+                  object = object.buffer;
+                  other = other.buffer;
+
+                case arrayBufferTag:
+                  if (
+                    object.byteLength != other.byteLength ||
+                    !equalFunc(new Uint8Array(object), new Uint8Array(other))
+                  ) {
+                    return false;
+                  }
+                  return true;
+
+                case boolTag:
+                case dateTag:
+                case numberTag:
+                  // Coerce booleans to `1` or `0` and dates to milliseconds.
+                  // Invalid dates are coerced to `NaN`.
+                  return eq(+object, +other);
+
+                case errorTag:
+                  return object.name == other.name && object.message == other.message;
+
+                case regexpTag:
+                case stringTag:
+                  // Coerce regexes to strings and treat strings, primitives and objects,
+                  // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring
+                  // for more details.
+                  return object == other + '';
+
+                case mapTag:
+                  var convert = mapToArray;
+
+                case setTag:
+                  var isPartial = bitmask & COMPARE_PARTIAL_FLAG;
+                  convert || (convert = setToArray);
+
+                  if (object.size != other.size && !isPartial) {
+                    return false;
+                  }
+                  // Assume cyclic values are equal.
+                  var stacked = stack.get(object);
+                  if (stacked) {
+                    return stacked == other;
+                  }
+                  bitmask |= COMPARE_UNORDERED_FLAG;
+
+                  // Recursively compare objects (susceptible to call stack limits).
+                  stack.set(object, other);
+                  var result = equalArrays(
+                    convert(object),
+                    convert(other),
+                    bitmask,
+                    customizer,
+                    equalFunc,
+                    stack
+                  );
+                  stack['delete'](object);
+                  return result;
+
+                case symbolTag:
+                  if (symbolValueOf) {
+                    return symbolValueOf.call(object) == symbolValueOf.call(other);
+                  }
+              }
+              return false;
+            }
+
+            /**
+             * A specialized version of `baseIsEqualDeep` for objects with support for
+             * partial deep comparisons.
+             *
+             * @private
+             * @param {Object} object The object to compare.
+             * @param {Object} other The other object to compare.
+             * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
+             * @param {Function} customizer The function to customize comparisons.
+             * @param {Function} equalFunc The function to determine equivalents of values.
+             * @param {Object} stack Tracks traversed `object` and `other` objects.
+             * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+             */
+            function equalObjects(object, other, bitmask, customizer, equalFunc, stack) {
+              var isPartial = bitmask & COMPARE_PARTIAL_FLAG,
+                objProps = getAllKeys(object),
+                objLength = objProps.length,
+                othProps = getAllKeys(other),
+                othLength = othProps.length;
+
+              if (objLength != othLength && !isPartial) {
+                return false;
+              }
+              var index = objLength;
+              while (index--) {
+                var key = objProps[index];
+                if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) {
+                  return false;
+                }
+              }
+              // Assume cyclic values are equal.
+              var stacked = stack.get(object);
+              if (stacked && stack.get(other)) {
+                return stacked == other;
+              }
+              var result = true;
+              stack.set(object, other);
+              stack.set(other, object);
+
+              var skipCtor = isPartial;
+              while (++index < objLength) {
+                key = objProps[index];
+                var objValue = object[key],
+                  othValue = other[key];
+
+                if (customizer) {
+                  var compared = isPartial
+                    ? customizer(othValue, objValue, key, other, object, stack)
+                    : customizer(objValue, othValue, key, object, other, stack);
+                }
+                // Recursively compare objects (susceptible to call stack limits).
+                if (
+                  !(compared === undefined
+                    ? objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack)
+                    : compared)
+                ) {
+                  result = false;
+                  break;
+                }
+                skipCtor || (skipCtor = key == 'constructor');
+              }
+              if (result && !skipCtor) {
+                var objCtor = object.constructor,
+                  othCtor = other.constructor;
+
+                // Non `Object` object instances with different constructors are not equal.
+                if (
+                  objCtor != othCtor &&
+                  'constructor' in object &&
+                  'constructor' in other &&
+                  !(
+                    typeof objCtor == 'function' &&
+                    objCtor instanceof objCtor &&
+                    typeof othCtor == 'function' &&
+                    othCtor instanceof othCtor
+                  )
+                ) {
+                  result = false;
+                }
+              }
+              stack['delete'](object);
+              stack['delete'](other);
+              return result;
+            }
+
+            /**
+             * A specialized version of `baseRest` which flattens the rest array.
+             *
+             * @private
+             * @param {Function} func The function to apply a rest parameter to.
+             * @returns {Function} Returns the new function.
+             */
+            function flatRest(func) {
+              return setToString(overRest(func, undefined, flatten), func + '');
+            }
+
+            /**
+             * Creates an array of own enumerable property names and symbols of `object`.
+             *
+             * @private
+             * @param {Object} object The object to query.
+             * @returns {Array} Returns the array of property names and symbols.
+             */
+            function getAllKeys(object) {
+              return baseGetAllKeys(object, keys, getSymbols);
+            }
+
+            /**
+             * Creates an array of own and inherited enumerable property names and
+             * symbols of `object`.
+             *
+             * @private
+             * @param {Object} object The object to query.
+             * @returns {Array} Returns the array of property names and symbols.
+             */
+            function getAllKeysIn(object) {
+              return baseGetAllKeys(object, keysIn, getSymbolsIn);
+            }
+
+            /**
+             * Gets metadata for `func`.
+             *
+             * @private
+             * @param {Function} func The function to query.
+             * @returns {*} Returns the metadata for `func`.
+             */
+            var getData = !metaMap
+              ? noop
+              : function (func) {
+                  return metaMap.get(func);
+                };
+
+            /**
+             * Gets the name of `func`.
+             *
+             * @private
+             * @param {Function} func The function to query.
+             * @returns {string} Returns the function name.
+             */
+            function getFuncName(func) {
+              var result = func.name + '',
+                array = realNames[result],
+                length = hasOwnProperty.call(realNames, result) ? array.length : 0;
+
+              while (length--) {
+                var data = array[length],
+                  otherFunc = data.func;
+                if (otherFunc == null || otherFunc == func) {
+                  return data.name;
+                }
+              }
+              return result;
+            }
+
+            /**
+             * Gets the argument placeholder value for `func`.
+             *
+             * @private
+             * @param {Function} func The function to inspect.
+             * @returns {*} Returns the placeholder value.
+             */
+            function getHolder(func) {
+              var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func;
+              return object.placeholder;
+            }
+
+            /**
+             * Gets the appropriate "iteratee" function. If `_.iteratee` is customized,
+             * this function returns the custom method, otherwise it returns `baseIteratee`.
+             * If arguments are provided, the chosen function is invoked with them and
+             * its result is returned.
+             *
+             * @private
+             * @param {*} [value] The value to convert to an iteratee.
+             * @param {number} [arity] The arity of the created iteratee.
+             * @returns {Function} Returns the chosen function or its result.
+             */
+            function getIteratee() {
+              var result = lodash.iteratee || iteratee;
+              result = result === iteratee ? baseIteratee : result;
+              return arguments.length ? result(arguments[0], arguments[1]) : result;
+            }
+
+            /**
+             * Gets the data for `map`.
+             *
+             * @private
+             * @param {Object} map The map to query.
+             * @param {string} key The reference key.
+             * @returns {*} Returns the map data.
+             */
+            function getMapData(map, key) {
+              var data = map.__data__;
+              return isKeyable(key) ? data[typeof key == 'string' ? 'string' : 'hash'] : data.map;
+            }
+
+            /**
+             * Gets the property names, values, and compare flags of `object`.
+             *
+             * @private
+             * @param {Object} object The object to query.
+             * @returns {Array} Returns the match data of `object`.
+             */
+            function getMatchData(object) {
+              var result = keys(object),
+                length = result.length;
+
+              while (length--) {
+                var key = result[length],
+                  value = object[key];
+
+                result[length] = [key, value, isStrictComparable(value)];
+              }
+              return result;
+            }
+
+            /**
+             * Gets the native function at `key` of `object`.
+             *
+             * @private
+             * @param {Object} object The object to query.
+             * @param {string} key The key of the method to get.
+             * @returns {*} Returns the function if it's native, else `undefined`.
+             */
+            function getNative(object, key) {
+              var value = getValue(object, key);
+              return baseIsNative(value) ? value : undefined;
+            }
+
+            /**
+             * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
+             *
+             * @private
+             * @param {*} value The value to query.
+             * @returns {string} Returns the raw `toStringTag`.
+             */
+            function getRawTag(value) {
+              var isOwn = hasOwnProperty.call(value, symToStringTag),
+                tag = value[symToStringTag];
+
+              try {
+                value[symToStringTag] = undefined;
+                var unmasked = true;
+              } catch (e) {}
+
+              var result = nativeObjectToString.call(value);
+              if (unmasked) {
+                if (isOwn) {
+                  value[symToStringTag] = tag;
+                } else {
+                  delete value[symToStringTag];
+                }
+              }
+              return result;
+            }
+
+            /**
+             * Creates an array of the own enumerable symbols of `object`.
+             *
+             * @private
+             * @param {Object} object The object to query.
+             * @returns {Array} Returns the array of symbols.
+             */
+            var getSymbols = !nativeGetSymbols
+              ? stubArray
+              : function (object) {
+                  if (object == null) {
+                    return [];
+                  }
+                  object = Object(object);
+                  return arrayFilter(nativeGetSymbols(object), function (symbol) {
+                    return propertyIsEnumerable.call(object, symbol);
+                  });
+                };
+
+            /**
+             * Creates an array of the own and inherited enumerable symbols of `object`.
+             *
+             * @private
+             * @param {Object} object The object to query.
+             * @returns {Array} Returns the array of symbols.
+             */
+            var getSymbolsIn = !nativeGetSymbols
+              ? stubArray
+              : function (object) {
+                  var result = [];
+                  while (object) {
+                    arrayPush(result, getSymbols(object));
+                    object = getPrototype(object);
+                  }
+                  return result;
+                };
+
+            /**
+             * Gets the `toStringTag` of `value`.
+             *
+             * @private
+             * @param {*} value The value to query.
+             * @returns {string} Returns the `toStringTag`.
+             */
+            var getTag = baseGetTag;
+
+            // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.
+            if (
+              (DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||
+              (Map && getTag(new Map()) != mapTag) ||
+              (Promise && getTag(Promise.resolve()) != promiseTag) ||
+              (Set && getTag(new Set()) != setTag) ||
+              (WeakMap && getTag(new WeakMap()) != weakMapTag)
+            ) {
+              getTag = function (value) {
+                var result = baseGetTag(value),
+                  Ctor = result == objectTag ? value.constructor : undefined,
+                  ctorString = Ctor ? toSource(Ctor) : '';
+
+                if (ctorString) {
+                  switch (ctorString) {
+                    case dataViewCtorString:
+                      return dataViewTag;
+                    case mapCtorString:
+                      return mapTag;
+                    case promiseCtorString:
+                      return promiseTag;
+                    case setCtorString:
+                      return setTag;
+                    case weakMapCtorString:
+                      return weakMapTag;
+                  }
+                }
+                return result;
+              };
+            }
+
+            /**
+             * Gets the view, applying any `transforms` to the `start` and `end` positions.
+             *
+             * @private
+             * @param {number} start The start of the view.
+             * @param {number} end The end of the view.
+             * @param {Array} transforms The transformations to apply to the view.
+             * @returns {Object} Returns an object containing the `start` and `end`
+             *  positions of the view.
+             */
+            function getView(start, end, transforms) {
+              var index = -1,
+                length = transforms.length;
+
+              while (++index < length) {
+                var data = transforms[index],
+                  size = data.size;
+
+                switch (data.type) {
+                  case 'drop':
+                    start += size;
+                    break;
+                  case 'dropRight':
+                    end -= size;
+                    break;
+                  case 'take':
+                    end = nativeMin(end, start + size);
+                    break;
+                  case 'takeRight':
+                    start = nativeMax(start, end - size);
+                    break;
+                }
+              }
+              return { start: start, end: end };
+            }
+
+            /**
+             * Extracts wrapper details from the `source` body comment.
+             *
+             * @private
+             * @param {string} source The source to inspect.
+             * @returns {Array} Returns the wrapper details.
+             */
+            function getWrapDetails(source) {
+              var match = source.match(reWrapDetails);
+              return match ? match[1].split(reSplitDetails) : [];
+            }
+
+            /**
+             * Checks if `path` exists on `object`.
+             *
+             * @private
+             * @param {Object} object The object to query.
+             * @param {Array|string} path The path to check.
+             * @param {Function} hasFunc The function to check properties.
+             * @returns {boolean} Returns `true` if `path` exists, else `false`.
+             */
+            function hasPath(object, path, hasFunc) {
+              path = castPath(path, object);
+
+              var index = -1,
+                length = path.length,
+                result = false;
+
+              while (++index < length) {
+                var key = toKey(path[index]);
+                if (!(result = object != null && hasFunc(object, key))) {
+                  break;
+                }
+                object = object[key];
+              }
+              if (result || ++index != length) {
+                return result;
+              }
+              length = object == null ? 0 : object.length;
+              return (
+                !!length &&
+                isLength(length) &&
+                isIndex(key, length) &&
+                (isArray(object) || isArguments(object))
+              );
+            }
+
+            /**
+             * Initializes an array clone.
+             *
+             * @private
+             * @param {Array} array The array to clone.
+             * @returns {Array} Returns the initialized clone.
+             */
+            function initCloneArray(array) {
+              var length = array.length,
+                result = new array.constructor(length);
+
+              // Add properties assigned by `RegExp#exec`.
+              if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
+                result.index = array.index;
+                result.input = array.input;
+              }
+              return result;
+            }
+
+            /**
+             * Initializes an object clone.
+             *
+             * @private
+             * @param {Object} object The object to clone.
+             * @returns {Object} Returns the initialized clone.
+             */
+            function initCloneObject(object) {
+              return typeof object.constructor == 'function' && !isPrototype(object)
+                ? baseCreate(getPrototype(object))
+                : {};
+            }
+
+            /**
+             * Initializes an object clone based on its `toStringTag`.
+             *
+             * **Note:** This function only supports cloning values with tags of
+             * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`.
+             *
+             * @private
+             * @param {Object} object The object to clone.
+             * @param {string} tag The `toStringTag` of the object to clone.
+             * @param {boolean} [isDeep] Specify a deep clone.
+             * @returns {Object} Returns the initialized clone.
+             */
+            function initCloneByTag(object, tag, isDeep) {
+              var Ctor = object.constructor;
+              switch (tag) {
+                case arrayBufferTag:
+                  return cloneArrayBuffer(object);
+
+                case boolTag:
+                case dateTag:
+                  return new Ctor(+object);
+
+                case dataViewTag:
+                  return cloneDataView(object, isDeep);
+
+                case float32Tag:
+                case float64Tag:
+                case int8Tag:
+                case int16Tag:
+                case int32Tag:
+                case uint8Tag:
+                case uint8ClampedTag:
+                case uint16Tag:
+                case uint32Tag:
+                  return cloneTypedArray(object, isDeep);
+
+                case mapTag:
+                  return new Ctor();
+
+                case numberTag:
+                case stringTag:
+                  return new Ctor(object);
+
+                case regexpTag:
+                  return cloneRegExp(object);
+
+                case setTag:
+                  return new Ctor();
+
+                case symbolTag:
+                  return cloneSymbol(object);
+              }
+            }
+
+            /**
+             * Inserts wrapper `details` in a comment at the top of the `source` body.
+             *
+             * @private
+             * @param {string} source The source to modify.
+             * @returns {Array} details The details to insert.
+             * @returns {string} Returns the modified source.
+             */
+            function insertWrapDetails(source, details) {
+              var length = details.length;
+              if (!length) {
+                return source;
+              }
+              var lastIndex = length - 1;
+              details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex];
+              details = details.join(length > 2 ? ', ' : ' ');
+              return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n');
+            }
+
+            /**
+             * Checks if `value` is a flattenable `arguments` object or array.
+             *
+             * @private
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
+             */
+            function isFlattenable(value) {
+              return (
+                isArray(value) ||
+                isArguments(value) ||
+                !!(spreadableSymbol && value && value[spreadableSymbol])
+              );
+            }
+
+            /**
+             * Checks if `value` is a valid array-like index.
+             *
+             * @private
+             * @param {*} value The value to check.
+             * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
+             * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
+             */
+            function isIndex(value, length) {
+              var type = typeof value;
+              length = length == null ? MAX_SAFE_INTEGER : length;
+
+              return (
+                !!length &&
+                (type == 'number' || (type != 'symbol' && reIsUint.test(value))) &&
+                value > -1 &&
+                value % 1 == 0 &&
+                value < length
+              );
+            }
+
+            /**
+             * Checks if the given arguments are from an iteratee call.
+             *
+             * @private
+             * @param {*} value The potential iteratee value argument.
+             * @param {*} index The potential iteratee index or key argument.
+             * @param {*} object The potential iteratee object argument.
+             * @returns {boolean} Returns `true` if the arguments are from an iteratee call,
+             *  else `false`.
+             */
+            function isIterateeCall(value, index, object) {
+              if (!isObject(object)) {
+                return false;
+              }
+              var type = typeof index;
+              if (
+                type == 'number'
+                  ? isArrayLike(object) && isIndex(index, object.length)
+                  : type == 'string' && index in object
+              ) {
+                return eq(object[index], value);
+              }
+              return false;
+            }
+
+            /**
+             * Checks if `value` is a property name and not a property path.
+             *
+             * @private
+             * @param {*} value The value to check.
+             * @param {Object} [object] The object to query keys on.
+             * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
+             */
+            function isKey(value, object) {
+              if (isArray(value)) {
+                return false;
+              }
+              var type = typeof value;
+              if (
+                type == 'number' ||
+                type == 'symbol' ||
+                type == 'boolean' ||
+                value == null ||
+                isSymbol(value)
+              ) {
+                return true;
+              }
+              return (
+                reIsPlainProp.test(value) ||
+                !reIsDeepProp.test(value) ||
+                (object != null && value in Object(object))
+              );
+            }
+
+            /**
+             * Checks if `value` is suitable for use as unique object key.
+             *
+             * @private
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
+             */
+            function isKeyable(value) {
+              var type = typeof value;
+              return type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean'
+                ? value !== '__proto__'
+                : value === null;
+            }
+
+            /**
+             * Checks if `func` has a lazy counterpart.
+             *
+             * @private
+             * @param {Function} func The function to check.
+             * @returns {boolean} Returns `true` if `func` has a lazy counterpart,
+             *  else `false`.
+             */
+            function isLaziable(func) {
+              var funcName = getFuncName(func),
+                other = lodash[funcName];
+
+              if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) {
+                return false;
+              }
+              if (func === other) {
+                return true;
+              }
+              var data = getData(other);
+              return !!data && func === data[0];
+            }
+
+            /**
+             * Checks if `func` has its source masked.
+             *
+             * @private
+             * @param {Function} func The function to check.
+             * @returns {boolean} Returns `true` if `func` is masked, else `false`.
+             */
+            function isMasked(func) {
+              return !!maskSrcKey && maskSrcKey in func;
+            }
+
+            /**
+             * Checks if `func` is capable of being masked.
+             *
+             * @private
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `func` is maskable, else `false`.
+             */
+            var isMaskable = coreJsData ? isFunction : stubFalse;
+
+            /**
+             * Checks if `value` is likely a prototype object.
+             *
+             * @private
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
+             */
+            function isPrototype(value) {
+              var Ctor = value && value.constructor,
+                proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;
+
+              return value === proto;
+            }
+
+            /**
+             * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
+             *
+             * @private
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` if suitable for strict
+             *  equality comparisons, else `false`.
+             */
+            function isStrictComparable(value) {
+              return value === value && !isObject(value);
+            }
+
+            /**
+             * A specialized version of `matchesProperty` for source values suitable
+             * for strict equality comparisons, i.e. `===`.
+             *
+             * @private
+             * @param {string} key The key of the property to get.
+             * @param {*} srcValue The value to match.
+             * @returns {Function} Returns the new spec function.
+             */
+            function matchesStrictComparable(key, srcValue) {
+              return function (object) {
+                if (object == null) {
+                  return false;
+                }
+                return object[key] === srcValue && (srcValue !== undefined || key in Object(object));
+              };
+            }
+
+            /**
+             * A specialized version of `_.memoize` which clears the memoized function's
+             * cache when it exceeds `MAX_MEMOIZE_SIZE`.
+             *
+             * @private
+             * @param {Function} func The function to have its output memoized.
+             * @returns {Function} Returns the new memoized function.
+             */
+            function memoizeCapped(func) {
+              var result = memoize(func, function (key) {
+                if (cache.size === MAX_MEMOIZE_SIZE) {
+                  cache.clear();
+                }
+                return key;
+              });
+
+              var cache = result.cache;
+              return result;
+            }
+
+            /**
+             * Merges the function metadata of `source` into `data`.
+             *
+             * Merging metadata reduces the number of wrappers used to invoke a function.
+             * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
+             * may be applied regardless of execution order. Methods like `_.ary` and
+             * `_.rearg` modify function arguments, making the order in which they are
+             * executed important, preventing the merging of metadata. However, we make
+             * an exception for a safe combined case where curried functions have `_.ary`
+             * and or `_.rearg` applied.
+             *
+             * @private
+             * @param {Array} data The destination metadata.
+             * @param {Array} source The source metadata.
+             * @returns {Array} Returns `data`.
+             */
+            function mergeData(data, source) {
+              var bitmask = data[1],
+                srcBitmask = source[1],
+                newBitmask = bitmask | srcBitmask,
+                isCommon = newBitmask < (WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG | WRAP_ARY_FLAG);
+
+              var isCombo =
+                (srcBitmask == WRAP_ARY_FLAG && bitmask == WRAP_CURRY_FLAG) ||
+                (srcBitmask == WRAP_ARY_FLAG && bitmask == WRAP_REARG_FLAG && data[7].length <= source[8]) ||
+                (srcBitmask == (WRAP_ARY_FLAG | WRAP_REARG_FLAG) &&
+                  source[7].length <= source[8] &&
+                  bitmask == WRAP_CURRY_FLAG);
+
+              // Exit early if metadata can't be merged.
+              if (!(isCommon || isCombo)) {
+                return data;
+              }
+              // Use source `thisArg` if available.
+              if (srcBitmask & WRAP_BIND_FLAG) {
+                data[2] = source[2];
+                // Set when currying a bound function.
+                newBitmask |= bitmask & WRAP_BIND_FLAG ? 0 : WRAP_CURRY_BOUND_FLAG;
+              }
+              // Compose partial arguments.
+              var value = source[3];
+              if (value) {
+                var partials = data[3];
+                data[3] = partials ? composeArgs(partials, value, source[4]) : value;
+                data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4];
+              }
+              // Compose partial right arguments.
+              value = source[5];
+              if (value) {
+                partials = data[5];
+                data[5] = partials ? composeArgsRight(partials, value, source[6]) : value;
+                data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6];
+              }
+              // Use source `argPos` if available.
+              value = source[7];
+              if (value) {
+                data[7] = value;
+              }
+              // Use source `ary` if it's smaller.
+              if (srcBitmask & WRAP_ARY_FLAG) {
+                data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
+              }
+              // Use source `arity` if one is not provided.
+              if (data[9] == null) {
+                data[9] = source[9];
+              }
+              // Use source `func` and merge bitmasks.
+              data[0] = source[0];
+              data[1] = newBitmask;
+
+              return data;
+            }
+
+            /**
+             * This function is like
+             * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
+             * except that it includes inherited enumerable properties.
+             *
+             * @private
+             * @param {Object} object The object to query.
+             * @returns {Array} Returns the array of property names.
+             */
+            function nativeKeysIn(object) {
+              var result = [];
+              if (object != null) {
+                for (var key in Object(object)) {
+                  result.push(key);
+                }
+              }
+              return result;
+            }
+
+            /**
+             * Converts `value` to a string using `Object.prototype.toString`.
+             *
+             * @private
+             * @param {*} value The value to convert.
+             * @returns {string} Returns the converted string.
+             */
+            function objectToString(value) {
+              return nativeObjectToString.call(value);
+            }
+
+            /**
+             * A specialized version of `baseRest` which transforms the rest array.
+             *
+             * @private
+             * @param {Function} func The function to apply a rest parameter to.
+             * @param {number} [start=func.length-1] The start position of the rest parameter.
+             * @param {Function} transform The rest array transform.
+             * @returns {Function} Returns the new function.
+             */
+            function overRest(func, start, transform) {
+              start = nativeMax(start === undefined ? func.length - 1 : start, 0);
+              return function () {
+                var args = arguments,
+                  index = -1,
+                  length = nativeMax(args.length - start, 0),
+                  array = Array(length);
+
+                while (++index < length) {
+                  array[index] = args[start + index];
+                }
+                index = -1;
+                var otherArgs = Array(start + 1);
+                while (++index < start) {
+                  otherArgs[index] = args[index];
+                }
+                otherArgs[start] = transform(array);
+                return apply(func, this, otherArgs);
+              };
+            }
+
+            /**
+             * Gets the parent value at `path` of `object`.
+             *
+             * @private
+             * @param {Object} object The object to query.
+             * @param {Array} path The path to get the parent value of.
+             * @returns {*} Returns the parent value.
+             */
+            function parent(object, path) {
+              return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1));
+            }
+
+            /**
+             * Reorder `array` according to the specified indexes where the element at
+             * the first index is assigned as the first element, the element at
+             * the second index is assigned as the second element, and so on.
+             *
+             * @private
+             * @param {Array} array The array to reorder.
+             * @param {Array} indexes The arranged array indexes.
+             * @returns {Array} Returns `array`.
+             */
+            function reorder(array, indexes) {
+              var arrLength = array.length,
+                length = nativeMin(indexes.length, arrLength),
+                oldArray = copyArray(array);
+
+              while (length--) {
+                var index = indexes[length];
+                array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
+              }
+              return array;
+            }
+
+            /**
+             * Sets metadata for `func`.
+             *
+             * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
+             * period of time, it will trip its breaker and transition to an identity
+             * function to avoid garbage collection pauses in V8. See
+             * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070)
+             * for more details.
+             *
+             * @private
+             * @param {Function} func The function to associate metadata with.
+             * @param {*} data The metadata.
+             * @returns {Function} Returns `func`.
+             */
+            var setData = shortOut(baseSetData);
+
+            /**
+             * A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout).
+             *
+             * @private
+             * @param {Function} func The function to delay.
+             * @param {number} wait The number of milliseconds to delay invocation.
+             * @returns {number|Object} Returns the timer id or timeout object.
+             */
+            var setTimeout =
+              ctxSetTimeout ||
+              function (func, wait) {
+                return root.setTimeout(func, wait);
+              };
+
+            /**
+             * Sets the `toString` method of `func` to return `string`.
+             *
+             * @private
+             * @param {Function} func The function to modify.
+             * @param {Function} string The `toString` result.
+             * @returns {Function} Returns `func`.
+             */
+            var setToString = shortOut(baseSetToString);
+
+            /**
+             * Sets the `toString` method of `wrapper` to mimic the source of `reference`
+             * with wrapper details in a comment at the top of the source body.
+             *
+             * @private
+             * @param {Function} wrapper The function to modify.
+             * @param {Function} reference The reference function.
+             * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+             * @returns {Function} Returns `wrapper`.
+             */
+            function setWrapToString(wrapper, reference, bitmask) {
+              var source = reference + '';
+              return setToString(
+                wrapper,
+                insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask))
+              );
+            }
+
+            /**
+             * Creates a function that'll short out and invoke `identity` instead
+             * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`
+             * milliseconds.
+             *
+             * @private
+             * @param {Function} func The function to restrict.
+             * @returns {Function} Returns the new shortable function.
+             */
+            function shortOut(func) {
+              var count = 0,
+                lastCalled = 0;
+
+              return function () {
+                var stamp = nativeNow(),
+                  remaining = HOT_SPAN - (stamp - lastCalled);
+
+                lastCalled = stamp;
+                if (remaining > 0) {
+                  if (++count >= HOT_COUNT) {
+                    return arguments[0];
+                  }
+                } else {
+                  count = 0;
+                }
+                return func.apply(undefined, arguments);
+              };
+            }
+
+            /**
+             * A specialized version of `_.shuffle` which mutates and sets the size of `array`.
+             *
+             * @private
+             * @param {Array} array The array to shuffle.
+             * @param {number} [size=array.length] The size of `array`.
+             * @returns {Array} Returns `array`.
+             */
+            function shuffleSelf(array, size) {
+              var index = -1,
+                length = array.length,
+                lastIndex = length - 1;
+
+              size = size === undefined ? length : size;
+              while (++index < size) {
+                var rand = baseRandom(index, lastIndex),
+                  value = array[rand];
+
+                array[rand] = array[index];
+                array[index] = value;
+              }
+              array.length = size;
+              return array;
+            }
+
+            /**
+             * Converts `string` to a property path array.
+             *
+             * @private
+             * @param {string} string The string to convert.
+             * @returns {Array} Returns the property path array.
+             */
+            var stringToPath = memoizeCapped(function (string) {
+              var result = [];
+              if (string.charCodeAt(0) === 46 /* . */) {
+                result.push('');
+              }
+              string.replace(rePropName, function (match, number, quote, subString) {
+                result.push(quote ? subString.replace(reEscapeChar, '$1') : number || match);
+              });
+              return result;
+            });
+
+            /**
+             * Converts `value` to a string key if it's not a string or symbol.
+             *
+             * @private
+             * @param {*} value The value to inspect.
+             * @returns {string|symbol} Returns the key.
+             */
+            function toKey(value) {
+              if (typeof value == 'string' || isSymbol(value)) {
+                return value;
+              }
+              var result = value + '';
+              return result == '0' && 1 / value == -INFINITY ? '-0' : result;
+            }
+
+            /**
+             * Converts `func` to its source code.
+             *
+             * @private
+             * @param {Function} func The function to convert.
+             * @returns {string} Returns the source code.
+             */
+            function toSource(func) {
+              if (func != null) {
+                try {
+                  return funcToString.call(func);
+                } catch (e) {}
+                try {
+                  return func + '';
+                } catch (e) {}
+              }
+              return '';
+            }
+
+            /**
+             * Updates wrapper `details` based on `bitmask` flags.
+             *
+             * @private
+             * @returns {Array} details The details to modify.
+             * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+             * @returns {Array} Returns `details`.
+             */
+            function updateWrapDetails(details, bitmask) {
+              arrayEach(wrapFlags, function (pair) {
+                var value = '_.' + pair[0];
+                if (bitmask & pair[1] && !arrayIncludes(details, value)) {
+                  details.push(value);
+                }
+              });
+              return details.sort();
+            }
+
+            /**
+             * Creates a clone of `wrapper`.
+             *
+             * @private
+             * @param {Object} wrapper The wrapper to clone.
+             * @returns {Object} Returns the cloned wrapper.
+             */
+            function wrapperClone(wrapper) {
+              if (wrapper instanceof LazyWrapper) {
+                return wrapper.clone();
+              }
+              var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__);
+              result.__actions__ = copyArray(wrapper.__actions__);
+              result.__index__ = wrapper.__index__;
+              result.__values__ = wrapper.__values__;
+              return result;
+            }
+
+            /*------------------------------------------------------------------------*/
+
+            /**
+             * Creates an array of elements split into groups the length of `size`.
+             * If `array` can't be split evenly, the final chunk will be the remaining
+             * elements.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Array
+             * @param {Array} array The array to process.
+             * @param {number} [size=1] The length of each chunk
+             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+             * @returns {Array} Returns the new array of chunks.
+             * @example
+             *
+             * _.chunk(['a', 'b', 'c', 'd'], 2);
+             * // => [['a', 'b'], ['c', 'd']]
+             *
+             * _.chunk(['a', 'b', 'c', 'd'], 3);
+             * // => [['a', 'b', 'c'], ['d']]
+             */
+            function chunk(array, size, guard) {
+              if (guard ? isIterateeCall(array, size, guard) : size === undefined) {
+                size = 1;
+              } else {
+                size = nativeMax(toInteger(size), 0);
+              }
+              var length = array == null ? 0 : array.length;
+              if (!length || size < 1) {
+                return [];
+              }
+              var index = 0,
+                resIndex = 0,
+                result = Array(nativeCeil(length / size));
+
+              while (index < length) {
+                result[resIndex++] = baseSlice(array, index, (index += size));
+              }
+              return result;
+            }
+
+            /**
+             * Creates an array with all falsey values removed. The values `false`, `null`,
+             * `0`, `""`, `undefined`, and `NaN` are falsey.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Array
+             * @param {Array} array The array to compact.
+             * @returns {Array} Returns the new array of filtered values.
+             * @example
+             *
+             * _.compact([0, 1, false, 2, '', 3]);
+             * // => [1, 2, 3]
+             */
+            function compact(array) {
+              var index = -1,
+                length = array == null ? 0 : array.length,
+                resIndex = 0,
+                result = [];
+
+              while (++index < length) {
+                var value = array[index];
+                if (value) {
+                  result[resIndex++] = value;
+                }
+              }
+              return result;
+            }
+
+            /**
+             * Creates a new array concatenating `array` with any additional arrays
+             * and/or values.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {Array} array The array to concatenate.
+             * @param {...*} [values] The values to concatenate.
+             * @returns {Array} Returns the new concatenated array.
+             * @example
+             *
+             * var array = [1];
+             * var other = _.concat(array, 2, [3], [[4]]);
+             *
+             * console.log(other);
+             * // => [1, 2, 3, [4]]
+             *
+             * console.log(array);
+             * // => [1]
+             */
+            function concat() {
+              var length = arguments.length;
+              if (!length) {
+                return [];
+              }
+              var args = Array(length - 1),
+                array = arguments[0],
+                index = length;
+
+              while (index--) {
+                args[index - 1] = arguments[index];
+              }
+              return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1));
+            }
+
+            /**
+             * Creates an array of `array` values not included in the other given arrays
+             * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+             * for equality comparisons. The order and references of result values are
+             * determined by the first array.
+             *
+             * **Note:** Unlike `_.pullAll`, this method returns a new array.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Array
+             * @param {Array} array The array to inspect.
+             * @param {...Array} [values] The values to exclude.
+             * @returns {Array} Returns the new array of filtered values.
+             * @see _.without, _.xor
+             * @example
+             *
+             * _.difference([2, 1], [2, 3]);
+             * // => [1]
+             */
+            var difference = baseRest(function (array, values) {
+              return isArrayLikeObject(array)
+                ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true))
+                : [];
+            });
+
+            /**
+             * This method is like `_.difference` except that it accepts `iteratee` which
+             * is invoked for each element of `array` and `values` to generate the criterion
+             * by which they're compared. The order and references of result values are
+             * determined by the first array. The iteratee is invoked with one argument:
+             * (value).
+             *
+             * **Note:** Unlike `_.pullAllBy`, this method returns a new array.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {Array} array The array to inspect.
+             * @param {...Array} [values] The values to exclude.
+             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+             * @returns {Array} Returns the new array of filtered values.
+             * @example
+             *
+             * _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor);
+             * // => [1.2]
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');
+             * // => [{ 'x': 2 }]
+             */
+            var differenceBy = baseRest(function (array, values) {
+              var iteratee = last(values);
+              if (isArrayLikeObject(iteratee)) {
+                iteratee = undefined;
+              }
+              return isArrayLikeObject(array)
+                ? baseDifference(
+                    array,
+                    baseFlatten(values, 1, isArrayLikeObject, true),
+                    getIteratee(iteratee, 2)
+                  )
+                : [];
+            });
+
+            /**
+             * This method is like `_.difference` except that it accepts `comparator`
+             * which is invoked to compare elements of `array` to `values`. The order and
+             * references of result values are determined by the first array. The comparator
+             * is invoked with two arguments: (arrVal, othVal).
+             *
+             * **Note:** Unlike `_.pullAllWith`, this method returns a new array.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {Array} array The array to inspect.
+             * @param {...Array} [values] The values to exclude.
+             * @param {Function} [comparator] The comparator invoked per element.
+             * @returns {Array} Returns the new array of filtered values.
+             * @example
+             *
+             * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
+             *
+             * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual);
+             * // => [{ 'x': 2, 'y': 1 }]
+             */
+            var differenceWith = baseRest(function (array, values) {
+              var comparator = last(values);
+              if (isArrayLikeObject(comparator)) {
+                comparator = undefined;
+              }
+              return isArrayLikeObject(array)
+                ? baseDifference(
+                    array,
+                    baseFlatten(values, 1, isArrayLikeObject, true),
+                    undefined,
+                    comparator
+                  )
+                : [];
+            });
+
+            /**
+             * Creates a slice of `array` with `n` elements dropped from the beginning.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.5.0
+             * @category Array
+             * @param {Array} array The array to query.
+             * @param {number} [n=1] The number of elements to drop.
+             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+             * @returns {Array} Returns the slice of `array`.
+             * @example
+             *
+             * _.drop([1, 2, 3]);
+             * // => [2, 3]
+             *
+             * _.drop([1, 2, 3], 2);
+             * // => [3]
+             *
+             * _.drop([1, 2, 3], 5);
+             * // => []
+             *
+             * _.drop([1, 2, 3], 0);
+             * // => [1, 2, 3]
+             */
+            function drop(array, n, guard) {
+              var length = array == null ? 0 : array.length;
+              if (!length) {
+                return [];
+              }
+              n = guard || n === undefined ? 1 : toInteger(n);
+              return baseSlice(array, n < 0 ? 0 : n, length);
+            }
+
+            /**
+             * Creates a slice of `array` with `n` elements dropped from the end.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Array
+             * @param {Array} array The array to query.
+             * @param {number} [n=1] The number of elements to drop.
+             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+             * @returns {Array} Returns the slice of `array`.
+             * @example
+             *
+             * _.dropRight([1, 2, 3]);
+             * // => [1, 2]
+             *
+             * _.dropRight([1, 2, 3], 2);
+             * // => [1]
+             *
+             * _.dropRight([1, 2, 3], 5);
+             * // => []
+             *
+             * _.dropRight([1, 2, 3], 0);
+             * // => [1, 2, 3]
+             */
+            function dropRight(array, n, guard) {
+              var length = array == null ? 0 : array.length;
+              if (!length) {
+                return [];
+              }
+              n = guard || n === undefined ? 1 : toInteger(n);
+              n = length - n;
+              return baseSlice(array, 0, n < 0 ? 0 : n);
+            }
+
+            /**
+             * Creates a slice of `array` excluding elements dropped from the end.
+             * Elements are dropped until `predicate` returns falsey. The predicate is
+             * invoked with three arguments: (value, index, array).
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Array
+             * @param {Array} array The array to query.
+             * @param {Function} [predicate=_.identity] The function invoked per iteration.
+             * @returns {Array} Returns the slice of `array`.
+             * @example
+             *
+             * var users = [
+             *   { 'user': 'barney',  'active': true },
+             *   { 'user': 'fred',    'active': false },
+             *   { 'user': 'pebbles', 'active': false }
+             * ];
+             *
+             * _.dropRightWhile(users, function(o) { return !o.active; });
+             * // => objects for ['barney']
+             *
+             * // The `_.matches` iteratee shorthand.
+             * _.dropRightWhile(users, { 'user': 'pebbles', 'active': false });
+             * // => objects for ['barney', 'fred']
+             *
+             * // The `_.matchesProperty` iteratee shorthand.
+             * _.dropRightWhile(users, ['active', false]);
+             * // => objects for ['barney']
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.dropRightWhile(users, 'active');
+             * // => objects for ['barney', 'fred', 'pebbles']
+             */
+            function dropRightWhile(array, predicate) {
+              return array && array.length ? baseWhile(array, getIteratee(predicate, 3), true, true) : [];
+            }
+
+            /**
+             * Creates a slice of `array` excluding elements dropped from the beginning.
+             * Elements are dropped until `predicate` returns falsey. The predicate is
+             * invoked with three arguments: (value, index, array).
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Array
+             * @param {Array} array The array to query.
+             * @param {Function} [predicate=_.identity] The function invoked per iteration.
+             * @returns {Array} Returns the slice of `array`.
+             * @example
+             *
+             * var users = [
+             *   { 'user': 'barney',  'active': false },
+             *   { 'user': 'fred',    'active': false },
+             *   { 'user': 'pebbles', 'active': true }
+             * ];
+             *
+             * _.dropWhile(users, function(o) { return !o.active; });
+             * // => objects for ['pebbles']
+             *
+             * // The `_.matches` iteratee shorthand.
+             * _.dropWhile(users, { 'user': 'barney', 'active': false });
+             * // => objects for ['fred', 'pebbles']
+             *
+             * // The `_.matchesProperty` iteratee shorthand.
+             * _.dropWhile(users, ['active', false]);
+             * // => objects for ['pebbles']
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.dropWhile(users, 'active');
+             * // => objects for ['barney', 'fred', 'pebbles']
+             */
+            function dropWhile(array, predicate) {
+              return array && array.length ? baseWhile(array, getIteratee(predicate, 3), true) : [];
+            }
+
+            /**
+             * Fills elements of `array` with `value` from `start` up to, but not
+             * including, `end`.
+             *
+             * **Note:** This method mutates `array`.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.2.0
+             * @category Array
+             * @param {Array} array The array to fill.
+             * @param {*} value The value to fill `array` with.
+             * @param {number} [start=0] The start position.
+             * @param {number} [end=array.length] The end position.
+             * @returns {Array} Returns `array`.
+             * @example
+             *
+             * var array = [1, 2, 3];
+             *
+             * _.fill(array, 'a');
+             * console.log(array);
+             * // => ['a', 'a', 'a']
+             *
+             * _.fill(Array(3), 2);
+             * // => [2, 2, 2]
+             *
+             * _.fill([4, 6, 8, 10], '*', 1, 3);
+             * // => [4, '*', '*', 10]
+             */
+            function fill(array, value, start, end) {
+              var length = array == null ? 0 : array.length;
+              if (!length) {
+                return [];
+              }
+              if (start && typeof start != 'number' && isIterateeCall(array, value, start)) {
+                start = 0;
+                end = length;
+              }
+              return baseFill(array, value, start, end);
+            }
+
+            /**
+             * This method is like `_.find` except that it returns the index of the first
+             * element `predicate` returns truthy for instead of the element itself.
+             *
+             * @static
+             * @memberOf _
+             * @since 1.1.0
+             * @category Array
+             * @param {Array} array The array to inspect.
+             * @param {Function} [predicate=_.identity] The function invoked per iteration.
+             * @param {number} [fromIndex=0] The index to search from.
+             * @returns {number} Returns the index of the found element, else `-1`.
+             * @example
+             *
+             * var users = [
+             *   { 'user': 'barney',  'active': false },
+             *   { 'user': 'fred',    'active': false },
+             *   { 'user': 'pebbles', 'active': true }
+             * ];
+             *
+             * _.findIndex(users, function(o) { return o.user == 'barney'; });
+             * // => 0
+             *
+             * // The `_.matches` iteratee shorthand.
+             * _.findIndex(users, { 'user': 'fred', 'active': false });
+             * // => 1
+             *
+             * // The `_.matchesProperty` iteratee shorthand.
+             * _.findIndex(users, ['active', false]);
+             * // => 0
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.findIndex(users, 'active');
+             * // => 2
+             */
+            function findIndex(array, predicate, fromIndex) {
+              var length = array == null ? 0 : array.length;
+              if (!length) {
+                return -1;
+              }
+              var index = fromIndex == null ? 0 : toInteger(fromIndex);
+              if (index < 0) {
+                index = nativeMax(length + index, 0);
+              }
+              return baseFindIndex(array, getIteratee(predicate, 3), index);
+            }
+
+            /**
+             * This method is like `_.findIndex` except that it iterates over elements
+             * of `collection` from right to left.
+             *
+             * @static
+             * @memberOf _
+             * @since 2.0.0
+             * @category Array
+             * @param {Array} array The array to inspect.
+             * @param {Function} [predicate=_.identity] The function invoked per iteration.
+             * @param {number} [fromIndex=array.length-1] The index to search from.
+             * @returns {number} Returns the index of the found element, else `-1`.
+             * @example
+             *
+             * var users = [
+             *   { 'user': 'barney',  'active': true },
+             *   { 'user': 'fred',    'active': false },
+             *   { 'user': 'pebbles', 'active': false }
+             * ];
+             *
+             * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; });
+             * // => 2
+             *
+             * // The `_.matches` iteratee shorthand.
+             * _.findLastIndex(users, { 'user': 'barney', 'active': true });
+             * // => 0
+             *
+             * // The `_.matchesProperty` iteratee shorthand.
+             * _.findLastIndex(users, ['active', false]);
+             * // => 2
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.findLastIndex(users, 'active');
+             * // => 0
+             */
+            function findLastIndex(array, predicate, fromIndex) {
+              var length = array == null ? 0 : array.length;
+              if (!length) {
+                return -1;
+              }
+              var index = length - 1;
+              if (fromIndex !== undefined) {
+                index = toInteger(fromIndex);
+                index = fromIndex < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1);
+              }
+              return baseFindIndex(array, getIteratee(predicate, 3), index, true);
+            }
+
+            /**
+             * Flattens `array` a single level deep.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Array
+             * @param {Array} array The array to flatten.
+             * @returns {Array} Returns the new flattened array.
+             * @example
+             *
+             * _.flatten([1, [2, [3, [4]], 5]]);
+             * // => [1, 2, [3, [4]], 5]
+             */
+            function flatten(array) {
+              var length = array == null ? 0 : array.length;
+              return length ? baseFlatten(array, 1) : [];
+            }
+
+            /**
+             * Recursively flattens `array`.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Array
+             * @param {Array} array The array to flatten.
+             * @returns {Array} Returns the new flattened array.
+             * @example
+             *
+             * _.flattenDeep([1, [2, [3, [4]], 5]]);
+             * // => [1, 2, 3, 4, 5]
+             */
+            function flattenDeep(array) {
+              var length = array == null ? 0 : array.length;
+              return length ? baseFlatten(array, INFINITY) : [];
+            }
+
+            /**
+             * Recursively flatten `array` up to `depth` times.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.4.0
+             * @category Array
+             * @param {Array} array The array to flatten.
+             * @param {number} [depth=1] The maximum recursion depth.
+             * @returns {Array} Returns the new flattened array.
+             * @example
+             *
+             * var array = [1, [2, [3, [4]], 5]];
+             *
+             * _.flattenDepth(array, 1);
+             * // => [1, 2, [3, [4]], 5]
+             *
+             * _.flattenDepth(array, 2);
+             * // => [1, 2, 3, [4], 5]
+             */
+            function flattenDepth(array, depth) {
+              var length = array == null ? 0 : array.length;
+              if (!length) {
+                return [];
+              }
+              depth = depth === undefined ? 1 : toInteger(depth);
+              return baseFlatten(array, depth);
+            }
+
+            /**
+             * The inverse of `_.toPairs`; this method returns an object composed
+             * from key-value `pairs`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {Array} pairs The key-value pairs.
+             * @returns {Object} Returns the new object.
+             * @example
+             *
+             * _.fromPairs([['a', 1], ['b', 2]]);
+             * // => { 'a': 1, 'b': 2 }
+             */
+            function fromPairs(pairs) {
+              var index = -1,
+                length = pairs == null ? 0 : pairs.length,
+                result = {};
+
+              while (++index < length) {
+                var pair = pairs[index];
+                result[pair[0]] = pair[1];
+              }
+              return result;
+            }
+
+            /**
+             * Gets the first element of `array`.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @alias first
+             * @category Array
+             * @param {Array} array The array to query.
+             * @returns {*} Returns the first element of `array`.
+             * @example
+             *
+             * _.head([1, 2, 3]);
+             * // => 1
+             *
+             * _.head([]);
+             * // => undefined
+             */
+            function head(array) {
+              return array && array.length ? array[0] : undefined;
+            }
+
+            /**
+             * Gets the index at which the first occurrence of `value` is found in `array`
+             * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+             * for equality comparisons. If `fromIndex` is negative, it's used as the
+             * offset from the end of `array`.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Array
+             * @param {Array} array The array to inspect.
+             * @param {*} value The value to search for.
+             * @param {number} [fromIndex=0] The index to search from.
+             * @returns {number} Returns the index of the matched value, else `-1`.
+             * @example
+             *
+             * _.indexOf([1, 2, 1, 2], 2);
+             * // => 1
+             *
+             * // Search from the `fromIndex`.
+             * _.indexOf([1, 2, 1, 2], 2, 2);
+             * // => 3
+             */
+            function indexOf(array, value, fromIndex) {
+              var length = array == null ? 0 : array.length;
+              if (!length) {
+                return -1;
+              }
+              var index = fromIndex == null ? 0 : toInteger(fromIndex);
+              if (index < 0) {
+                index = nativeMax(length + index, 0);
+              }
+              return baseIndexOf(array, value, index);
+            }
+
+            /**
+             * Gets all but the last element of `array`.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Array
+             * @param {Array} array The array to query.
+             * @returns {Array} Returns the slice of `array`.
+             * @example
+             *
+             * _.initial([1, 2, 3]);
+             * // => [1, 2]
+             */
+            function initial(array) {
+              var length = array == null ? 0 : array.length;
+              return length ? baseSlice(array, 0, -1) : [];
+            }
+
+            /**
+             * Creates an array of unique values that are included in all given arrays
+             * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+             * for equality comparisons. The order and references of result values are
+             * determined by the first array.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Array
+             * @param {...Array} [arrays] The arrays to inspect.
+             * @returns {Array} Returns the new array of intersecting values.
+             * @example
+             *
+             * _.intersection([2, 1], [2, 3]);
+             * // => [2]
+             */
+            var intersection = baseRest(function (arrays) {
+              var mapped = arrayMap(arrays, castArrayLikeObject);
+              return mapped.length && mapped[0] === arrays[0] ? baseIntersection(mapped) : [];
+            });
+
+            /**
+             * This method is like `_.intersection` except that it accepts `iteratee`
+             * which is invoked for each element of each `arrays` to generate the criterion
+             * by which they're compared. The order and references of result values are
+             * determined by the first array. The iteratee is invoked with one argument:
+             * (value).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {...Array} [arrays] The arrays to inspect.
+             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+             * @returns {Array} Returns the new array of intersecting values.
+             * @example
+             *
+             * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor);
+             * // => [2.1]
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
+             * // => [{ 'x': 1 }]
+             */
+            var intersectionBy = baseRest(function (arrays) {
+              var iteratee = last(arrays),
+                mapped = arrayMap(arrays, castArrayLikeObject);
+
+              if (iteratee === last(mapped)) {
+                iteratee = undefined;
+              } else {
+                mapped.pop();
+              }
+              return mapped.length && mapped[0] === arrays[0]
+                ? baseIntersection(mapped, getIteratee(iteratee, 2))
+                : [];
+            });
+
+            /**
+             * This method is like `_.intersection` except that it accepts `comparator`
+             * which is invoked to compare elements of `arrays`. The order and references
+             * of result values are determined by the first array. The comparator is
+             * invoked with two arguments: (arrVal, othVal).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {...Array} [arrays] The arrays to inspect.
+             * @param {Function} [comparator] The comparator invoked per element.
+             * @returns {Array} Returns the new array of intersecting values.
+             * @example
+             *
+             * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
+             * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
+             *
+             * _.intersectionWith(objects, others, _.isEqual);
+             * // => [{ 'x': 1, 'y': 2 }]
+             */
+            var intersectionWith = baseRest(function (arrays) {
+              var comparator = last(arrays),
+                mapped = arrayMap(arrays, castArrayLikeObject);
+
+              comparator = typeof comparator == 'function' ? comparator : undefined;
+              if (comparator) {
+                mapped.pop();
+              }
+              return mapped.length && mapped[0] === arrays[0]
+                ? baseIntersection(mapped, undefined, comparator)
+                : [];
+            });
+
+            /**
+             * Converts all elements in `array` into a string separated by `separator`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {Array} array The array to convert.
+             * @param {string} [separator=','] The element separator.
+             * @returns {string} Returns the joined string.
+             * @example
+             *
+             * _.join(['a', 'b', 'c'], '~');
+             * // => 'a~b~c'
+             */
+            function join(array, separator) {
+              return array == null ? '' : nativeJoin.call(array, separator);
+            }
+
+            /**
+             * Gets the last element of `array`.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Array
+             * @param {Array} array The array to query.
+             * @returns {*} Returns the last element of `array`.
+             * @example
+             *
+             * _.last([1, 2, 3]);
+             * // => 3
+             */
+            function last(array) {
+              var length = array == null ? 0 : array.length;
+              return length ? array[length - 1] : undefined;
+            }
+
+            /**
+             * This method is like `_.indexOf` except that it iterates over elements of
+             * `array` from right to left.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Array
+             * @param {Array} array The array to inspect.
+             * @param {*} value The value to search for.
+             * @param {number} [fromIndex=array.length-1] The index to search from.
+             * @returns {number} Returns the index of the matched value, else `-1`.
+             * @example
+             *
+             * _.lastIndexOf([1, 2, 1, 2], 2);
+             * // => 3
+             *
+             * // Search from the `fromIndex`.
+             * _.lastIndexOf([1, 2, 1, 2], 2, 2);
+             * // => 1
+             */
+            function lastIndexOf(array, value, fromIndex) {
+              var length = array == null ? 0 : array.length;
+              if (!length) {
+                return -1;
+              }
+              var index = length;
+              if (fromIndex !== undefined) {
+                index = toInteger(fromIndex);
+                index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1);
+              }
+              return value === value
+                ? strictLastIndexOf(array, value, index)
+                : baseFindIndex(array, baseIsNaN, index, true);
+            }
+
+            /**
+             * Gets the element at index `n` of `array`. If `n` is negative, the nth
+             * element from the end is returned.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.11.0
+             * @category Array
+             * @param {Array} array The array to query.
+             * @param {number} [n=0] The index of the element to return.
+             * @returns {*} Returns the nth element of `array`.
+             * @example
+             *
+             * var array = ['a', 'b', 'c', 'd'];
+             *
+             * _.nth(array, 1);
+             * // => 'b'
+             *
+             * _.nth(array, -2);
+             * // => 'c';
+             */
+            function nth(array, n) {
+              return array && array.length ? baseNth(array, toInteger(n)) : undefined;
+            }
+
+            /**
+             * Removes all given values from `array` using
+             * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+             * for equality comparisons.
+             *
+             * **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove`
+             * to remove elements from an array by predicate.
+             *
+             * @static
+             * @memberOf _
+             * @since 2.0.0
+             * @category Array
+             * @param {Array} array The array to modify.
+             * @param {...*} [values] The values to remove.
+             * @returns {Array} Returns `array`.
+             * @example
+             *
+             * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
+             *
+             * _.pull(array, 'a', 'c');
+             * console.log(array);
+             * // => ['b', 'b']
+             */
+            var pull = baseRest(pullAll);
+
+            /**
+             * This method is like `_.pull` except that it accepts an array of values to remove.
+             *
+             * **Note:** Unlike `_.difference`, this method mutates `array`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {Array} array The array to modify.
+             * @param {Array} values The values to remove.
+             * @returns {Array} Returns `array`.
+             * @example
+             *
+             * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
+             *
+             * _.pullAll(array, ['a', 'c']);
+             * console.log(array);
+             * // => ['b', 'b']
+             */
+            function pullAll(array, values) {
+              return array && array.length && values && values.length ? basePullAll(array, values) : array;
+            }
+
+            /**
+             * This method is like `_.pullAll` except that it accepts `iteratee` which is
+             * invoked for each element of `array` and `values` to generate the criterion
+             * by which they're compared. The iteratee is invoked with one argument: (value).
+             *
+             * **Note:** Unlike `_.differenceBy`, this method mutates `array`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {Array} array The array to modify.
+             * @param {Array} values The values to remove.
+             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+             * @returns {Array} Returns `array`.
+             * @example
+             *
+             * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }];
+             *
+             * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x');
+             * console.log(array);
+             * // => [{ 'x': 2 }]
+             */
+            function pullAllBy(array, values, iteratee) {
+              return array && array.length && values && values.length
+                ? basePullAll(array, values, getIteratee(iteratee, 2))
+                : array;
+            }
+
+            /**
+             * This method is like `_.pullAll` except that it accepts `comparator` which
+             * is invoked to compare elements of `array` to `values`. The comparator is
+             * invoked with two arguments: (arrVal, othVal).
+             *
+             * **Note:** Unlike `_.differenceWith`, this method mutates `array`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.6.0
+             * @category Array
+             * @param {Array} array The array to modify.
+             * @param {Array} values The values to remove.
+             * @param {Function} [comparator] The comparator invoked per element.
+             * @returns {Array} Returns `array`.
+             * @example
+             *
+             * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }];
+             *
+             * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual);
+             * console.log(array);
+             * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }]
+             */
+            function pullAllWith(array, values, comparator) {
+              return array && array.length && values && values.length
+                ? basePullAll(array, values, undefined, comparator)
+                : array;
+            }
+
+            /**
+             * Removes elements from `array` corresponding to `indexes` and returns an
+             * array of removed elements.
+             *
+             * **Note:** Unlike `_.at`, this method mutates `array`.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Array
+             * @param {Array} array The array to modify.
+             * @param {...(number|number[])} [indexes] The indexes of elements to remove.
+             * @returns {Array} Returns the new array of removed elements.
+             * @example
+             *
+             * var array = ['a', 'b', 'c', 'd'];
+             * var pulled = _.pullAt(array, [1, 3]);
+             *
+             * console.log(array);
+             * // => ['a', 'c']
+             *
+             * console.log(pulled);
+             * // => ['b', 'd']
+             */
+            var pullAt = flatRest(function (array, indexes) {
+              var length = array == null ? 0 : array.length,
+                result = baseAt(array, indexes);
+
+              basePullAt(
+                array,
+                arrayMap(indexes, function (index) {
+                  return isIndex(index, length) ? +index : index;
+                }).sort(compareAscending)
+              );
+
+              return result;
+            });
+
+            /**
+             * Removes all elements from `array` that `predicate` returns truthy for
+             * and returns an array of the removed elements. The predicate is invoked
+             * with three arguments: (value, index, array).
+             *
+             * **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull`
+             * to pull elements from an array by value.
+             *
+             * @static
+             * @memberOf _
+             * @since 2.0.0
+             * @category Array
+             * @param {Array} array The array to modify.
+             * @param {Function} [predicate=_.identity] The function invoked per iteration.
+             * @returns {Array} Returns the new array of removed elements.
+             * @example
+             *
+             * var array = [1, 2, 3, 4];
+             * var evens = _.remove(array, function(n) {
+             *   return n % 2 == 0;
+             * });
+             *
+             * console.log(array);
+             * // => [1, 3]
+             *
+             * console.log(evens);
+             * // => [2, 4]
+             */
+            function remove(array, predicate) {
+              var result = [];
+              if (!(array && array.length)) {
+                return result;
+              }
+              var index = -1,
+                indexes = [],
+                length = array.length;
+
+              predicate = getIteratee(predicate, 3);
+              while (++index < length) {
+                var value = array[index];
+                if (predicate(value, index, array)) {
+                  result.push(value);
+                  indexes.push(index);
+                }
+              }
+              basePullAt(array, indexes);
+              return result;
+            }
+
+            /**
+             * Reverses `array` so that the first element becomes the last, the second
+             * element becomes the second to last, and so on.
+             *
+             * **Note:** This method mutates `array` and is based on
+             * [`Array#reverse`](https://mdn.io/Array/reverse).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {Array} array The array to modify.
+             * @returns {Array} Returns `array`.
+             * @example
+             *
+             * var array = [1, 2, 3];
+             *
+             * _.reverse(array);
+             * // => [3, 2, 1]
+             *
+             * console.log(array);
+             * // => [3, 2, 1]
+             */
+            function reverse(array) {
+              return array == null ? array : nativeReverse.call(array);
+            }
+
+            /**
+             * Creates a slice of `array` from `start` up to, but not including, `end`.
+             *
+             * **Note:** This method is used instead of
+             * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are
+             * returned.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Array
+             * @param {Array} array The array to slice.
+             * @param {number} [start=0] The start position.
+             * @param {number} [end=array.length] The end position.
+             * @returns {Array} Returns the slice of `array`.
+             */
+            function slice(array, start, end) {
+              var length = array == null ? 0 : array.length;
+              if (!length) {
+                return [];
+              }
+              if (end && typeof end != 'number' && isIterateeCall(array, start, end)) {
+                start = 0;
+                end = length;
+              } else {
+                start = start == null ? 0 : toInteger(start);
+                end = end === undefined ? length : toInteger(end);
+              }
+              return baseSlice(array, start, end);
+            }
+
+            /**
+             * Uses a binary search to determine the lowest index at which `value`
+             * should be inserted into `array` in order to maintain its sort order.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Array
+             * @param {Array} array The sorted array to inspect.
+             * @param {*} value The value to evaluate.
+             * @returns {number} Returns the index at which `value` should be inserted
+             *  into `array`.
+             * @example
+             *
+             * _.sortedIndex([30, 50], 40);
+             * // => 1
+             */
+            function sortedIndex(array, value) {
+              return baseSortedIndex(array, value);
+            }
+
+            /**
+             * This method is like `_.sortedIndex` except that it accepts `iteratee`
+             * which is invoked for `value` and each element of `array` to compute their
+             * sort ranking. The iteratee is invoked with one argument: (value).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {Array} array The sorted array to inspect.
+             * @param {*} value The value to evaluate.
+             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+             * @returns {number} Returns the index at which `value` should be inserted
+             *  into `array`.
+             * @example
+             *
+             * var objects = [{ 'x': 4 }, { 'x': 5 }];
+             *
+             * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
+             * // => 0
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.sortedIndexBy(objects, { 'x': 4 }, 'x');
+             * // => 0
+             */
+            function sortedIndexBy(array, value, iteratee) {
+              return baseSortedIndexBy(array, value, getIteratee(iteratee, 2));
+            }
+
+            /**
+             * This method is like `_.indexOf` except that it performs a binary
+             * search on a sorted `array`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {Array} array The array to inspect.
+             * @param {*} value The value to search for.
+             * @returns {number} Returns the index of the matched value, else `-1`.
+             * @example
+             *
+             * _.sortedIndexOf([4, 5, 5, 5, 6], 5);
+             * // => 1
+             */
+            function sortedIndexOf(array, value) {
+              var length = array == null ? 0 : array.length;
+              if (length) {
+                var index = baseSortedIndex(array, value);
+                if (index < length && eq(array[index], value)) {
+                  return index;
+                }
+              }
+              return -1;
+            }
+
+            /**
+             * This method is like `_.sortedIndex` except that it returns the highest
+             * index at which `value` should be inserted into `array` in order to
+             * maintain its sort order.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Array
+             * @param {Array} array The sorted array to inspect.
+             * @param {*} value The value to evaluate.
+             * @returns {number} Returns the index at which `value` should be inserted
+             *  into `array`.
+             * @example
+             *
+             * _.sortedLastIndex([4, 5, 5, 5, 6], 5);
+             * // => 4
+             */
+            function sortedLastIndex(array, value) {
+              return baseSortedIndex(array, value, true);
+            }
+
+            /**
+             * This method is like `_.sortedLastIndex` except that it accepts `iteratee`
+             * which is invoked for `value` and each element of `array` to compute their
+             * sort ranking. The iteratee is invoked with one argument: (value).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {Array} array The sorted array to inspect.
+             * @param {*} value The value to evaluate.
+             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+             * @returns {number} Returns the index at which `value` should be inserted
+             *  into `array`.
+             * @example
+             *
+             * var objects = [{ 'x': 4 }, { 'x': 5 }];
+             *
+             * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
+             * // => 1
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x');
+             * // => 1
+             */
+            function sortedLastIndexBy(array, value, iteratee) {
+              return baseSortedIndexBy(array, value, getIteratee(iteratee, 2), true);
+            }
+
+            /**
+             * This method is like `_.lastIndexOf` except that it performs a binary
+             * search on a sorted `array`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {Array} array The array to inspect.
+             * @param {*} value The value to search for.
+             * @returns {number} Returns the index of the matched value, else `-1`.
+             * @example
+             *
+             * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5);
+             * // => 3
+             */
+            function sortedLastIndexOf(array, value) {
+              var length = array == null ? 0 : array.length;
+              if (length) {
+                var index = baseSortedIndex(array, value, true) - 1;
+                if (eq(array[index], value)) {
+                  return index;
+                }
+              }
+              return -1;
+            }
+
+            /**
+             * This method is like `_.uniq` except that it's designed and optimized
+             * for sorted arrays.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {Array} array The array to inspect.
+             * @returns {Array} Returns the new duplicate free array.
+             * @example
+             *
+             * _.sortedUniq([1, 1, 2]);
+             * // => [1, 2]
+             */
+            function sortedUniq(array) {
+              return array && array.length ? baseSortedUniq(array) : [];
+            }
+
+            /**
+             * This method is like `_.uniqBy` except that it's designed and optimized
+             * for sorted arrays.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {Array} array The array to inspect.
+             * @param {Function} [iteratee] The iteratee invoked per element.
+             * @returns {Array} Returns the new duplicate free array.
+             * @example
+             *
+             * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor);
+             * // => [1.1, 2.3]
+             */
+            function sortedUniqBy(array, iteratee) {
+              return array && array.length ? baseSortedUniq(array, getIteratee(iteratee, 2)) : [];
+            }
+
+            /**
+             * Gets all but the first element of `array`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {Array} array The array to query.
+             * @returns {Array} Returns the slice of `array`.
+             * @example
+             *
+             * _.tail([1, 2, 3]);
+             * // => [2, 3]
+             */
+            function tail(array) {
+              var length = array == null ? 0 : array.length;
+              return length ? baseSlice(array, 1, length) : [];
+            }
+
+            /**
+             * Creates a slice of `array` with `n` elements taken from the beginning.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Array
+             * @param {Array} array The array to query.
+             * @param {number} [n=1] The number of elements to take.
+             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+             * @returns {Array} Returns the slice of `array`.
+             * @example
+             *
+             * _.take([1, 2, 3]);
+             * // => [1]
+             *
+             * _.take([1, 2, 3], 2);
+             * // => [1, 2]
+             *
+             * _.take([1, 2, 3], 5);
+             * // => [1, 2, 3]
+             *
+             * _.take([1, 2, 3], 0);
+             * // => []
+             */
+            function take(array, n, guard) {
+              if (!(array && array.length)) {
+                return [];
+              }
+              n = guard || n === undefined ? 1 : toInteger(n);
+              return baseSlice(array, 0, n < 0 ? 0 : n);
+            }
+
+            /**
+             * Creates a slice of `array` with `n` elements taken from the end.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Array
+             * @param {Array} array The array to query.
+             * @param {number} [n=1] The number of elements to take.
+             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+             * @returns {Array} Returns the slice of `array`.
+             * @example
+             *
+             * _.takeRight([1, 2, 3]);
+             * // => [3]
+             *
+             * _.takeRight([1, 2, 3], 2);
+             * // => [2, 3]
+             *
+             * _.takeRight([1, 2, 3], 5);
+             * // => [1, 2, 3]
+             *
+             * _.takeRight([1, 2, 3], 0);
+             * // => []
+             */
+            function takeRight(array, n, guard) {
+              var length = array == null ? 0 : array.length;
+              if (!length) {
+                return [];
+              }
+              n = guard || n === undefined ? 1 : toInteger(n);
+              n = length - n;
+              return baseSlice(array, n < 0 ? 0 : n, length);
+            }
+
+            /**
+             * Creates a slice of `array` with elements taken from the end. Elements are
+             * taken until `predicate` returns falsey. The predicate is invoked with
+             * three arguments: (value, index, array).
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Array
+             * @param {Array} array The array to query.
+             * @param {Function} [predicate=_.identity] The function invoked per iteration.
+             * @returns {Array} Returns the slice of `array`.
+             * @example
+             *
+             * var users = [
+             *   { 'user': 'barney',  'active': true },
+             *   { 'user': 'fred',    'active': false },
+             *   { 'user': 'pebbles', 'active': false }
+             * ];
+             *
+             * _.takeRightWhile(users, function(o) { return !o.active; });
+             * // => objects for ['fred', 'pebbles']
+             *
+             * // The `_.matches` iteratee shorthand.
+             * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false });
+             * // => objects for ['pebbles']
+             *
+             * // The `_.matchesProperty` iteratee shorthand.
+             * _.takeRightWhile(users, ['active', false]);
+             * // => objects for ['fred', 'pebbles']
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.takeRightWhile(users, 'active');
+             * // => []
+             */
+            function takeRightWhile(array, predicate) {
+              return array && array.length ? baseWhile(array, getIteratee(predicate, 3), false, true) : [];
+            }
+
+            /**
+             * Creates a slice of `array` with elements taken from the beginning. Elements
+             * are taken until `predicate` returns falsey. The predicate is invoked with
+             * three arguments: (value, index, array).
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Array
+             * @param {Array} array The array to query.
+             * @param {Function} [predicate=_.identity] The function invoked per iteration.
+             * @returns {Array} Returns the slice of `array`.
+             * @example
+             *
+             * var users = [
+             *   { 'user': 'barney',  'active': false },
+             *   { 'user': 'fred',    'active': false },
+             *   { 'user': 'pebbles', 'active': true }
+             * ];
+             *
+             * _.takeWhile(users, function(o) { return !o.active; });
+             * // => objects for ['barney', 'fred']
+             *
+             * // The `_.matches` iteratee shorthand.
+             * _.takeWhile(users, { 'user': 'barney', 'active': false });
+             * // => objects for ['barney']
+             *
+             * // The `_.matchesProperty` iteratee shorthand.
+             * _.takeWhile(users, ['active', false]);
+             * // => objects for ['barney', 'fred']
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.takeWhile(users, 'active');
+             * // => []
+             */
+            function takeWhile(array, predicate) {
+              return array && array.length ? baseWhile(array, getIteratee(predicate, 3)) : [];
+            }
+
+            /**
+             * Creates an array of unique values, in order, from all given arrays using
+             * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+             * for equality comparisons.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Array
+             * @param {...Array} [arrays] The arrays to inspect.
+             * @returns {Array} Returns the new array of combined values.
+             * @example
+             *
+             * _.union([2], [1, 2]);
+             * // => [2, 1]
+             */
+            var union = baseRest(function (arrays) {
+              return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true));
+            });
+
+            /**
+             * This method is like `_.union` except that it accepts `iteratee` which is
+             * invoked for each element of each `arrays` to generate the criterion by
+             * which uniqueness is computed. Result values are chosen from the first
+             * array in which the value occurs. The iteratee is invoked with one argument:
+             * (value).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {...Array} [arrays] The arrays to inspect.
+             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+             * @returns {Array} Returns the new array of combined values.
+             * @example
+             *
+             * _.unionBy([2.1], [1.2, 2.3], Math.floor);
+             * // => [2.1, 1.2]
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
+             * // => [{ 'x': 1 }, { 'x': 2 }]
+             */
+            var unionBy = baseRest(function (arrays) {
+              var iteratee = last(arrays);
+              if (isArrayLikeObject(iteratee)) {
+                iteratee = undefined;
+              }
+              return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee, 2));
+            });
+
+            /**
+             * This method is like `_.union` except that it accepts `comparator` which
+             * is invoked to compare elements of `arrays`. Result values are chosen from
+             * the first array in which the value occurs. The comparator is invoked
+             * with two arguments: (arrVal, othVal).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {...Array} [arrays] The arrays to inspect.
+             * @param {Function} [comparator] The comparator invoked per element.
+             * @returns {Array} Returns the new array of combined values.
+             * @example
+             *
+             * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
+             * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
+             *
+             * _.unionWith(objects, others, _.isEqual);
+             * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
+             */
+            var unionWith = baseRest(function (arrays) {
+              var comparator = last(arrays);
+              comparator = typeof comparator == 'function' ? comparator : undefined;
+              return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator);
+            });
+
+            /**
+             * Creates a duplicate-free version of an array, using
+             * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+             * for equality comparisons, in which only the first occurrence of each element
+             * is kept. The order of result values is determined by the order they occur
+             * in the array.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Array
+             * @param {Array} array The array to inspect.
+             * @returns {Array} Returns the new duplicate free array.
+             * @example
+             *
+             * _.uniq([2, 1, 2]);
+             * // => [2, 1]
+             */
+            function uniq(array) {
+              return array && array.length ? baseUniq(array) : [];
+            }
+
+            /**
+             * This method is like `_.uniq` except that it accepts `iteratee` which is
+             * invoked for each element in `array` to generate the criterion by which
+             * uniqueness is computed. The order of result values is determined by the
+             * order they occur in the array. The iteratee is invoked with one argument:
+             * (value).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {Array} array The array to inspect.
+             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+             * @returns {Array} Returns the new duplicate free array.
+             * @example
+             *
+             * _.uniqBy([2.1, 1.2, 2.3], Math.floor);
+             * // => [2.1, 1.2]
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
+             * // => [{ 'x': 1 }, { 'x': 2 }]
+             */
+            function uniqBy(array, iteratee) {
+              return array && array.length ? baseUniq(array, getIteratee(iteratee, 2)) : [];
+            }
+
+            /**
+             * This method is like `_.uniq` except that it accepts `comparator` which
+             * is invoked to compare elements of `array`. The order of result values is
+             * determined by the order they occur in the array.The comparator is invoked
+             * with two arguments: (arrVal, othVal).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {Array} array The array to inspect.
+             * @param {Function} [comparator] The comparator invoked per element.
+             * @returns {Array} Returns the new duplicate free array.
+             * @example
+             *
+             * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
+             *
+             * _.uniqWith(objects, _.isEqual);
+             * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
+             */
+            function uniqWith(array, comparator) {
+              comparator = typeof comparator == 'function' ? comparator : undefined;
+              return array && array.length ? baseUniq(array, undefined, comparator) : [];
+            }
+
+            /**
+             * This method is like `_.zip` except that it accepts an array of grouped
+             * elements and creates an array regrouping the elements to their pre-zip
+             * configuration.
+             *
+             * @static
+             * @memberOf _
+             * @since 1.2.0
+             * @category Array
+             * @param {Array} array The array of grouped elements to process.
+             * @returns {Array} Returns the new array of regrouped elements.
+             * @example
+             *
+             * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]);
+             * // => [['a', 1, true], ['b', 2, false]]
+             *
+             * _.unzip(zipped);
+             * // => [['a', 'b'], [1, 2], [true, false]]
+             */
+            function unzip(array) {
+              if (!(array && array.length)) {
+                return [];
+              }
+              var length = 0;
+              array = arrayFilter(array, function (group) {
+                if (isArrayLikeObject(group)) {
+                  length = nativeMax(group.length, length);
+                  return true;
+                }
+              });
+              return baseTimes(length, function (index) {
+                return arrayMap(array, baseProperty(index));
+              });
+            }
+
+            /**
+             * This method is like `_.unzip` except that it accepts `iteratee` to specify
+             * how regrouped values should be combined. The iteratee is invoked with the
+             * elements of each group: (...group).
+             *
+             * @static
+             * @memberOf _
+             * @since 3.8.0
+             * @category Array
+             * @param {Array} array The array of grouped elements to process.
+             * @param {Function} [iteratee=_.identity] The function to combine
+             *  regrouped values.
+             * @returns {Array} Returns the new array of regrouped elements.
+             * @example
+             *
+             * var zipped = _.zip([1, 2], [10, 20], [100, 200]);
+             * // => [[1, 10, 100], [2, 20, 200]]
+             *
+             * _.unzipWith(zipped, _.add);
+             * // => [3, 30, 300]
+             */
+            function unzipWith(array, iteratee) {
+              if (!(array && array.length)) {
+                return [];
+              }
+              var result = unzip(array);
+              if (iteratee == null) {
+                return result;
+              }
+              return arrayMap(result, function (group) {
+                return apply(iteratee, undefined, group);
+              });
+            }
+
+            /**
+             * Creates an array excluding all given values using
+             * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+             * for equality comparisons.
+             *
+             * **Note:** Unlike `_.pull`, this method returns a new array.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Array
+             * @param {Array} array The array to inspect.
+             * @param {...*} [values] The values to exclude.
+             * @returns {Array} Returns the new array of filtered values.
+             * @see _.difference, _.xor
+             * @example
+             *
+             * _.without([2, 1, 2, 3], 1, 2);
+             * // => [3]
+             */
+            var without = baseRest(function (array, values) {
+              return isArrayLikeObject(array) ? baseDifference(array, values) : [];
+            });
+
+            /**
+             * Creates an array of unique values that is the
+             * [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference)
+             * of the given arrays. The order of result values is determined by the order
+             * they occur in the arrays.
+             *
+             * @static
+             * @memberOf _
+             * @since 2.4.0
+             * @category Array
+             * @param {...Array} [arrays] The arrays to inspect.
+             * @returns {Array} Returns the new array of filtered values.
+             * @see _.difference, _.without
+             * @example
+             *
+             * _.xor([2, 1], [2, 3]);
+             * // => [1, 3]
+             */
+            var xor = baseRest(function (arrays) {
+              return baseXor(arrayFilter(arrays, isArrayLikeObject));
+            });
+
+            /**
+             * This method is like `_.xor` except that it accepts `iteratee` which is
+             * invoked for each element of each `arrays` to generate the criterion by
+             * which by which they're compared. The order of result values is determined
+             * by the order they occur in the arrays. The iteratee is invoked with one
+             * argument: (value).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {...Array} [arrays] The arrays to inspect.
+             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+             * @returns {Array} Returns the new array of filtered values.
+             * @example
+             *
+             * _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor);
+             * // => [1.2, 3.4]
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
+             * // => [{ 'x': 2 }]
+             */
+            var xorBy = baseRest(function (arrays) {
+              var iteratee = last(arrays);
+              if (isArrayLikeObject(iteratee)) {
+                iteratee = undefined;
+              }
+              return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee, 2));
+            });
+
+            /**
+             * This method is like `_.xor` except that it accepts `comparator` which is
+             * invoked to compare elements of `arrays`. The order of result values is
+             * determined by the order they occur in the arrays. The comparator is invoked
+             * with two arguments: (arrVal, othVal).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Array
+             * @param {...Array} [arrays] The arrays to inspect.
+             * @param {Function} [comparator] The comparator invoked per element.
+             * @returns {Array} Returns the new array of filtered values.
+             * @example
+             *
+             * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
+             * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
+             *
+             * _.xorWith(objects, others, _.isEqual);
+             * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
+             */
+            var xorWith = baseRest(function (arrays) {
+              var comparator = last(arrays);
+              comparator = typeof comparator == 'function' ? comparator : undefined;
+              return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator);
+            });
+
+            /**
+             * Creates an array of grouped elements, the first of which contains the
+             * first elements of the given arrays, the second of which contains the
+             * second elements of the given arrays, and so on.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Array
+             * @param {...Array} [arrays] The arrays to process.
+             * @returns {Array} Returns the new array of grouped elements.
+             * @example
+             *
+             * _.zip(['a', 'b'], [1, 2], [true, false]);
+             * // => [['a', 1, true], ['b', 2, false]]
+             */
+            var zip = baseRest(unzip);
+
+            /**
+             * This method is like `_.fromPairs` except that it accepts two arrays,
+             * one of property identifiers and one of corresponding values.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.4.0
+             * @category Array
+             * @param {Array} [props=[]] The property identifiers.
+             * @param {Array} [values=[]] The property values.
+             * @returns {Object} Returns the new object.
+             * @example
+             *
+             * _.zipObject(['a', 'b'], [1, 2]);
+             * // => { 'a': 1, 'b': 2 }
+             */
+            function zipObject(props, values) {
+              return baseZipObject(props || [], values || [], assignValue);
+            }
+
+            /**
+             * This method is like `_.zipObject` except that it supports property paths.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.1.0
+             * @category Array
+             * @param {Array} [props=[]] The property identifiers.
+             * @param {Array} [values=[]] The property values.
+             * @returns {Object} Returns the new object.
+             * @example
+             *
+             * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]);
+             * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } }
+             */
+            function zipObjectDeep(props, values) {
+              return baseZipObject(props || [], values || [], baseSet);
+            }
+
+            /**
+             * This method is like `_.zip` except that it accepts `iteratee` to specify
+             * how grouped values should be combined. The iteratee is invoked with the
+             * elements of each group: (...group).
+             *
+             * @static
+             * @memberOf _
+             * @since 3.8.0
+             * @category Array
+             * @param {...Array} [arrays] The arrays to process.
+             * @param {Function} [iteratee=_.identity] The function to combine
+             *  grouped values.
+             * @returns {Array} Returns the new array of grouped elements.
+             * @example
+             *
+             * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) {
+             *   return a + b + c;
+             * });
+             * // => [111, 222]
+             */
+            var zipWith = baseRest(function (arrays) {
+              var length = arrays.length,
+                iteratee = length > 1 ? arrays[length - 1] : undefined;
+
+              iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined;
+              return unzipWith(arrays, iteratee);
+            });
+
+            /*------------------------------------------------------------------------*/
+
+            /**
+             * Creates a `lodash` wrapper instance that wraps `value` with explicit method
+             * chain sequences enabled. The result of such sequences must be unwrapped
+             * with `_#value`.
+             *
+             * @static
+             * @memberOf _
+             * @since 1.3.0
+             * @category Seq
+             * @param {*} value The value to wrap.
+             * @returns {Object} Returns the new `lodash` wrapper instance.
+             * @example
+             *
+             * var users = [
+             *   { 'user': 'barney',  'age': 36 },
+             *   { 'user': 'fred',    'age': 40 },
+             *   { 'user': 'pebbles', 'age': 1 }
+             * ];
+             *
+             * var youngest = _
+             *   .chain(users)
+             *   .sortBy('age')
+             *   .map(function(o) {
+             *     return o.user + ' is ' + o.age;
+             *   })
+             *   .head()
+             *   .value();
+             * // => 'pebbles is 1'
+             */
+            function chain(value) {
+              var result = lodash(value);
+              result.__chain__ = true;
+              return result;
+            }
+
+            /**
+             * This method invokes `interceptor` and returns `value`. The interceptor
+             * is invoked with one argument; (value). The purpose of this method is to
+             * "tap into" a method chain sequence in order to modify intermediate results.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Seq
+             * @param {*} value The value to provide to `interceptor`.
+             * @param {Function} interceptor The function to invoke.
+             * @returns {*} Returns `value`.
+             * @example
+             *
+             * _([1, 2, 3])
+             *  .tap(function(array) {
+             *    // Mutate input array.
+             *    array.pop();
+             *  })
+             *  .reverse()
+             *  .value();
+             * // => [2, 1]
+             */
+            function tap(value, interceptor) {
+              interceptor(value);
+              return value;
+            }
+
+            /**
+             * This method is like `_.tap` except that it returns the result of `interceptor`.
+             * The purpose of this method is to "pass thru" values replacing intermediate
+             * results in a method chain sequence.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Seq
+             * @param {*} value The value to provide to `interceptor`.
+             * @param {Function} interceptor The function to invoke.
+             * @returns {*} Returns the result of `interceptor`.
+             * @example
+             *
+             * _('  abc  ')
+             *  .chain()
+             *  .trim()
+             *  .thru(function(value) {
+             *    return [value];
+             *  })
+             *  .value();
+             * // => ['abc']
+             */
+            function thru(value, interceptor) {
+              return interceptor(value);
+            }
+
+            /**
+             * This method is the wrapper version of `_.at`.
+             *
+             * @name at
+             * @memberOf _
+             * @since 1.0.0
+             * @category Seq
+             * @param {...(string|string[])} [paths] The property paths to pick.
+             * @returns {Object} Returns the new `lodash` wrapper instance.
+             * @example
+             *
+             * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
+             *
+             * _(object).at(['a[0].b.c', 'a[1]']).value();
+             * // => [3, 4]
+             */
+            var wrapperAt = flatRest(function (paths) {
+              var length = paths.length,
+                start = length ? paths[0] : 0,
+                value = this.__wrapped__,
+                interceptor = function (object) {
+                  return baseAt(object, paths);
+                };
+
+              if (
+                length > 1 ||
+                this.__actions__.length ||
+                !(value instanceof LazyWrapper) ||
+                !isIndex(start)
+              ) {
+                return this.thru(interceptor);
+              }
+              value = value.slice(start, +start + (length ? 1 : 0));
+              value.__actions__.push({
+                func: thru,
+                args: [interceptor],
+                thisArg: undefined,
+              });
+              return new LodashWrapper(value, this.__chain__).thru(function (array) {
+                if (length && !array.length) {
+                  array.push(undefined);
+                }
+                return array;
+              });
+            });
+
+            /**
+             * Creates a `lodash` wrapper instance with explicit method chain sequences enabled.
+             *
+             * @name chain
+             * @memberOf _
+             * @since 0.1.0
+             * @category Seq
+             * @returns {Object} Returns the new `lodash` wrapper instance.
+             * @example
+             *
+             * var users = [
+             *   { 'user': 'barney', 'age': 36 },
+             *   { 'user': 'fred',   'age': 40 }
+             * ];
+             *
+             * // A sequence without explicit chaining.
+             * _(users).head();
+             * // => { 'user': 'barney', 'age': 36 }
+             *
+             * // A sequence with explicit chaining.
+             * _(users)
+             *   .chain()
+             *   .head()
+             *   .pick('user')
+             *   .value();
+             * // => { 'user': 'barney' }
+             */
+            function wrapperChain() {
+              return chain(this);
+            }
+
+            /**
+             * Executes the chain sequence and returns the wrapped result.
+             *
+             * @name commit
+             * @memberOf _
+             * @since 3.2.0
+             * @category Seq
+             * @returns {Object} Returns the new `lodash` wrapper instance.
+             * @example
+             *
+             * var array = [1, 2];
+             * var wrapped = _(array).push(3);
+             *
+             * console.log(array);
+             * // => [1, 2]
+             *
+             * wrapped = wrapped.commit();
+             * console.log(array);
+             * // => [1, 2, 3]
+             *
+             * wrapped.last();
+             * // => 3
+             *
+             * console.log(array);
+             * // => [1, 2, 3]
+             */
+            function wrapperCommit() {
+              return new LodashWrapper(this.value(), this.__chain__);
+            }
+
+            /**
+             * Gets the next value on a wrapped object following the
+             * [iterator protocol](https://mdn.io/iteration_protocols#iterator).
+             *
+             * @name next
+             * @memberOf _
+             * @since 4.0.0
+             * @category Seq
+             * @returns {Object} Returns the next iterator value.
+             * @example
+             *
+             * var wrapped = _([1, 2]);
+             *
+             * wrapped.next();
+             * // => { 'done': false, 'value': 1 }
+             *
+             * wrapped.next();
+             * // => { 'done': false, 'value': 2 }
+             *
+             * wrapped.next();
+             * // => { 'done': true, 'value': undefined }
+             */
+            function wrapperNext() {
+              if (this.__values__ === undefined) {
+                this.__values__ = toArray(this.value());
+              }
+              var done = this.__index__ >= this.__values__.length,
+                value = done ? undefined : this.__values__[this.__index__++];
+
+              return { done: done, value: value };
+            }
+
+            /**
+             * Enables the wrapper to be iterable.
+             *
+             * @name Symbol.iterator
+             * @memberOf _
+             * @since 4.0.0
+             * @category Seq
+             * @returns {Object} Returns the wrapper object.
+             * @example
+             *
+             * var wrapped = _([1, 2]);
+             *
+             * wrapped[Symbol.iterator]() === wrapped;
+             * // => true
+             *
+             * Array.from(wrapped);
+             * // => [1, 2]
+             */
+            function wrapperToIterator() {
+              return this;
+            }
+
+            /**
+             * Creates a clone of the chain sequence planting `value` as the wrapped value.
+             *
+             * @name plant
+             * @memberOf _
+             * @since 3.2.0
+             * @category Seq
+             * @param {*} value The value to plant.
+             * @returns {Object} Returns the new `lodash` wrapper instance.
+             * @example
+             *
+             * function square(n) {
+             *   return n * n;
+             * }
+             *
+             * var wrapped = _([1, 2]).map(square);
+             * var other = wrapped.plant([3, 4]);
+             *
+             * other.value();
+             * // => [9, 16]
+             *
+             * wrapped.value();
+             * // => [1, 4]
+             */
+            function wrapperPlant(value) {
+              var result,
+                parent = this;
+
+              while (parent instanceof baseLodash) {
+                var clone = wrapperClone(parent);
+                clone.__index__ = 0;
+                clone.__values__ = undefined;
+                if (result) {
+                  previous.__wrapped__ = clone;
+                } else {
+                  result = clone;
+                }
+                var previous = clone;
+                parent = parent.__wrapped__;
+              }
+              previous.__wrapped__ = value;
+              return result;
+            }
+
+            /**
+             * This method is the wrapper version of `_.reverse`.
+             *
+             * **Note:** This method mutates the wrapped array.
+             *
+             * @name reverse
+             * @memberOf _
+             * @since 0.1.0
+             * @category Seq
+             * @returns {Object} Returns the new `lodash` wrapper instance.
+             * @example
+             *
+             * var array = [1, 2, 3];
+             *
+             * _(array).reverse().value()
+             * // => [3, 2, 1]
+             *
+             * console.log(array);
+             * // => [3, 2, 1]
+             */
+            function wrapperReverse() {
+              var value = this.__wrapped__;
+              if (value instanceof LazyWrapper) {
+                var wrapped = value;
+                if (this.__actions__.length) {
+                  wrapped = new LazyWrapper(this);
+                }
+                wrapped = wrapped.reverse();
+                wrapped.__actions__.push({
+                  func: thru,
+                  args: [reverse],
+                  thisArg: undefined,
+                });
+                return new LodashWrapper(wrapped, this.__chain__);
+              }
+              return this.thru(reverse);
+            }
+
+            /**
+             * Executes the chain sequence to resolve the unwrapped value.
+             *
+             * @name value
+             * @memberOf _
+             * @since 0.1.0
+             * @alias toJSON, valueOf
+             * @category Seq
+             * @returns {*} Returns the resolved unwrapped value.
+             * @example
+             *
+             * _([1, 2, 3]).value();
+             * // => [1, 2, 3]
+             */
+            function wrapperValue() {
+              return baseWrapperValue(this.__wrapped__, this.__actions__);
+            }
+
+            /*------------------------------------------------------------------------*/
+
+            /**
+             * Creates an object composed of keys generated from the results of running
+             * each element of `collection` thru `iteratee`. The corresponding value of
+             * each key is the number of times the key was returned by `iteratee`. The
+             * iteratee is invoked with one argument: (value).
+             *
+             * @static
+             * @memberOf _
+             * @since 0.5.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
+             * @returns {Object} Returns the composed aggregate object.
+             * @example
+             *
+             * _.countBy([6.1, 4.2, 6.3], Math.floor);
+             * // => { '4': 1, '6': 2 }
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.countBy(['one', 'two', 'three'], 'length');
+             * // => { '3': 2, '5': 1 }
+             */
+            var countBy = createAggregator(function (result, value, key) {
+              if (hasOwnProperty.call(result, key)) {
+                ++result[key];
+              } else {
+                baseAssignValue(result, key, 1);
+              }
+            });
+
+            /**
+             * Checks if `predicate` returns truthy for **all** elements of `collection`.
+             * Iteration is stopped once `predicate` returns falsey. The predicate is
+             * invoked with three arguments: (value, index|key, collection).
+             *
+             * **Note:** This method returns `true` for
+             * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because
+             * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of
+             * elements of empty collections.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} [predicate=_.identity] The function invoked per iteration.
+             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+             * @returns {boolean} Returns `true` if all elements pass the predicate check,
+             *  else `false`.
+             * @example
+             *
+             * _.every([true, 1, null, 'yes'], Boolean);
+             * // => false
+             *
+             * var users = [
+             *   { 'user': 'barney', 'age': 36, 'active': false },
+             *   { 'user': 'fred',   'age': 40, 'active': false }
+             * ];
+             *
+             * // The `_.matches` iteratee shorthand.
+             * _.every(users, { 'user': 'barney', 'active': false });
+             * // => false
+             *
+             * // The `_.matchesProperty` iteratee shorthand.
+             * _.every(users, ['active', false]);
+             * // => true
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.every(users, 'active');
+             * // => false
+             */
+            function every(collection, predicate, guard) {
+              var func = isArray(collection) ? arrayEvery : baseEvery;
+              if (guard && isIterateeCall(collection, predicate, guard)) {
+                predicate = undefined;
+              }
+              return func(collection, getIteratee(predicate, 3));
+            }
+
+            /**
+             * Iterates over elements of `collection`, returning an array of all elements
+             * `predicate` returns truthy for. The predicate is invoked with three
+             * arguments: (value, index|key, collection).
+             *
+             * **Note:** Unlike `_.remove`, this method returns a new array.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} [predicate=_.identity] The function invoked per iteration.
+             * @returns {Array} Returns the new filtered array.
+             * @see _.reject
+             * @example
+             *
+             * var users = [
+             *   { 'user': 'barney', 'age': 36, 'active': true },
+             *   { 'user': 'fred',   'age': 40, 'active': false }
+             * ];
+             *
+             * _.filter(users, function(o) { return !o.active; });
+             * // => objects for ['fred']
+             *
+             * // The `_.matches` iteratee shorthand.
+             * _.filter(users, { 'age': 36, 'active': true });
+             * // => objects for ['barney']
+             *
+             * // The `_.matchesProperty` iteratee shorthand.
+             * _.filter(users, ['active', false]);
+             * // => objects for ['fred']
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.filter(users, 'active');
+             * // => objects for ['barney']
+             */
+            function filter(collection, predicate) {
+              var func = isArray(collection) ? arrayFilter : baseFilter;
+              return func(collection, getIteratee(predicate, 3));
+            }
+
+            /**
+             * Iterates over elements of `collection`, returning the first element
+             * `predicate` returns truthy for. The predicate is invoked with three
+             * arguments: (value, index|key, collection).
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to inspect.
+             * @param {Function} [predicate=_.identity] The function invoked per iteration.
+             * @param {number} [fromIndex=0] The index to search from.
+             * @returns {*} Returns the matched element, else `undefined`.
+             * @example
+             *
+             * var users = [
+             *   { 'user': 'barney',  'age': 36, 'active': true },
+             *   { 'user': 'fred',    'age': 40, 'active': false },
+             *   { 'user': 'pebbles', 'age': 1,  'active': true }
+             * ];
+             *
+             * _.find(users, function(o) { return o.age < 40; });
+             * // => object for 'barney'
+             *
+             * // The `_.matches` iteratee shorthand.
+             * _.find(users, { 'age': 1, 'active': true });
+             * // => object for 'pebbles'
+             *
+             * // The `_.matchesProperty` iteratee shorthand.
+             * _.find(users, ['active', false]);
+             * // => object for 'fred'
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.find(users, 'active');
+             * // => object for 'barney'
+             */
+            var find = createFind(findIndex);
+
+            /**
+             * This method is like `_.find` except that it iterates over elements of
+             * `collection` from right to left.
+             *
+             * @static
+             * @memberOf _
+             * @since 2.0.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to inspect.
+             * @param {Function} [predicate=_.identity] The function invoked per iteration.
+             * @param {number} [fromIndex=collection.length-1] The index to search from.
+             * @returns {*} Returns the matched element, else `undefined`.
+             * @example
+             *
+             * _.findLast([1, 2, 3, 4], function(n) {
+             *   return n % 2 == 1;
+             * });
+             * // => 3
+             */
+            var findLast = createFind(findLastIndex);
+
+            /**
+             * Creates a flattened array of values by running each element in `collection`
+             * thru `iteratee` and flattening the mapped results. The iteratee is invoked
+             * with three arguments: (value, index|key, collection).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+             * @returns {Array} Returns the new flattened array.
+             * @example
+             *
+             * function duplicate(n) {
+             *   return [n, n];
+             * }
+             *
+             * _.flatMap([1, 2], duplicate);
+             * // => [1, 1, 2, 2]
+             */
+            function flatMap(collection, iteratee) {
+              return baseFlatten(map(collection, iteratee), 1);
+            }
+
+            /**
+             * This method is like `_.flatMap` except that it recursively flattens the
+             * mapped results.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.7.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+             * @returns {Array} Returns the new flattened array.
+             * @example
+             *
+             * function duplicate(n) {
+             *   return [[[n, n]]];
+             * }
+             *
+             * _.flatMapDeep([1, 2], duplicate);
+             * // => [1, 1, 2, 2]
+             */
+            function flatMapDeep(collection, iteratee) {
+              return baseFlatten(map(collection, iteratee), INFINITY);
+            }
+
+            /**
+             * This method is like `_.flatMap` except that it recursively flattens the
+             * mapped results up to `depth` times.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.7.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+             * @param {number} [depth=1] The maximum recursion depth.
+             * @returns {Array} Returns the new flattened array.
+             * @example
+             *
+             * function duplicate(n) {
+             *   return [[[n, n]]];
+             * }
+             *
+             * _.flatMapDepth([1, 2], duplicate, 2);
+             * // => [[1, 1], [2, 2]]
+             */
+            function flatMapDepth(collection, iteratee, depth) {
+              depth = depth === undefined ? 1 : toInteger(depth);
+              return baseFlatten(map(collection, iteratee), depth);
+            }
+
+            /**
+             * Iterates over elements of `collection` and invokes `iteratee` for each element.
+             * The iteratee is invoked with three arguments: (value, index|key, collection).
+             * Iteratee functions may exit iteration early by explicitly returning `false`.
+             *
+             * **Note:** As with other "Collections" methods, objects with a "length"
+             * property are iterated like arrays. To avoid this behavior use `_.forIn`
+             * or `_.forOwn` for object iteration.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @alias each
+             * @category Collection
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+             * @returns {Array|Object} Returns `collection`.
+             * @see _.forEachRight
+             * @example
+             *
+             * _.forEach([1, 2], function(value) {
+             *   console.log(value);
+             * });
+             * // => Logs `1` then `2`.
+             *
+             * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) {
+             *   console.log(key);
+             * });
+             * // => Logs 'a' then 'b' (iteration order is not guaranteed).
+             */
+            function forEach(collection, iteratee) {
+              var func = isArray(collection) ? arrayEach : baseEach;
+              return func(collection, getIteratee(iteratee, 3));
+            }
+
+            /**
+             * This method is like `_.forEach` except that it iterates over elements of
+             * `collection` from right to left.
+             *
+             * @static
+             * @memberOf _
+             * @since 2.0.0
+             * @alias eachRight
+             * @category Collection
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+             * @returns {Array|Object} Returns `collection`.
+             * @see _.forEach
+             * @example
+             *
+             * _.forEachRight([1, 2], function(value) {
+             *   console.log(value);
+             * });
+             * // => Logs `2` then `1`.
+             */
+            function forEachRight(collection, iteratee) {
+              var func = isArray(collection) ? arrayEachRight : baseEachRight;
+              return func(collection, getIteratee(iteratee, 3));
+            }
+
+            /**
+             * Creates an object composed of keys generated from the results of running
+             * each element of `collection` thru `iteratee`. The order of grouped values
+             * is determined by the order they occur in `collection`. The corresponding
+             * value of each key is an array of elements responsible for generating the
+             * key. The iteratee is invoked with one argument: (value).
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
+             * @returns {Object} Returns the composed aggregate object.
+             * @example
+             *
+             * _.groupBy([6.1, 4.2, 6.3], Math.floor);
+             * // => { '4': [4.2], '6': [6.1, 6.3] }
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.groupBy(['one', 'two', 'three'], 'length');
+             * // => { '3': ['one', 'two'], '5': ['three'] }
+             */
+            var groupBy = createAggregator(function (result, value, key) {
+              if (hasOwnProperty.call(result, key)) {
+                result[key].push(value);
+              } else {
+                baseAssignValue(result, key, [value]);
+              }
+            });
+
+            /**
+             * Checks if `value` is in `collection`. If `collection` is a string, it's
+             * checked for a substring of `value`, otherwise
+             * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+             * is used for equality comparisons. If `fromIndex` is negative, it's used as
+             * the offset from the end of `collection`.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Collection
+             * @param {Array|Object|string} collection The collection to inspect.
+             * @param {*} value The value to search for.
+             * @param {number} [fromIndex=0] The index to search from.
+             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
+             * @returns {boolean} Returns `true` if `value` is found, else `false`.
+             * @example
+             *
+             * _.includes([1, 2, 3], 1);
+             * // => true
+             *
+             * _.includes([1, 2, 3], 1, 2);
+             * // => false
+             *
+             * _.includes({ 'a': 1, 'b': 2 }, 1);
+             * // => true
+             *
+             * _.includes('abcd', 'bc');
+             * // => true
+             */
+            function includes(collection, value, fromIndex, guard) {
+              collection = isArrayLike(collection) ? collection : values(collection);
+              fromIndex = fromIndex && !guard ? toInteger(fromIndex) : 0;
+
+              var length = collection.length;
+              if (fromIndex < 0) {
+                fromIndex = nativeMax(length + fromIndex, 0);
+              }
+              return isString(collection)
+                ? fromIndex <= length && collection.indexOf(value, fromIndex) > -1
+                : !!length && baseIndexOf(collection, value, fromIndex) > -1;
+            }
+
+            /**
+             * Invokes the method at `path` of each element in `collection`, returning
+             * an array of the results of each invoked method. Any additional arguments
+             * are provided to each invoked method. If `path` is a function, it's invoked
+             * for, and `this` bound to, each element in `collection`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Array|Function|string} path The path of the method to invoke or
+             *  the function invoked per iteration.
+             * @param {...*} [args] The arguments to invoke each method with.
+             * @returns {Array} Returns the array of results.
+             * @example
+             *
+             * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort');
+             * // => [[1, 5, 7], [1, 2, 3]]
+             *
+             * _.invokeMap([123, 456], String.prototype.split, '');
+             * // => [['1', '2', '3'], ['4', '5', '6']]
+             */
+            var invokeMap = baseRest(function (collection, path, args) {
+              var index = -1,
+                isFunc = typeof path == 'function',
+                result = isArrayLike(collection) ? Array(collection.length) : [];
+
+              baseEach(collection, function (value) {
+                result[++index] = isFunc ? apply(path, value, args) : baseInvoke(value, path, args);
+              });
+              return result;
+            });
+
+            /**
+             * Creates an object composed of keys generated from the results of running
+             * each element of `collection` thru `iteratee`. The corresponding value of
+             * each key is the last element responsible for generating the key. The
+             * iteratee is invoked with one argument: (value).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
+             * @returns {Object} Returns the composed aggregate object.
+             * @example
+             *
+             * var array = [
+             *   { 'dir': 'left', 'code': 97 },
+             *   { 'dir': 'right', 'code': 100 }
+             * ];
+             *
+             * _.keyBy(array, function(o) {
+             *   return String.fromCharCode(o.code);
+             * });
+             * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
+             *
+             * _.keyBy(array, 'dir');
+             * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
+             */
+            var keyBy = createAggregator(function (result, value, key) {
+              baseAssignValue(result, key, value);
+            });
+
+            /**
+             * Creates an array of values by running each element in `collection` thru
+             * `iteratee`. The iteratee is invoked with three arguments:
+             * (value, index|key, collection).
+             *
+             * Many lodash methods are guarded to work as iteratees for methods like
+             * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`.
+             *
+             * The guarded methods are:
+             * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`,
+             * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`,
+             * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`,
+             * `template`, `trim`, `trimEnd`, `trimStart`, and `words`
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+             * @returns {Array} Returns the new mapped array.
+             * @example
+             *
+             * function square(n) {
+             *   return n * n;
+             * }
+             *
+             * _.map([4, 8], square);
+             * // => [16, 64]
+             *
+             * _.map({ 'a': 4, 'b': 8 }, square);
+             * // => [16, 64] (iteration order is not guaranteed)
+             *
+             * var users = [
+             *   { 'user': 'barney' },
+             *   { 'user': 'fred' }
+             * ];
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.map(users, 'user');
+             * // => ['barney', 'fred']
+             */
+            function map(collection, iteratee) {
+              var func = isArray(collection) ? arrayMap : baseMap;
+              return func(collection, getIteratee(iteratee, 3));
+            }
+
+            /**
+             * This method is like `_.sortBy` except that it allows specifying the sort
+             * orders of the iteratees to sort by. If `orders` is unspecified, all values
+             * are sorted in ascending order. Otherwise, specify an order of "desc" for
+             * descending or "asc" for ascending sort order of corresponding values.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]]
+             *  The iteratees to sort by.
+             * @param {string[]} [orders] The sort orders of `iteratees`.
+             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
+             * @returns {Array} Returns the new sorted array.
+             * @example
+             *
+             * var users = [
+             *   { 'user': 'fred',   'age': 48 },
+             *   { 'user': 'barney', 'age': 34 },
+             *   { 'user': 'fred',   'age': 40 },
+             *   { 'user': 'barney', 'age': 36 }
+             * ];
+             *
+             * // Sort by `user` in ascending order and by `age` in descending order.
+             * _.orderBy(users, ['user', 'age'], ['asc', 'desc']);
+             * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
+             */
+            function orderBy(collection, iteratees, orders, guard) {
+              if (collection == null) {
+                return [];
+              }
+              if (!isArray(iteratees)) {
+                iteratees = iteratees == null ? [] : [iteratees];
+              }
+              orders = guard ? undefined : orders;
+              if (!isArray(orders)) {
+                orders = orders == null ? [] : [orders];
+              }
+              return baseOrderBy(collection, iteratees, orders);
+            }
+
+            /**
+             * Creates an array of elements split into two groups, the first of which
+             * contains elements `predicate` returns truthy for, the second of which
+             * contains elements `predicate` returns falsey for. The predicate is
+             * invoked with one argument: (value).
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} [predicate=_.identity] The function invoked per iteration.
+             * @returns {Array} Returns the array of grouped elements.
+             * @example
+             *
+             * var users = [
+             *   { 'user': 'barney',  'age': 36, 'active': false },
+             *   { 'user': 'fred',    'age': 40, 'active': true },
+             *   { 'user': 'pebbles', 'age': 1,  'active': false }
+             * ];
+             *
+             * _.partition(users, function(o) { return o.active; });
+             * // => objects for [['fred'], ['barney', 'pebbles']]
+             *
+             * // The `_.matches` iteratee shorthand.
+             * _.partition(users, { 'age': 1, 'active': false });
+             * // => objects for [['pebbles'], ['barney', 'fred']]
+             *
+             * // The `_.matchesProperty` iteratee shorthand.
+             * _.partition(users, ['active', false]);
+             * // => objects for [['barney', 'pebbles'], ['fred']]
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.partition(users, 'active');
+             * // => objects for [['fred'], ['barney', 'pebbles']]
+             */
+            var partition = createAggregator(
+              function (result, value, key) {
+                result[key ? 0 : 1].push(value);
+              },
+              function () {
+                return [[], []];
+              }
+            );
+
+            /**
+             * Reduces `collection` to a value which is the accumulated result of running
+             * each element in `collection` thru `iteratee`, where each successive
+             * invocation is supplied the return value of the previous. If `accumulator`
+             * is not given, the first element of `collection` is used as the initial
+             * value. The iteratee is invoked with four arguments:
+             * (accumulator, value, index|key, collection).
+             *
+             * Many lodash methods are guarded to work as iteratees for methods like
+             * `_.reduce`, `_.reduceRight`, and `_.transform`.
+             *
+             * The guarded methods are:
+             * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`,
+             * and `sortBy`
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+             * @param {*} [accumulator] The initial value.
+             * @returns {*} Returns the accumulated value.
+             * @see _.reduceRight
+             * @example
+             *
+             * _.reduce([1, 2], function(sum, n) {
+             *   return sum + n;
+             * }, 0);
+             * // => 3
+             *
+             * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
+             *   (result[value] || (result[value] = [])).push(key);
+             *   return result;
+             * }, {});
+             * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed)
+             */
+            function reduce(collection, iteratee, accumulator) {
+              var func = isArray(collection) ? arrayReduce : baseReduce,
+                initAccum = arguments.length < 3;
+
+              return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach);
+            }
+
+            /**
+             * This method is like `_.reduce` except that it iterates over elements of
+             * `collection` from right to left.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+             * @param {*} [accumulator] The initial value.
+             * @returns {*} Returns the accumulated value.
+             * @see _.reduce
+             * @example
+             *
+             * var array = [[0, 1], [2, 3], [4, 5]];
+             *
+             * _.reduceRight(array, function(flattened, other) {
+             *   return flattened.concat(other);
+             * }, []);
+             * // => [4, 5, 2, 3, 0, 1]
+             */
+            function reduceRight(collection, iteratee, accumulator) {
+              var func = isArray(collection) ? arrayReduceRight : baseReduce,
+                initAccum = arguments.length < 3;
+
+              return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight);
+            }
+
+            /**
+             * The opposite of `_.filter`; this method returns the elements of `collection`
+             * that `predicate` does **not** return truthy for.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} [predicate=_.identity] The function invoked per iteration.
+             * @returns {Array} Returns the new filtered array.
+             * @see _.filter
+             * @example
+             *
+             * var users = [
+             *   { 'user': 'barney', 'age': 36, 'active': false },
+             *   { 'user': 'fred',   'age': 40, 'active': true }
+             * ];
+             *
+             * _.reject(users, function(o) { return !o.active; });
+             * // => objects for ['fred']
+             *
+             * // The `_.matches` iteratee shorthand.
+             * _.reject(users, { 'age': 40, 'active': true });
+             * // => objects for ['barney']
+             *
+             * // The `_.matchesProperty` iteratee shorthand.
+             * _.reject(users, ['active', false]);
+             * // => objects for ['fred']
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.reject(users, 'active');
+             * // => objects for ['barney']
+             */
+            function reject(collection, predicate) {
+              var func = isArray(collection) ? arrayFilter : baseFilter;
+              return func(collection, negate(getIteratee(predicate, 3)));
+            }
+
+            /**
+             * Gets a random element from `collection`.
+             *
+             * @static
+             * @memberOf _
+             * @since 2.0.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to sample.
+             * @returns {*} Returns the random element.
+             * @example
+             *
+             * _.sample([1, 2, 3, 4]);
+             * // => 2
+             */
+            function sample(collection) {
+              var func = isArray(collection) ? arraySample : baseSample;
+              return func(collection);
+            }
+
+            /**
+             * Gets `n` random elements at unique keys from `collection` up to the
+             * size of `collection`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to sample.
+             * @param {number} [n=1] The number of elements to sample.
+             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+             * @returns {Array} Returns the random elements.
+             * @example
+             *
+             * _.sampleSize([1, 2, 3], 2);
+             * // => [3, 1]
+             *
+             * _.sampleSize([1, 2, 3], 4);
+             * // => [2, 3, 1]
+             */
+            function sampleSize(collection, n, guard) {
+              if (guard ? isIterateeCall(collection, n, guard) : n === undefined) {
+                n = 1;
+              } else {
+                n = toInteger(n);
+              }
+              var func = isArray(collection) ? arraySampleSize : baseSampleSize;
+              return func(collection, n);
+            }
+
+            /**
+             * Creates an array of shuffled values, using a version of the
+             * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle).
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to shuffle.
+             * @returns {Array} Returns the new shuffled array.
+             * @example
+             *
+             * _.shuffle([1, 2, 3, 4]);
+             * // => [4, 1, 3, 2]
+             */
+            function shuffle(collection) {
+              var func = isArray(collection) ? arrayShuffle : baseShuffle;
+              return func(collection);
+            }
+
+            /**
+             * Gets the size of `collection` by returning its length for array-like
+             * values or the number of own enumerable string keyed properties for objects.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Collection
+             * @param {Array|Object|string} collection The collection to inspect.
+             * @returns {number} Returns the collection size.
+             * @example
+             *
+             * _.size([1, 2, 3]);
+             * // => 3
+             *
+             * _.size({ 'a': 1, 'b': 2 });
+             * // => 2
+             *
+             * _.size('pebbles');
+             * // => 7
+             */
+            function size(collection) {
+              if (collection == null) {
+                return 0;
+              }
+              if (isArrayLike(collection)) {
+                return isString(collection) ? stringSize(collection) : collection.length;
+              }
+              var tag = getTag(collection);
+              if (tag == mapTag || tag == setTag) {
+                return collection.size;
+              }
+              return baseKeys(collection).length;
+            }
+
+            /**
+             * Checks if `predicate` returns truthy for **any** element of `collection`.
+             * Iteration is stopped once `predicate` returns truthy. The predicate is
+             * invoked with three arguments: (value, index|key, collection).
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {Function} [predicate=_.identity] The function invoked per iteration.
+             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+             * @returns {boolean} Returns `true` if any element passes the predicate check,
+             *  else `false`.
+             * @example
+             *
+             * _.some([null, 0, 'yes', false], Boolean);
+             * // => true
+             *
+             * var users = [
+             *   { 'user': 'barney', 'active': true },
+             *   { 'user': 'fred',   'active': false }
+             * ];
+             *
+             * // The `_.matches` iteratee shorthand.
+             * _.some(users, { 'user': 'barney', 'active': false });
+             * // => false
+             *
+             * // The `_.matchesProperty` iteratee shorthand.
+             * _.some(users, ['active', false]);
+             * // => true
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.some(users, 'active');
+             * // => true
+             */
+            function some(collection, predicate, guard) {
+              var func = isArray(collection) ? arraySome : baseSome;
+              if (guard && isIterateeCall(collection, predicate, guard)) {
+                predicate = undefined;
+              }
+              return func(collection, getIteratee(predicate, 3));
+            }
+
+            /**
+             * Creates an array of elements, sorted in ascending order by the results of
+             * running each element in a collection thru each iteratee. This method
+             * performs a stable sort, that is, it preserves the original sort order of
+             * equal elements. The iteratees are invoked with one argument: (value).
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Collection
+             * @param {Array|Object} collection The collection to iterate over.
+             * @param {...(Function|Function[])} [iteratees=[_.identity]]
+             *  The iteratees to sort by.
+             * @returns {Array} Returns the new sorted array.
+             * @example
+             *
+             * var users = [
+             *   { 'user': 'fred',   'age': 48 },
+             *   { 'user': 'barney', 'age': 36 },
+             *   { 'user': 'fred',   'age': 40 },
+             *   { 'user': 'barney', 'age': 34 }
+             * ];
+             *
+             * _.sortBy(users, [function(o) { return o.user; }]);
+             * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
+             *
+             * _.sortBy(users, ['user', 'age']);
+             * // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]]
+             */
+            var sortBy = baseRest(function (collection, iteratees) {
+              if (collection == null) {
+                return [];
+              }
+              var length = iteratees.length;
+              if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) {
+                iteratees = [];
+              } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) {
+                iteratees = [iteratees[0]];
+              }
+              return baseOrderBy(collection, baseFlatten(iteratees, 1), []);
+            });
+
+            /*------------------------------------------------------------------------*/
+
+            /**
+             * Gets the timestamp of the number of milliseconds that have elapsed since
+             * the Unix epoch (1 January 1970 00:00:00 UTC).
+             *
+             * @static
+             * @memberOf _
+             * @since 2.4.0
+             * @category Date
+             * @returns {number} Returns the timestamp.
+             * @example
+             *
+             * _.defer(function(stamp) {
+             *   console.log(_.now() - stamp);
+             * }, _.now());
+             * // => Logs the number of milliseconds it took for the deferred invocation.
+             */
+            var now =
+              ctxNow ||
+              function () {
+                return root.Date.now();
+              };
+
+            /*------------------------------------------------------------------------*/
+
+            /**
+             * The opposite of `_.before`; this method creates a function that invokes
+             * `func` once it's called `n` or more times.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Function
+             * @param {number} n The number of calls before `func` is invoked.
+             * @param {Function} func The function to restrict.
+             * @returns {Function} Returns the new restricted function.
+             * @example
+             *
+             * var saves = ['profile', 'settings'];
+             *
+             * var done = _.after(saves.length, function() {
+             *   console.log('done saving!');
+             * });
+             *
+             * _.forEach(saves, function(type) {
+             *   asyncSave({ 'type': type, 'complete': done });
+             * });
+             * // => Logs 'done saving!' after the two async saves have completed.
+             */
+            function after(n, func) {
+              if (typeof func != 'function') {
+                throw new TypeError(FUNC_ERROR_TEXT);
+              }
+              n = toInteger(n);
+              return function () {
+                if (--n < 1) {
+                  return func.apply(this, arguments);
+                }
+              };
+            }
+
+            /**
+             * Creates a function that invokes `func`, with up to `n` arguments,
+             * ignoring any additional arguments.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Function
+             * @param {Function} func The function to cap arguments for.
+             * @param {number} [n=func.length] The arity cap.
+             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+             * @returns {Function} Returns the new capped function.
+             * @example
+             *
+             * _.map(['6', '8', '10'], _.ary(parseInt, 1));
+             * // => [6, 8, 10]
+             */
+            function ary(func, n, guard) {
+              n = guard ? undefined : n;
+              n = func && n == null ? func.length : n;
+              return createWrap(func, WRAP_ARY_FLAG, undefined, undefined, undefined, undefined, n);
+            }
+
+            /**
+             * Creates a function that invokes `func`, with the `this` binding and arguments
+             * of the created function, while it's called less than `n` times. Subsequent
+             * calls to the created function return the result of the last `func` invocation.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Function
+             * @param {number} n The number of calls at which `func` is no longer invoked.
+             * @param {Function} func The function to restrict.
+             * @returns {Function} Returns the new restricted function.
+             * @example
+             *
+             * jQuery(element).on('click', _.before(5, addContactToList));
+             * // => Allows adding up to 4 contacts to the list.
+             */
+            function before(n, func) {
+              var result;
+              if (typeof func != 'function') {
+                throw new TypeError(FUNC_ERROR_TEXT);
+              }
+              n = toInteger(n);
+              return function () {
+                if (--n > 0) {
+                  result = func.apply(this, arguments);
+                }
+                if (n <= 1) {
+                  func = undefined;
+                }
+                return result;
+              };
+            }
+
+            /**
+             * Creates a function that invokes `func` with the `this` binding of `thisArg`
+             * and `partials` prepended to the arguments it receives.
+             *
+             * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
+             * may be used as a placeholder for partially applied arguments.
+             *
+             * **Note:** Unlike native `Function#bind`, this method doesn't set the "length"
+             * property of bound functions.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Function
+             * @param {Function} func The function to bind.
+             * @param {*} thisArg The `this` binding of `func`.
+             * @param {...*} [partials] The arguments to be partially applied.
+             * @returns {Function} Returns the new bound function.
+             * @example
+             *
+             * function greet(greeting, punctuation) {
+             *   return greeting + ' ' + this.user + punctuation;
+             * }
+             *
+             * var object = { 'user': 'fred' };
+             *
+             * var bound = _.bind(greet, object, 'hi');
+             * bound('!');
+             * // => 'hi fred!'
+             *
+             * // Bound with placeholders.
+             * var bound = _.bind(greet, object, _, '!');
+             * bound('hi');
+             * // => 'hi fred!'
+             */
+            var bind = baseRest(function (func, thisArg, partials) {
+              var bitmask = WRAP_BIND_FLAG;
+              if (partials.length) {
+                var holders = replaceHolders(partials, getHolder(bind));
+                bitmask |= WRAP_PARTIAL_FLAG;
+              }
+              return createWrap(func, bitmask, thisArg, partials, holders);
+            });
+
+            /**
+             * Creates a function that invokes the method at `object[key]` with `partials`
+             * prepended to the arguments it receives.
+             *
+             * This method differs from `_.bind` by allowing bound functions to reference
+             * methods that may be redefined or don't yet exist. See
+             * [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern)
+             * for more details.
+             *
+             * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic
+             * builds, may be used as a placeholder for partially applied arguments.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.10.0
+             * @category Function
+             * @param {Object} object The object to invoke the method on.
+             * @param {string} key The key of the method.
+             * @param {...*} [partials] The arguments to be partially applied.
+             * @returns {Function} Returns the new bound function.
+             * @example
+             *
+             * var object = {
+             *   'user': 'fred',
+             *   'greet': function(greeting, punctuation) {
+             *     return greeting + ' ' + this.user + punctuation;
+             *   }
+             * };
+             *
+             * var bound = _.bindKey(object, 'greet', 'hi');
+             * bound('!');
+             * // => 'hi fred!'
+             *
+             * object.greet = function(greeting, punctuation) {
+             *   return greeting + 'ya ' + this.user + punctuation;
+             * };
+             *
+             * bound('!');
+             * // => 'hiya fred!'
+             *
+             * // Bound with placeholders.
+             * var bound = _.bindKey(object, 'greet', _, '!');
+             * bound('hi');
+             * // => 'hiya fred!'
+             */
+            var bindKey = baseRest(function (object, key, partials) {
+              var bitmask = WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG;
+              if (partials.length) {
+                var holders = replaceHolders(partials, getHolder(bindKey));
+                bitmask |= WRAP_PARTIAL_FLAG;
+              }
+              return createWrap(key, bitmask, object, partials, holders);
+            });
+
+            /**
+             * Creates a function that accepts arguments of `func` and either invokes
+             * `func` returning its result, if at least `arity` number of arguments have
+             * been provided, or returns a function that accepts the remaining `func`
+             * arguments, and so on. The arity of `func` may be specified if `func.length`
+             * is not sufficient.
+             *
+             * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds,
+             * may be used as a placeholder for provided arguments.
+             *
+             * **Note:** This method doesn't set the "length" property of curried functions.
+             *
+             * @static
+             * @memberOf _
+             * @since 2.0.0
+             * @category Function
+             * @param {Function} func The function to curry.
+             * @param {number} [arity=func.length] The arity of `func`.
+             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+             * @returns {Function} Returns the new curried function.
+             * @example
+             *
+             * var abc = function(a, b, c) {
+             *   return [a, b, c];
+             * };
+             *
+             * var curried = _.curry(abc);
+             *
+             * curried(1)(2)(3);
+             * // => [1, 2, 3]
+             *
+             * curried(1, 2)(3);
+             * // => [1, 2, 3]
+             *
+             * curried(1, 2, 3);
+             * // => [1, 2, 3]
+             *
+             * // Curried with placeholders.
+             * curried(1)(_, 3)(2);
+             * // => [1, 2, 3]
+             */
+            function curry(func, arity, guard) {
+              arity = guard ? undefined : arity;
+              var result = createWrap(
+                func,
+                WRAP_CURRY_FLAG,
+                undefined,
+                undefined,
+                undefined,
+                undefined,
+                undefined,
+                arity
+              );
+              result.placeholder = curry.placeholder;
+              return result;
+            }
+
+            /**
+             * This method is like `_.curry` except that arguments are applied to `func`
+             * in the manner of `_.partialRight` instead of `_.partial`.
+             *
+             * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic
+             * builds, may be used as a placeholder for provided arguments.
+             *
+             * **Note:** This method doesn't set the "length" property of curried functions.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Function
+             * @param {Function} func The function to curry.
+             * @param {number} [arity=func.length] The arity of `func`.
+             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+             * @returns {Function} Returns the new curried function.
+             * @example
+             *
+             * var abc = function(a, b, c) {
+             *   return [a, b, c];
+             * };
+             *
+             * var curried = _.curryRight(abc);
+             *
+             * curried(3)(2)(1);
+             * // => [1, 2, 3]
+             *
+             * curried(2, 3)(1);
+             * // => [1, 2, 3]
+             *
+             * curried(1, 2, 3);
+             * // => [1, 2, 3]
+             *
+             * // Curried with placeholders.
+             * curried(3)(1, _)(2);
+             * // => [1, 2, 3]
+             */
+            function curryRight(func, arity, guard) {
+              arity = guard ? undefined : arity;
+              var result = createWrap(
+                func,
+                WRAP_CURRY_RIGHT_FLAG,
+                undefined,
+                undefined,
+                undefined,
+                undefined,
+                undefined,
+                arity
+              );
+              result.placeholder = curryRight.placeholder;
+              return result;
+            }
+
+            /**
+             * Creates a debounced function that delays invoking `func` until after `wait`
+             * milliseconds have elapsed since the last time the debounced function was
+             * invoked. The debounced function comes with a `cancel` method to cancel
+             * delayed `func` invocations and a `flush` method to immediately invoke them.
+             * Provide `options` to indicate whether `func` should be invoked on the
+             * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
+             * with the last arguments provided to the debounced function. Subsequent
+             * calls to the debounced function return the result of the last `func`
+             * invocation.
+             *
+             * **Note:** If `leading` and `trailing` options are `true`, `func` is
+             * invoked on the trailing edge of the timeout only if the debounced function
+             * is invoked more than once during the `wait` timeout.
+             *
+             * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
+             * until to the next tick, similar to `setTimeout` with a timeout of `0`.
+             *
+             * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
+             * for details over the differences between `_.debounce` and `_.throttle`.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Function
+             * @param {Function} func The function to debounce.
+             * @param {number} [wait=0] The number of milliseconds to delay.
+             * @param {Object} [options={}] The options object.
+             * @param {boolean} [options.leading=false]
+             *  Specify invoking on the leading edge of the timeout.
+             * @param {number} [options.maxWait]
+             *  The maximum time `func` is allowed to be delayed before it's invoked.
+             * @param {boolean} [options.trailing=true]
+             *  Specify invoking on the trailing edge of the timeout.
+             * @returns {Function} Returns the new debounced function.
+             * @example
+             *
+             * // Avoid costly calculations while the window size is in flux.
+             * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
+             *
+             * // Invoke `sendMail` when clicked, debouncing subsequent calls.
+             * jQuery(element).on('click', _.debounce(sendMail, 300, {
+             *   'leading': true,
+             *   'trailing': false
+             * }));
+             *
+             * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
+             * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
+             * var source = new EventSource('/stream');
+             * jQuery(source).on('message', debounced);
+             *
+             * // Cancel the trailing debounced invocation.
+             * jQuery(window).on('popstate', debounced.cancel);
+             */
+            function debounce(func, wait, options) {
+              var lastArgs,
+                lastThis,
+                maxWait,
+                result,
+                timerId,
+                lastCallTime,
+                lastInvokeTime = 0,
+                leading = false,
+                maxing = false,
+                trailing = true;
+
+              if (typeof func != 'function') {
+                throw new TypeError(FUNC_ERROR_TEXT);
+              }
+              wait = toNumber(wait) || 0;
+              if (isObject(options)) {
+                leading = !!options.leading;
+                maxing = 'maxWait' in options;
+                maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
+                trailing = 'trailing' in options ? !!options.trailing : trailing;
+              }
+
+              function invokeFunc(time) {
+                var args = lastArgs,
+                  thisArg = lastThis;
+
+                lastArgs = lastThis = undefined;
+                lastInvokeTime = time;
+                result = func.apply(thisArg, args);
+                return result;
+              }
+
+              function leadingEdge(time) {
+                // Reset any `maxWait` timer.
+                lastInvokeTime = time;
+                // Start the timer for the trailing edge.
+                timerId = setTimeout(timerExpired, wait);
+                // Invoke the leading edge.
+                return leading ? invokeFunc(time) : result;
+              }
+
+              function remainingWait(time) {
+                var timeSinceLastCall = time - lastCallTime,
+                  timeSinceLastInvoke = time - lastInvokeTime,
+                  timeWaiting = wait - timeSinceLastCall;
+
+                return maxing ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting;
+              }
+
+              function shouldInvoke(time) {
+                var timeSinceLastCall = time - lastCallTime,
+                  timeSinceLastInvoke = time - lastInvokeTime;
+
+                // Either this is the first call, activity has stopped and we're at the
+                // trailing edge, the system time has gone backwards and we're treating
+                // it as the trailing edge, or we've hit the `maxWait` limit.
+                return (
+                  lastCallTime === undefined ||
+                  timeSinceLastCall >= wait ||
+                  timeSinceLastCall < 0 ||
+                  (maxing && timeSinceLastInvoke >= maxWait)
+                );
+              }
+
+              function timerExpired() {
+                var time = now();
+                if (shouldInvoke(time)) {
+                  return trailingEdge(time);
+                }
+                // Restart the timer.
+                timerId = setTimeout(timerExpired, remainingWait(time));
+              }
+
+              function trailingEdge(time) {
+                timerId = undefined;
+
+                // Only invoke if we have `lastArgs` which means `func` has been
+                // debounced at least once.
+                if (trailing && lastArgs) {
+                  return invokeFunc(time);
+                }
+                lastArgs = lastThis = undefined;
+                return result;
+              }
+
+              function cancel() {
+                if (timerId !== undefined) {
+                  clearTimeout(timerId);
+                }
+                lastInvokeTime = 0;
+                lastArgs = lastCallTime = lastThis = timerId = undefined;
+              }
+
+              function flush() {
+                return timerId === undefined ? result : trailingEdge(now());
+              }
+
+              function debounced() {
+                var time = now(),
+                  isInvoking = shouldInvoke(time);
+
+                lastArgs = arguments;
+                lastThis = this;
+                lastCallTime = time;
+
+                if (isInvoking) {
+                  if (timerId === undefined) {
+                    return leadingEdge(lastCallTime);
+                  }
+                  if (maxing) {
+                    // Handle invocations in a tight loop.
+                    timerId = setTimeout(timerExpired, wait);
+                    return invokeFunc(lastCallTime);
+                  }
+                }
+                if (timerId === undefined) {
+                  timerId = setTimeout(timerExpired, wait);
+                }
+                return result;
+              }
+              debounced.cancel = cancel;
+              debounced.flush = flush;
+              return debounced;
+            }
+
+            /**
+             * Defers invoking the `func` until the current call stack has cleared. Any
+             * additional arguments are provided to `func` when it's invoked.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Function
+             * @param {Function} func The function to defer.
+             * @param {...*} [args] The arguments to invoke `func` with.
+             * @returns {number} Returns the timer id.
+             * @example
+             *
+             * _.defer(function(text) {
+             *   console.log(text);
+             * }, 'deferred');
+             * // => Logs 'deferred' after one millisecond.
+             */
+            var defer = baseRest(function (func, args) {
+              return baseDelay(func, 1, args);
+            });
+
+            /**
+             * Invokes `func` after `wait` milliseconds. Any additional arguments are
+             * provided to `func` when it's invoked.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Function
+             * @param {Function} func The function to delay.
+             * @param {number} wait The number of milliseconds to delay invocation.
+             * @param {...*} [args] The arguments to invoke `func` with.
+             * @returns {number} Returns the timer id.
+             * @example
+             *
+             * _.delay(function(text) {
+             *   console.log(text);
+             * }, 1000, 'later');
+             * // => Logs 'later' after one second.
+             */
+            var delay = baseRest(function (func, wait, args) {
+              return baseDelay(func, toNumber(wait) || 0, args);
+            });
+
+            /**
+             * Creates a function that invokes `func` with arguments reversed.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Function
+             * @param {Function} func The function to flip arguments for.
+             * @returns {Function} Returns the new flipped function.
+             * @example
+             *
+             * var flipped = _.flip(function() {
+             *   return _.toArray(arguments);
+             * });
+             *
+             * flipped('a', 'b', 'c', 'd');
+             * // => ['d', 'c', 'b', 'a']
+             */
+            function flip(func) {
+              return createWrap(func, WRAP_FLIP_FLAG);
+            }
+
+            /**
+             * Creates a function that memoizes the result of `func`. If `resolver` is
+             * provided, it determines the cache key for storing the result based on the
+             * arguments provided to the memoized function. By default, the first argument
+             * provided to the memoized function is used as the map cache key. The `func`
+             * is invoked with the `this` binding of the memoized function.
+             *
+             * **Note:** The cache is exposed as the `cache` property on the memoized
+             * function. Its creation may be customized by replacing the `_.memoize.Cache`
+             * constructor with one whose instances implement the
+             * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
+             * method interface of `clear`, `delete`, `get`, `has`, and `set`.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Function
+             * @param {Function} func The function to have its output memoized.
+             * @param {Function} [resolver] The function to resolve the cache key.
+             * @returns {Function} Returns the new memoized function.
+             * @example
+             *
+             * var object = { 'a': 1, 'b': 2 };
+             * var other = { 'c': 3, 'd': 4 };
+             *
+             * var values = _.memoize(_.values);
+             * values(object);
+             * // => [1, 2]
+             *
+             * values(other);
+             * // => [3, 4]
+             *
+             * object.a = 2;
+             * values(object);
+             * // => [1, 2]
+             *
+             * // Modify the result cache.
+             * values.cache.set(object, ['a', 'b']);
+             * values(object);
+             * // => ['a', 'b']
+             *
+             * // Replace `_.memoize.Cache`.
+             * _.memoize.Cache = WeakMap;
+             */
+            function memoize(func, resolver) {
+              if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {
+                throw new TypeError(FUNC_ERROR_TEXT);
+              }
+              var memoized = function () {
+                var args = arguments,
+                  key = resolver ? resolver.apply(this, args) : args[0],
+                  cache = memoized.cache;
+
+                if (cache.has(key)) {
+                  return cache.get(key);
+                }
+                var result = func.apply(this, args);
+                memoized.cache = cache.set(key, result) || cache;
+                return result;
+              };
+              memoized.cache = new (memoize.Cache || MapCache)();
+              return memoized;
+            }
+
+            // Expose `MapCache`.
+            memoize.Cache = MapCache;
+
+            /**
+             * Creates a function that negates the result of the predicate `func`. The
+             * `func` predicate is invoked with the `this` binding and arguments of the
+             * created function.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Function
+             * @param {Function} predicate The predicate to negate.
+             * @returns {Function} Returns the new negated function.
+             * @example
+             *
+             * function isEven(n) {
+             *   return n % 2 == 0;
+             * }
+             *
+             * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));
+             * // => [1, 3, 5]
+             */
+            function negate(predicate) {
+              if (typeof predicate != 'function') {
+                throw new TypeError(FUNC_ERROR_TEXT);
+              }
+              return function () {
+                var args = arguments;
+                switch (args.length) {
+                  case 0:
+                    return !predicate.call(this);
+                  case 1:
+                    return !predicate.call(this, args[0]);
+                  case 2:
+                    return !predicate.call(this, args[0], args[1]);
+                  case 3:
+                    return !predicate.call(this, args[0], args[1], args[2]);
+                }
+                return !predicate.apply(this, args);
+              };
+            }
+
+            /**
+             * Creates a function that is restricted to invoking `func` once. Repeat calls
+             * to the function return the value of the first invocation. The `func` is
+             * invoked with the `this` binding and arguments of the created function.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Function
+             * @param {Function} func The function to restrict.
+             * @returns {Function} Returns the new restricted function.
+             * @example
+             *
+             * var initialize = _.once(createApplication);
+             * initialize();
+             * initialize();
+             * // => `createApplication` is invoked once
+             */
+            function once(func) {
+              return before(2, func);
+            }
+
+            /**
+             * Creates a function that invokes `func` with its arguments transformed.
+             *
+             * @static
+             * @since 4.0.0
+             * @memberOf _
+             * @category Function
+             * @param {Function} func The function to wrap.
+             * @param {...(Function|Function[])} [transforms=[_.identity]]
+             *  The argument transforms.
+             * @returns {Function} Returns the new function.
+             * @example
+             *
+             * function doubled(n) {
+             *   return n * 2;
+             * }
+             *
+             * function square(n) {
+             *   return n * n;
+             * }
+             *
+             * var func = _.overArgs(function(x, y) {
+             *   return [x, y];
+             * }, [square, doubled]);
+             *
+             * func(9, 3);
+             * // => [81, 6]
+             *
+             * func(10, 5);
+             * // => [100, 10]
+             */
+            var overArgs = castRest(function (func, transforms) {
+              transforms =
+                transforms.length == 1 && isArray(transforms[0])
+                  ? arrayMap(transforms[0], baseUnary(getIteratee()))
+                  : arrayMap(baseFlatten(transforms, 1), baseUnary(getIteratee()));
+
+              var funcsLength = transforms.length;
+              return baseRest(function (args) {
+                var index = -1,
+                  length = nativeMin(args.length, funcsLength);
+
+                while (++index < length) {
+                  args[index] = transforms[index].call(this, args[index]);
+                }
+                return apply(func, this, args);
+              });
+            });
+
+            /**
+             * Creates a function that invokes `func` with `partials` prepended to the
+             * arguments it receives. This method is like `_.bind` except it does **not**
+             * alter the `this` binding.
+             *
+             * The `_.partial.placeholder` value, which defaults to `_` in monolithic
+             * builds, may be used as a placeholder for partially applied arguments.
+             *
+             * **Note:** This method doesn't set the "length" property of partially
+             * applied functions.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.2.0
+             * @category Function
+             * @param {Function} func The function to partially apply arguments to.
+             * @param {...*} [partials] The arguments to be partially applied.
+             * @returns {Function} Returns the new partially applied function.
+             * @example
+             *
+             * function greet(greeting, name) {
+             *   return greeting + ' ' + name;
+             * }
+             *
+             * var sayHelloTo = _.partial(greet, 'hello');
+             * sayHelloTo('fred');
+             * // => 'hello fred'
+             *
+             * // Partially applied with placeholders.
+             * var greetFred = _.partial(greet, _, 'fred');
+             * greetFred('hi');
+             * // => 'hi fred'
+             */
+            var partial = baseRest(function (func, partials) {
+              var holders = replaceHolders(partials, getHolder(partial));
+              return createWrap(func, WRAP_PARTIAL_FLAG, undefined, partials, holders);
+            });
+
+            /**
+             * This method is like `_.partial` except that partially applied arguments
+             * are appended to the arguments it receives.
+             *
+             * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic
+             * builds, may be used as a placeholder for partially applied arguments.
+             *
+             * **Note:** This method doesn't set the "length" property of partially
+             * applied functions.
+             *
+             * @static
+             * @memberOf _
+             * @since 1.0.0
+             * @category Function
+             * @param {Function} func The function to partially apply arguments to.
+             * @param {...*} [partials] The arguments to be partially applied.
+             * @returns {Function} Returns the new partially applied function.
+             * @example
+             *
+             * function greet(greeting, name) {
+             *   return greeting + ' ' + name;
+             * }
+             *
+             * var greetFred = _.partialRight(greet, 'fred');
+             * greetFred('hi');
+             * // => 'hi fred'
+             *
+             * // Partially applied with placeholders.
+             * var sayHelloTo = _.partialRight(greet, 'hello', _);
+             * sayHelloTo('fred');
+             * // => 'hello fred'
+             */
+            var partialRight = baseRest(function (func, partials) {
+              var holders = replaceHolders(partials, getHolder(partialRight));
+              return createWrap(func, WRAP_PARTIAL_RIGHT_FLAG, undefined, partials, holders);
+            });
+
+            /**
+             * Creates a function that invokes `func` with arguments arranged according
+             * to the specified `indexes` where the argument value at the first index is
+             * provided as the first argument, the argument value at the second index is
+             * provided as the second argument, and so on.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Function
+             * @param {Function} func The function to rearrange arguments for.
+             * @param {...(number|number[])} indexes The arranged argument indexes.
+             * @returns {Function} Returns the new function.
+             * @example
+             *
+             * var rearged = _.rearg(function(a, b, c) {
+             *   return [a, b, c];
+             * }, [2, 0, 1]);
+             *
+             * rearged('b', 'c', 'a')
+             * // => ['a', 'b', 'c']
+             */
+            var rearg = flatRest(function (func, indexes) {
+              return createWrap(func, WRAP_REARG_FLAG, undefined, undefined, undefined, indexes);
+            });
+
+            /**
+             * Creates a function that invokes `func` with the `this` binding of the
+             * created function and arguments from `start` and beyond provided as
+             * an array.
+             *
+             * **Note:** This method is based on the
+             * [rest parameter](https://mdn.io/rest_parameters).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Function
+             * @param {Function} func The function to apply a rest parameter to.
+             * @param {number} [start=func.length-1] The start position of the rest parameter.
+             * @returns {Function} Returns the new function.
+             * @example
+             *
+             * var say = _.rest(function(what, names) {
+             *   return what + ' ' + _.initial(names).join(', ') +
+             *     (_.size(names) > 1 ? ', & ' : '') + _.last(names);
+             * });
+             *
+             * say('hello', 'fred', 'barney', 'pebbles');
+             * // => 'hello fred, barney, & pebbles'
+             */
+            function rest(func, start) {
+              if (typeof func != 'function') {
+                throw new TypeError(FUNC_ERROR_TEXT);
+              }
+              start = start === undefined ? start : toInteger(start);
+              return baseRest(func, start);
+            }
+
+            /**
+             * Creates a function that invokes `func` with the `this` binding of the
+             * create function and an array of arguments much like
+             * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply).
+             *
+             * **Note:** This method is based on the
+             * [spread operator](https://mdn.io/spread_operator).
+             *
+             * @static
+             * @memberOf _
+             * @since 3.2.0
+             * @category Function
+             * @param {Function} func The function to spread arguments over.
+             * @param {number} [start=0] The start position of the spread.
+             * @returns {Function} Returns the new function.
+             * @example
+             *
+             * var say = _.spread(function(who, what) {
+             *   return who + ' says ' + what;
+             * });
+             *
+             * say(['fred', 'hello']);
+             * // => 'fred says hello'
+             *
+             * var numbers = Promise.all([
+             *   Promise.resolve(40),
+             *   Promise.resolve(36)
+             * ]);
+             *
+             * numbers.then(_.spread(function(x, y) {
+             *   return x + y;
+             * }));
+             * // => a Promise of 76
+             */
+            function spread(func, start) {
+              if (typeof func != 'function') {
+                throw new TypeError(FUNC_ERROR_TEXT);
+              }
+              start = start == null ? 0 : nativeMax(toInteger(start), 0);
+              return baseRest(function (args) {
+                var array = args[start],
+                  otherArgs = castSlice(args, 0, start);
+
+                if (array) {
+                  arrayPush(otherArgs, array);
+                }
+                return apply(func, this, otherArgs);
+              });
+            }
+
+            /**
+             * Creates a throttled function that only invokes `func` at most once per
+             * every `wait` milliseconds. The throttled function comes with a `cancel`
+             * method to cancel delayed `func` invocations and a `flush` method to
+             * immediately invoke them. Provide `options` to indicate whether `func`
+             * should be invoked on the leading and/or trailing edge of the `wait`
+             * timeout. The `func` is invoked with the last arguments provided to the
+             * throttled function. Subsequent calls to the throttled function return the
+             * result of the last `func` invocation.
+             *
+             * **Note:** If `leading` and `trailing` options are `true`, `func` is
+             * invoked on the trailing edge of the timeout only if the throttled function
+             * is invoked more than once during the `wait` timeout.
+             *
+             * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
+             * until to the next tick, similar to `setTimeout` with a timeout of `0`.
+             *
+             * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
+             * for details over the differences between `_.throttle` and `_.debounce`.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Function
+             * @param {Function} func The function to throttle.
+             * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
+             * @param {Object} [options={}] The options object.
+             * @param {boolean} [options.leading=true]
+             *  Specify invoking on the leading edge of the timeout.
+             * @param {boolean} [options.trailing=true]
+             *  Specify invoking on the trailing edge of the timeout.
+             * @returns {Function} Returns the new throttled function.
+             * @example
+             *
+             * // Avoid excessively updating the position while scrolling.
+             * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
+             *
+             * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
+             * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
+             * jQuery(element).on('click', throttled);
+             *
+             * // Cancel the trailing throttled invocation.
+             * jQuery(window).on('popstate', throttled.cancel);
+             */
+            function throttle(func, wait, options) {
+              var leading = true,
+                trailing = true;
+
+              if (typeof func != 'function') {
+                throw new TypeError(FUNC_ERROR_TEXT);
+              }
+              if (isObject(options)) {
+                leading = 'leading' in options ? !!options.leading : leading;
+                trailing = 'trailing' in options ? !!options.trailing : trailing;
+              }
+              return debounce(func, wait, {
+                leading: leading,
+                maxWait: wait,
+                trailing: trailing,
+              });
+            }
+
+            /**
+             * Creates a function that accepts up to one argument, ignoring any
+             * additional arguments.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Function
+             * @param {Function} func The function to cap arguments for.
+             * @returns {Function} Returns the new capped function.
+             * @example
+             *
+             * _.map(['6', '8', '10'], _.unary(parseInt));
+             * // => [6, 8, 10]
+             */
+            function unary(func) {
+              return ary(func, 1);
+            }
+
+            /**
+             * Creates a function that provides `value` to `wrapper` as its first
+             * argument. Any additional arguments provided to the function are appended
+             * to those provided to the `wrapper`. The wrapper is invoked with the `this`
+             * binding of the created function.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Function
+             * @param {*} value The value to wrap.
+             * @param {Function} [wrapper=identity] The wrapper function.
+             * @returns {Function} Returns the new function.
+             * @example
+             *
+             * var p = _.wrap(_.escape, function(func, text) {
+             *   return '' + func(text) + '
';
+             * });
+             *
+             * p('fred, barney, & pebbles');
+             * // => 'fred, barney, & pebbles
'
+             */
+            function wrap(value, wrapper) {
+              return partial(castFunction(wrapper), value);
+            }
+
+            /*------------------------------------------------------------------------*/
+
+            /**
+             * Casts `value` as an array if it's not one.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.4.0
+             * @category Lang
+             * @param {*} value The value to inspect.
+             * @returns {Array} Returns the cast array.
+             * @example
+             *
+             * _.castArray(1);
+             * // => [1]
+             *
+             * _.castArray({ 'a': 1 });
+             * // => [{ 'a': 1 }]
+             *
+             * _.castArray('abc');
+             * // => ['abc']
+             *
+             * _.castArray(null);
+             * // => [null]
+             *
+             * _.castArray(undefined);
+             * // => [undefined]
+             *
+             * _.castArray();
+             * // => []
+             *
+             * var array = [1, 2, 3];
+             * console.log(_.castArray(array) === array);
+             * // => true
+             */
+            function castArray() {
+              if (!arguments.length) {
+                return [];
+              }
+              var value = arguments[0];
+              return isArray(value) ? value : [value];
+            }
+
+            /**
+             * Creates a shallow clone of `value`.
+             *
+             * **Note:** This method is loosely based on the
+             * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm)
+             * and supports cloning arrays, array buffers, booleans, date objects, maps,
+             * numbers, `Object` objects, regexes, sets, strings, symbols, and typed
+             * arrays. The own enumerable properties of `arguments` objects are cloned
+             * as plain objects. An empty object is returned for uncloneable values such
+             * as error objects, functions, DOM nodes, and WeakMaps.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Lang
+             * @param {*} value The value to clone.
+             * @returns {*} Returns the cloned value.
+             * @see _.cloneDeep
+             * @example
+             *
+             * var objects = [{ 'a': 1 }, { 'b': 2 }];
+             *
+             * var shallow = _.clone(objects);
+             * console.log(shallow[0] === objects[0]);
+             * // => true
+             */
+            function clone(value) {
+              return baseClone(value, CLONE_SYMBOLS_FLAG);
+            }
+
+            /**
+             * This method is like `_.clone` except that it accepts `customizer` which
+             * is invoked to produce the cloned value. If `customizer` returns `undefined`,
+             * cloning is handled by the method instead. The `customizer` is invoked with
+             * up to four arguments; (value [, index|key, object, stack]).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Lang
+             * @param {*} value The value to clone.
+             * @param {Function} [customizer] The function to customize cloning.
+             * @returns {*} Returns the cloned value.
+             * @see _.cloneDeepWith
+             * @example
+             *
+             * function customizer(value) {
+             *   if (_.isElement(value)) {
+             *     return value.cloneNode(false);
+             *   }
+             * }
+             *
+             * var el = _.cloneWith(document.body, customizer);
+             *
+             * console.log(el === document.body);
+             * // => false
+             * console.log(el.nodeName);
+             * // => 'BODY'
+             * console.log(el.childNodes.length);
+             * // => 0
+             */
+            function cloneWith(value, customizer) {
+              customizer = typeof customizer == 'function' ? customizer : undefined;
+              return baseClone(value, CLONE_SYMBOLS_FLAG, customizer);
+            }
+
+            /**
+             * This method is like `_.clone` except that it recursively clones `value`.
+             *
+             * @static
+             * @memberOf _
+             * @since 1.0.0
+             * @category Lang
+             * @param {*} value The value to recursively clone.
+             * @returns {*} Returns the deep cloned value.
+             * @see _.clone
+             * @example
+             *
+             * var objects = [{ 'a': 1 }, { 'b': 2 }];
+             *
+             * var deep = _.cloneDeep(objects);
+             * console.log(deep[0] === objects[0]);
+             * // => false
+             */
+            function cloneDeep(value) {
+              return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG);
+            }
+
+            /**
+             * This method is like `_.cloneWith` except that it recursively clones `value`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Lang
+             * @param {*} value The value to recursively clone.
+             * @param {Function} [customizer] The function to customize cloning.
+             * @returns {*} Returns the deep cloned value.
+             * @see _.cloneWith
+             * @example
+             *
+             * function customizer(value) {
+             *   if (_.isElement(value)) {
+             *     return value.cloneNode(true);
+             *   }
+             * }
+             *
+             * var el = _.cloneDeepWith(document.body, customizer);
+             *
+             * console.log(el === document.body);
+             * // => false
+             * console.log(el.nodeName);
+             * // => 'BODY'
+             * console.log(el.childNodes.length);
+             * // => 20
+             */
+            function cloneDeepWith(value, customizer) {
+              customizer = typeof customizer == 'function' ? customizer : undefined;
+              return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer);
+            }
+
+            /**
+             * Checks if `object` conforms to `source` by invoking the predicate
+             * properties of `source` with the corresponding property values of `object`.
+             *
+             * **Note:** This method is equivalent to `_.conforms` when `source` is
+             * partially applied.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.14.0
+             * @category Lang
+             * @param {Object} object The object to inspect.
+             * @param {Object} source The object of property predicates to conform to.
+             * @returns {boolean} Returns `true` if `object` conforms, else `false`.
+             * @example
+             *
+             * var object = { 'a': 1, 'b': 2 };
+             *
+             * _.conformsTo(object, { 'b': function(n) { return n > 1; } });
+             * // => true
+             *
+             * _.conformsTo(object, { 'b': function(n) { return n > 2; } });
+             * // => false
+             */
+            function conformsTo(object, source) {
+              return source == null || baseConformsTo(object, source, keys(source));
+            }
+
+            /**
+             * Performs a
+             * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+             * comparison between two values to determine if they are equivalent.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Lang
+             * @param {*} value The value to compare.
+             * @param {*} other The other value to compare.
+             * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+             * @example
+             *
+             * var object = { 'a': 1 };
+             * var other = { 'a': 1 };
+             *
+             * _.eq(object, object);
+             * // => true
+             *
+             * _.eq(object, other);
+             * // => false
+             *
+             * _.eq('a', 'a');
+             * // => true
+             *
+             * _.eq('a', Object('a'));
+             * // => false
+             *
+             * _.eq(NaN, NaN);
+             * // => true
+             */
+            function eq(value, other) {
+              return value === other || (value !== value && other !== other);
+            }
+
+            /**
+             * Checks if `value` is greater than `other`.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.9.0
+             * @category Lang
+             * @param {*} value The value to compare.
+             * @param {*} other The other value to compare.
+             * @returns {boolean} Returns `true` if `value` is greater than `other`,
+             *  else `false`.
+             * @see _.lt
+             * @example
+             *
+             * _.gt(3, 1);
+             * // => true
+             *
+             * _.gt(3, 3);
+             * // => false
+             *
+             * _.gt(1, 3);
+             * // => false
+             */
+            var gt = createRelationalOperation(baseGt);
+
+            /**
+             * Checks if `value` is greater than or equal to `other`.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.9.0
+             * @category Lang
+             * @param {*} value The value to compare.
+             * @param {*} other The other value to compare.
+             * @returns {boolean} Returns `true` if `value` is greater than or equal to
+             *  `other`, else `false`.
+             * @see _.lte
+             * @example
+             *
+             * _.gte(3, 1);
+             * // => true
+             *
+             * _.gte(3, 3);
+             * // => true
+             *
+             * _.gte(1, 3);
+             * // => false
+             */
+            var gte = createRelationalOperation(function (value, other) {
+              return value >= other;
+            });
+
+            /**
+             * Checks if `value` is likely an `arguments` object.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is an `arguments` object,
+             *  else `false`.
+             * @example
+             *
+             * _.isArguments(function() { return arguments; }());
+             * // => true
+             *
+             * _.isArguments([1, 2, 3]);
+             * // => false
+             */
+            var isArguments = baseIsArguments(
+              (function () {
+                return arguments;
+              })()
+            )
+              ? baseIsArguments
+              : function (value) {
+                  return (
+                    isObjectLike(value) &&
+                    hasOwnProperty.call(value, 'callee') &&
+                    !propertyIsEnumerable.call(value, 'callee')
+                  );
+                };
+
+            /**
+             * Checks if `value` is classified as an `Array` object.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is an array, else `false`.
+             * @example
+             *
+             * _.isArray([1, 2, 3]);
+             * // => true
+             *
+             * _.isArray(document.body.children);
+             * // => false
+             *
+             * _.isArray('abc');
+             * // => false
+             *
+             * _.isArray(_.noop);
+             * // => false
+             */
+            var isArray = Array.isArray;
+
+            /**
+             * Checks if `value` is classified as an `ArrayBuffer` object.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.3.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
+             * @example
+             *
+             * _.isArrayBuffer(new ArrayBuffer(2));
+             * // => true
+             *
+             * _.isArrayBuffer(new Array(2));
+             * // => false
+             */
+            var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer;
+
+            /**
+             * Checks if `value` is array-like. A value is considered array-like if it's
+             * not a function and has a `value.length` that's an integer greater than or
+             * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
+             * @example
+             *
+             * _.isArrayLike([1, 2, 3]);
+             * // => true
+             *
+             * _.isArrayLike(document.body.children);
+             * // => true
+             *
+             * _.isArrayLike('abc');
+             * // => true
+             *
+             * _.isArrayLike(_.noop);
+             * // => false
+             */
+            function isArrayLike(value) {
+              return value != null && isLength(value.length) && !isFunction(value);
+            }
+
+            /**
+             * This method is like `_.isArrayLike` except that it also checks if `value`
+             * is an object.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is an array-like object,
+             *  else `false`.
+             * @example
+             *
+             * _.isArrayLikeObject([1, 2, 3]);
+             * // => true
+             *
+             * _.isArrayLikeObject(document.body.children);
+             * // => true
+             *
+             * _.isArrayLikeObject('abc');
+             * // => false
+             *
+             * _.isArrayLikeObject(_.noop);
+             * // => false
+             */
+            function isArrayLikeObject(value) {
+              return isObjectLike(value) && isArrayLike(value);
+            }
+
+            /**
+             * Checks if `value` is classified as a boolean primitive or object.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a boolean, else `false`.
+             * @example
+             *
+             * _.isBoolean(false);
+             * // => true
+             *
+             * _.isBoolean(null);
+             * // => false
+             */
+            function isBoolean(value) {
+              return (
+                value === true || value === false || (isObjectLike(value) && baseGetTag(value) == boolTag)
+              );
+            }
+
+            /**
+             * Checks if `value` is a buffer.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.3.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.
+             * @example
+             *
+             * _.isBuffer(new Buffer(2));
+             * // => true
+             *
+             * _.isBuffer(new Uint8Array(2));
+             * // => false
+             */
+            var isBuffer = nativeIsBuffer || stubFalse;
+
+            /**
+             * Checks if `value` is classified as a `Date` object.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a date object, else `false`.
+             * @example
+             *
+             * _.isDate(new Date);
+             * // => true
+             *
+             * _.isDate('Mon April 23 2012');
+             * // => false
+             */
+            var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate;
+
+            /**
+             * Checks if `value` is likely a DOM element.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`.
+             * @example
+             *
+             * _.isElement(document.body);
+             * // => true
+             *
+             * _.isElement('');
+             * // => false
+             */
+            function isElement(value) {
+              return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value);
+            }
+
+            /**
+             * Checks if `value` is an empty object, collection, map, or set.
+             *
+             * Objects are considered empty if they have no own enumerable string keyed
+             * properties.
+             *
+             * Array-like values such as `arguments` objects, arrays, buffers, strings, or
+             * jQuery-like collections are considered empty if they have a `length` of `0`.
+             * Similarly, maps and sets are considered empty if they have a `size` of `0`.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is empty, else `false`.
+             * @example
+             *
+             * _.isEmpty(null);
+             * // => true
+             *
+             * _.isEmpty(true);
+             * // => true
+             *
+             * _.isEmpty(1);
+             * // => true
+             *
+             * _.isEmpty([1, 2, 3]);
+             * // => false
+             *
+             * _.isEmpty({ 'a': 1 });
+             * // => false
+             */
+            function isEmpty(value) {
+              if (value == null) {
+                return true;
+              }
+              if (
+                isArrayLike(value) &&
+                (isArray(value) ||
+                  typeof value == 'string' ||
+                  typeof value.splice == 'function' ||
+                  isBuffer(value) ||
+                  isTypedArray(value) ||
+                  isArguments(value))
+              ) {
+                return !value.length;
+              }
+              var tag = getTag(value);
+              if (tag == mapTag || tag == setTag) {
+                return !value.size;
+              }
+              if (isPrototype(value)) {
+                return !baseKeys(value).length;
+              }
+              for (var key in value) {
+                if (hasOwnProperty.call(value, key)) {
+                  return false;
+                }
+              }
+              return true;
+            }
+
+            /**
+             * Performs a deep comparison between two values to determine if they are
+             * equivalent.
+             *
+             * **Note:** This method supports comparing arrays, array buffers, booleans,
+             * date objects, error objects, maps, numbers, `Object` objects, regexes,
+             * sets, strings, symbols, and typed arrays. `Object` objects are compared
+             * by their own, not inherited, enumerable properties. Functions and DOM
+             * nodes are compared by strict equality, i.e. `===`.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Lang
+             * @param {*} value The value to compare.
+             * @param {*} other The other value to compare.
+             * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+             * @example
+             *
+             * var object = { 'a': 1 };
+             * var other = { 'a': 1 };
+             *
+             * _.isEqual(object, other);
+             * // => true
+             *
+             * object === other;
+             * // => false
+             */
+            function isEqual(value, other) {
+              return baseIsEqual(value, other);
+            }
+
+            /**
+             * This method is like `_.isEqual` except that it accepts `customizer` which
+             * is invoked to compare values. If `customizer` returns `undefined`, comparisons
+             * are handled by the method instead. The `customizer` is invoked with up to
+             * six arguments: (objValue, othValue [, index|key, object, other, stack]).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Lang
+             * @param {*} value The value to compare.
+             * @param {*} other The other value to compare.
+             * @param {Function} [customizer] The function to customize comparisons.
+             * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+             * @example
+             *
+             * function isGreeting(value) {
+             *   return /^h(?:i|ello)$/.test(value);
+             * }
+             *
+             * function customizer(objValue, othValue) {
+             *   if (isGreeting(objValue) && isGreeting(othValue)) {
+             *     return true;
+             *   }
+             * }
+             *
+             * var array = ['hello', 'goodbye'];
+             * var other = ['hi', 'goodbye'];
+             *
+             * _.isEqualWith(array, other, customizer);
+             * // => true
+             */
+            function isEqualWith(value, other, customizer) {
+              customizer = typeof customizer == 'function' ? customizer : undefined;
+              var result = customizer ? customizer(value, other) : undefined;
+              return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result;
+            }
+
+            /**
+             * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`,
+             * `SyntaxError`, `TypeError`, or `URIError` object.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is an error object, else `false`.
+             * @example
+             *
+             * _.isError(new Error);
+             * // => true
+             *
+             * _.isError(Error);
+             * // => false
+             */
+            function isError(value) {
+              if (!isObjectLike(value)) {
+                return false;
+              }
+              var tag = baseGetTag(value);
+              return (
+                tag == errorTag ||
+                tag == domExcTag ||
+                (typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value))
+              );
+            }
+
+            /**
+             * Checks if `value` is a finite primitive number.
+             *
+             * **Note:** This method is based on
+             * [`Number.isFinite`](https://mdn.io/Number/isFinite).
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a finite number, else `false`.
+             * @example
+             *
+             * _.isFinite(3);
+             * // => true
+             *
+             * _.isFinite(Number.MIN_VALUE);
+             * // => true
+             *
+             * _.isFinite(Infinity);
+             * // => false
+             *
+             * _.isFinite('3');
+             * // => false
+             */
+            function isFinite(value) {
+              return typeof value == 'number' && nativeIsFinite(value);
+            }
+
+            /**
+             * Checks if `value` is classified as a `Function` object.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a function, else `false`.
+             * @example
+             *
+             * _.isFunction(_);
+             * // => true
+             *
+             * _.isFunction(/abc/);
+             * // => false
+             */
+            function isFunction(value) {
+              if (!isObject(value)) {
+                return false;
+              }
+              // The use of `Object#toString` avoids issues with the `typeof` operator
+              // in Safari 9 which returns 'object' for typed arrays and other constructors.
+              var tag = baseGetTag(value);
+              return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
+            }
+
+            /**
+             * Checks if `value` is an integer.
+             *
+             * **Note:** This method is based on
+             * [`Number.isInteger`](https://mdn.io/Number/isInteger).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is an integer, else `false`.
+             * @example
+             *
+             * _.isInteger(3);
+             * // => true
+             *
+             * _.isInteger(Number.MIN_VALUE);
+             * // => false
+             *
+             * _.isInteger(Infinity);
+             * // => false
+             *
+             * _.isInteger('3');
+             * // => false
+             */
+            function isInteger(value) {
+              return typeof value == 'number' && value == toInteger(value);
+            }
+
+            /**
+             * Checks if `value` is a valid array-like length.
+             *
+             * **Note:** This method is loosely based on
+             * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
+             * @example
+             *
+             * _.isLength(3);
+             * // => true
+             *
+             * _.isLength(Number.MIN_VALUE);
+             * // => false
+             *
+             * _.isLength(Infinity);
+             * // => false
+             *
+             * _.isLength('3');
+             * // => false
+             */
+            function isLength(value) {
+              return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+            }
+
+            /**
+             * Checks if `value` is the
+             * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
+             * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+             * @example
+             *
+             * _.isObject({});
+             * // => true
+             *
+             * _.isObject([1, 2, 3]);
+             * // => true
+             *
+             * _.isObject(_.noop);
+             * // => true
+             *
+             * _.isObject(null);
+             * // => false
+             */
+            function isObject(value) {
+              var type = typeof value;
+              return value != null && (type == 'object' || type == 'function');
+            }
+
+            /**
+             * Checks if `value` is object-like. A value is object-like if it's not `null`
+             * and has a `typeof` result of "object".
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+             * @example
+             *
+             * _.isObjectLike({});
+             * // => true
+             *
+             * _.isObjectLike([1, 2, 3]);
+             * // => true
+             *
+             * _.isObjectLike(_.noop);
+             * // => false
+             *
+             * _.isObjectLike(null);
+             * // => false
+             */
+            function isObjectLike(value) {
+              return value != null && typeof value == 'object';
+            }
+
+            /**
+             * Checks if `value` is classified as a `Map` object.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.3.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a map, else `false`.
+             * @example
+             *
+             * _.isMap(new Map);
+             * // => true
+             *
+             * _.isMap(new WeakMap);
+             * // => false
+             */
+            var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap;
+
+            /**
+             * Performs a partial deep comparison between `object` and `source` to
+             * determine if `object` contains equivalent property values.
+             *
+             * **Note:** This method is equivalent to `_.matches` when `source` is
+             * partially applied.
+             *
+             * Partial comparisons will match empty array and empty object `source`
+             * values against any array or object value, respectively. See `_.isEqual`
+             * for a list of supported value comparisons.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Lang
+             * @param {Object} object The object to inspect.
+             * @param {Object} source The object of property values to match.
+             * @returns {boolean} Returns `true` if `object` is a match, else `false`.
+             * @example
+             *
+             * var object = { 'a': 1, 'b': 2 };
+             *
+             * _.isMatch(object, { 'b': 2 });
+             * // => true
+             *
+             * _.isMatch(object, { 'b': 1 });
+             * // => false
+             */
+            function isMatch(object, source) {
+              return object === source || baseIsMatch(object, source, getMatchData(source));
+            }
+
+            /**
+             * This method is like `_.isMatch` except that it accepts `customizer` which
+             * is invoked to compare values. If `customizer` returns `undefined`, comparisons
+             * are handled by the method instead. The `customizer` is invoked with five
+             * arguments: (objValue, srcValue, index|key, object, source).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Lang
+             * @param {Object} object The object to inspect.
+             * @param {Object} source The object of property values to match.
+             * @param {Function} [customizer] The function to customize comparisons.
+             * @returns {boolean} Returns `true` if `object` is a match, else `false`.
+             * @example
+             *
+             * function isGreeting(value) {
+             *   return /^h(?:i|ello)$/.test(value);
+             * }
+             *
+             * function customizer(objValue, srcValue) {
+             *   if (isGreeting(objValue) && isGreeting(srcValue)) {
+             *     return true;
+             *   }
+             * }
+             *
+             * var object = { 'greeting': 'hello' };
+             * var source = { 'greeting': 'hi' };
+             *
+             * _.isMatchWith(object, source, customizer);
+             * // => true
+             */
+            function isMatchWith(object, source, customizer) {
+              customizer = typeof customizer == 'function' ? customizer : undefined;
+              return baseIsMatch(object, source, getMatchData(source), customizer);
+            }
+
+            /**
+             * Checks if `value` is `NaN`.
+             *
+             * **Note:** This method is based on
+             * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as
+             * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for
+             * `undefined` and other non-number values.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
+             * @example
+             *
+             * _.isNaN(NaN);
+             * // => true
+             *
+             * _.isNaN(new Number(NaN));
+             * // => true
+             *
+             * isNaN(undefined);
+             * // => true
+             *
+             * _.isNaN(undefined);
+             * // => false
+             */
+            function isNaN(value) {
+              // An `NaN` primitive is the only value that is not equal to itself.
+              // Perform the `toStringTag` check first to avoid errors with some
+              // ActiveX objects in IE.
+              return isNumber(value) && value != +value;
+            }
+
+            /**
+             * Checks if `value` is a pristine native function.
+             *
+             * **Note:** This method can't reliably detect native functions in the presence
+             * of the core-js package because core-js circumvents this kind of detection.
+             * Despite multiple requests, the core-js maintainer has made it clear: any
+             * attempt to fix the detection will be obstructed. As a result, we're left
+             * with little choice but to throw an error. Unfortunately, this also affects
+             * packages, like [babel-polyfill](https://www.npmjs.com/package/babel-polyfill),
+             * which rely on core-js.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a native function,
+             *  else `false`.
+             * @example
+             *
+             * _.isNative(Array.prototype.push);
+             * // => true
+             *
+             * _.isNative(_);
+             * // => false
+             */
+            function isNative(value) {
+              if (isMaskable(value)) {
+                throw new Error(CORE_ERROR_TEXT);
+              }
+              return baseIsNative(value);
+            }
+
+            /**
+             * Checks if `value` is `null`.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is `null`, else `false`.
+             * @example
+             *
+             * _.isNull(null);
+             * // => true
+             *
+             * _.isNull(void 0);
+             * // => false
+             */
+            function isNull(value) {
+              return value === null;
+            }
+
+            /**
+             * Checks if `value` is `null` or `undefined`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is nullish, else `false`.
+             * @example
+             *
+             * _.isNil(null);
+             * // => true
+             *
+             * _.isNil(void 0);
+             * // => true
+             *
+             * _.isNil(NaN);
+             * // => false
+             */
+            function isNil(value) {
+              return value == null;
+            }
+
+            /**
+             * Checks if `value` is classified as a `Number` primitive or object.
+             *
+             * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are
+             * classified as numbers, use the `_.isFinite` method.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a number, else `false`.
+             * @example
+             *
+             * _.isNumber(3);
+             * // => true
+             *
+             * _.isNumber(Number.MIN_VALUE);
+             * // => true
+             *
+             * _.isNumber(Infinity);
+             * // => true
+             *
+             * _.isNumber('3');
+             * // => false
+             */
+            function isNumber(value) {
+              return typeof value == 'number' || (isObjectLike(value) && baseGetTag(value) == numberTag);
+            }
+
+            /**
+             * Checks if `value` is a plain object, that is, an object created by the
+             * `Object` constructor or one with a `[[Prototype]]` of `null`.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.8.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
+             * @example
+             *
+             * function Foo() {
+             *   this.a = 1;
+             * }
+             *
+             * _.isPlainObject(new Foo);
+             * // => false
+             *
+             * _.isPlainObject([1, 2, 3]);
+             * // => false
+             *
+             * _.isPlainObject({ 'x': 0, 'y': 0 });
+             * // => true
+             *
+             * _.isPlainObject(Object.create(null));
+             * // => true
+             */
+            function isPlainObject(value) {
+              if (!isObjectLike(value) || baseGetTag(value) != objectTag) {
+                return false;
+              }
+              var proto = getPrototype(value);
+              if (proto === null) {
+                return true;
+              }
+              var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;
+              return (
+                typeof Ctor == 'function' &&
+                Ctor instanceof Ctor &&
+                funcToString.call(Ctor) == objectCtorString
+              );
+            }
+
+            /**
+             * Checks if `value` is classified as a `RegExp` object.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.1.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
+             * @example
+             *
+             * _.isRegExp(/abc/);
+             * // => true
+             *
+             * _.isRegExp('/abc/');
+             * // => false
+             */
+            var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp;
+
+            /**
+             * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754
+             * double precision number which isn't the result of a rounded unsafe integer.
+             *
+             * **Note:** This method is based on
+             * [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`.
+             * @example
+             *
+             * _.isSafeInteger(3);
+             * // => true
+             *
+             * _.isSafeInteger(Number.MIN_VALUE);
+             * // => false
+             *
+             * _.isSafeInteger(Infinity);
+             * // => false
+             *
+             * _.isSafeInteger('3');
+             * // => false
+             */
+            function isSafeInteger(value) {
+              return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER;
+            }
+
+            /**
+             * Checks if `value` is classified as a `Set` object.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.3.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a set, else `false`.
+             * @example
+             *
+             * _.isSet(new Set);
+             * // => true
+             *
+             * _.isSet(new WeakSet);
+             * // => false
+             */
+            var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet;
+
+            /**
+             * Checks if `value` is classified as a `String` primitive or object.
+             *
+             * @static
+             * @since 0.1.0
+             * @memberOf _
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a string, else `false`.
+             * @example
+             *
+             * _.isString('abc');
+             * // => true
+             *
+             * _.isString(1);
+             * // => false
+             */
+            function isString(value) {
+              return (
+                typeof value == 'string' ||
+                (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag)
+              );
+            }
+
+            /**
+             * Checks if `value` is classified as a `Symbol` primitive or object.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
+             * @example
+             *
+             * _.isSymbol(Symbol.iterator);
+             * // => true
+             *
+             * _.isSymbol('abc');
+             * // => false
+             */
+            function isSymbol(value) {
+              return typeof value == 'symbol' || (isObjectLike(value) && baseGetTag(value) == symbolTag);
+            }
+
+            /**
+             * Checks if `value` is classified as a typed array.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
+             * @example
+             *
+             * _.isTypedArray(new Uint8Array);
+             * // => true
+             *
+             * _.isTypedArray([]);
+             * // => false
+             */
+            var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;
+
+            /**
+             * Checks if `value` is `undefined`.
+             *
+             * @static
+             * @since 0.1.0
+             * @memberOf _
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
+             * @example
+             *
+             * _.isUndefined(void 0);
+             * // => true
+             *
+             * _.isUndefined(null);
+             * // => false
+             */
+            function isUndefined(value) {
+              return value === undefined;
+            }
+
+            /**
+             * Checks if `value` is classified as a `WeakMap` object.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.3.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a weak map, else `false`.
+             * @example
+             *
+             * _.isWeakMap(new WeakMap);
+             * // => true
+             *
+             * _.isWeakMap(new Map);
+             * // => false
+             */
+            function isWeakMap(value) {
+              return isObjectLike(value) && getTag(value) == weakMapTag;
+            }
+
+            /**
+             * Checks if `value` is classified as a `WeakSet` object.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.3.0
+             * @category Lang
+             * @param {*} value The value to check.
+             * @returns {boolean} Returns `true` if `value` is a weak set, else `false`.
+             * @example
+             *
+             * _.isWeakSet(new WeakSet);
+             * // => true
+             *
+             * _.isWeakSet(new Set);
+             * // => false
+             */
+            function isWeakSet(value) {
+              return isObjectLike(value) && baseGetTag(value) == weakSetTag;
+            }
+
+            /**
+             * Checks if `value` is less than `other`.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.9.0
+             * @category Lang
+             * @param {*} value The value to compare.
+             * @param {*} other The other value to compare.
+             * @returns {boolean} Returns `true` if `value` is less than `other`,
+             *  else `false`.
+             * @see _.gt
+             * @example
+             *
+             * _.lt(1, 3);
+             * // => true
+             *
+             * _.lt(3, 3);
+             * // => false
+             *
+             * _.lt(3, 1);
+             * // => false
+             */
+            var lt = createRelationalOperation(baseLt);
+
+            /**
+             * Checks if `value` is less than or equal to `other`.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.9.0
+             * @category Lang
+             * @param {*} value The value to compare.
+             * @param {*} other The other value to compare.
+             * @returns {boolean} Returns `true` if `value` is less than or equal to
+             *  `other`, else `false`.
+             * @see _.gte
+             * @example
+             *
+             * _.lte(1, 3);
+             * // => true
+             *
+             * _.lte(3, 3);
+             * // => true
+             *
+             * _.lte(3, 1);
+             * // => false
+             */
+            var lte = createRelationalOperation(function (value, other) {
+              return value <= other;
+            });
+
+            /**
+             * Converts `value` to an array.
+             *
+             * @static
+             * @since 0.1.0
+             * @memberOf _
+             * @category Lang
+             * @param {*} value The value to convert.
+             * @returns {Array} Returns the converted array.
+             * @example
+             *
+             * _.toArray({ 'a': 1, 'b': 2 });
+             * // => [1, 2]
+             *
+             * _.toArray('abc');
+             * // => ['a', 'b', 'c']
+             *
+             * _.toArray(1);
+             * // => []
+             *
+             * _.toArray(null);
+             * // => []
+             */
+            function toArray(value) {
+              if (!value) {
+                return [];
+              }
+              if (isArrayLike(value)) {
+                return isString(value) ? stringToArray(value) : copyArray(value);
+              }
+              if (symIterator && value[symIterator]) {
+                return iteratorToArray(value[symIterator]());
+              }
+              var tag = getTag(value),
+                func = tag == mapTag ? mapToArray : tag == setTag ? setToArray : values;
+
+              return func(value);
+            }
+
+            /**
+             * Converts `value` to a finite number.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.12.0
+             * @category Lang
+             * @param {*} value The value to convert.
+             * @returns {number} Returns the converted number.
+             * @example
+             *
+             * _.toFinite(3.2);
+             * // => 3.2
+             *
+             * _.toFinite(Number.MIN_VALUE);
+             * // => 5e-324
+             *
+             * _.toFinite(Infinity);
+             * // => 1.7976931348623157e+308
+             *
+             * _.toFinite('3.2');
+             * // => 3.2
+             */
+            function toFinite(value) {
+              if (!value) {
+                return value === 0 ? value : 0;
+              }
+              value = toNumber(value);
+              if (value === INFINITY || value === -INFINITY) {
+                var sign = value < 0 ? -1 : 1;
+                return sign * MAX_INTEGER;
+              }
+              return value === value ? value : 0;
+            }
+
+            /**
+             * Converts `value` to an integer.
+             *
+             * **Note:** This method is loosely based on
+             * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Lang
+             * @param {*} value The value to convert.
+             * @returns {number} Returns the converted integer.
+             * @example
+             *
+             * _.toInteger(3.2);
+             * // => 3
+             *
+             * _.toInteger(Number.MIN_VALUE);
+             * // => 0
+             *
+             * _.toInteger(Infinity);
+             * // => 1.7976931348623157e+308
+             *
+             * _.toInteger('3.2');
+             * // => 3
+             */
+            function toInteger(value) {
+              var result = toFinite(value),
+                remainder = result % 1;
+
+              return result === result ? (remainder ? result - remainder : result) : 0;
+            }
+
+            /**
+             * Converts `value` to an integer suitable for use as the length of an
+             * array-like object.
+             *
+             * **Note:** This method is based on
+             * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Lang
+             * @param {*} value The value to convert.
+             * @returns {number} Returns the converted integer.
+             * @example
+             *
+             * _.toLength(3.2);
+             * // => 3
+             *
+             * _.toLength(Number.MIN_VALUE);
+             * // => 0
+             *
+             * _.toLength(Infinity);
+             * // => 4294967295
+             *
+             * _.toLength('3.2');
+             * // => 3
+             */
+            function toLength(value) {
+              return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0;
+            }
+
+            /**
+             * Converts `value` to a number.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Lang
+             * @param {*} value The value to process.
+             * @returns {number} Returns the number.
+             * @example
+             *
+             * _.toNumber(3.2);
+             * // => 3.2
+             *
+             * _.toNumber(Number.MIN_VALUE);
+             * // => 5e-324
+             *
+             * _.toNumber(Infinity);
+             * // => Infinity
+             *
+             * _.toNumber('3.2');
+             * // => 3.2
+             */
+            function toNumber(value) {
+              if (typeof value == 'number') {
+                return value;
+              }
+              if (isSymbol(value)) {
+                return NAN;
+              }
+              if (isObject(value)) {
+                var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
+                value = isObject(other) ? other + '' : other;
+              }
+              if (typeof value != 'string') {
+                return value === 0 ? value : +value;
+              }
+              value = value.replace(reTrim, '');
+              var isBinary = reIsBinary.test(value);
+              return isBinary || reIsOctal.test(value)
+                ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
+                : reIsBadHex.test(value)
+                ? NAN
+                : +value;
+            }
+
+            /**
+             * Converts `value` to a plain object flattening inherited enumerable string
+             * keyed properties of `value` to own properties of the plain object.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Lang
+             * @param {*} value The value to convert.
+             * @returns {Object} Returns the converted plain object.
+             * @example
+             *
+             * function Foo() {
+             *   this.b = 2;
+             * }
+             *
+             * Foo.prototype.c = 3;
+             *
+             * _.assign({ 'a': 1 }, new Foo);
+             * // => { 'a': 1, 'b': 2 }
+             *
+             * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
+             * // => { 'a': 1, 'b': 2, 'c': 3 }
+             */
+            function toPlainObject(value) {
+              return copyObject(value, keysIn(value));
+            }
+
+            /**
+             * Converts `value` to a safe integer. A safe integer can be compared and
+             * represented correctly.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Lang
+             * @param {*} value The value to convert.
+             * @returns {number} Returns the converted integer.
+             * @example
+             *
+             * _.toSafeInteger(3.2);
+             * // => 3
+             *
+             * _.toSafeInteger(Number.MIN_VALUE);
+             * // => 0
+             *
+             * _.toSafeInteger(Infinity);
+             * // => 9007199254740991
+             *
+             * _.toSafeInteger('3.2');
+             * // => 3
+             */
+            function toSafeInteger(value) {
+              return value
+                ? baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER)
+                : value === 0
+                ? value
+                : 0;
+            }
+
+            /**
+             * Converts `value` to a string. An empty string is returned for `null`
+             * and `undefined` values. The sign of `-0` is preserved.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Lang
+             * @param {*} value The value to convert.
+             * @returns {string} Returns the converted string.
+             * @example
+             *
+             * _.toString(null);
+             * // => ''
+             *
+             * _.toString(-0);
+             * // => '-0'
+             *
+             * _.toString([1, 2, 3]);
+             * // => '1,2,3'
+             */
+            function toString(value) {
+              return value == null ? '' : baseToString(value);
+            }
+
+            /*------------------------------------------------------------------------*/
+
+            /**
+             * Assigns own enumerable string keyed properties of source objects to the
+             * destination object. Source objects are applied from left to right.
+             * Subsequent sources overwrite property assignments of previous sources.
+             *
+             * **Note:** This method mutates `object` and is loosely based on
+             * [`Object.assign`](https://mdn.io/Object/assign).
+             *
+             * @static
+             * @memberOf _
+             * @since 0.10.0
+             * @category Object
+             * @param {Object} object The destination object.
+             * @param {...Object} [sources] The source objects.
+             * @returns {Object} Returns `object`.
+             * @see _.assignIn
+             * @example
+             *
+             * function Foo() {
+             *   this.a = 1;
+             * }
+             *
+             * function Bar() {
+             *   this.c = 3;
+             * }
+             *
+             * Foo.prototype.b = 2;
+             * Bar.prototype.d = 4;
+             *
+             * _.assign({ 'a': 0 }, new Foo, new Bar);
+             * // => { 'a': 1, 'c': 3 }
+             */
+            var assign = createAssigner(function (object, source) {
+              if (isPrototype(source) || isArrayLike(source)) {
+                copyObject(source, keys(source), object);
+                return;
+              }
+              for (var key in source) {
+                if (hasOwnProperty.call(source, key)) {
+                  assignValue(object, key, source[key]);
+                }
+              }
+            });
+
+            /**
+             * This method is like `_.assign` except that it iterates over own and
+             * inherited source properties.
+             *
+             * **Note:** This method mutates `object`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @alias extend
+             * @category Object
+             * @param {Object} object The destination object.
+             * @param {...Object} [sources] The source objects.
+             * @returns {Object} Returns `object`.
+             * @see _.assign
+             * @example
+             *
+             * function Foo() {
+             *   this.a = 1;
+             * }
+             *
+             * function Bar() {
+             *   this.c = 3;
+             * }
+             *
+             * Foo.prototype.b = 2;
+             * Bar.prototype.d = 4;
+             *
+             * _.assignIn({ 'a': 0 }, new Foo, new Bar);
+             * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }
+             */
+            var assignIn = createAssigner(function (object, source) {
+              copyObject(source, keysIn(source), object);
+            });
+
+            /**
+             * This method is like `_.assignIn` except that it accepts `customizer`
+             * which is invoked to produce the assigned values. If `customizer` returns
+             * `undefined`, assignment is handled by the method instead. The `customizer`
+             * is invoked with five arguments: (objValue, srcValue, key, object, source).
+             *
+             * **Note:** This method mutates `object`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @alias extendWith
+             * @category Object
+             * @param {Object} object The destination object.
+             * @param {...Object} sources The source objects.
+             * @param {Function} [customizer] The function to customize assigned values.
+             * @returns {Object} Returns `object`.
+             * @see _.assignWith
+             * @example
+             *
+             * function customizer(objValue, srcValue) {
+             *   return _.isUndefined(objValue) ? srcValue : objValue;
+             * }
+             *
+             * var defaults = _.partialRight(_.assignInWith, customizer);
+             *
+             * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
+             * // => { 'a': 1, 'b': 2 }
+             */
+            var assignInWith = createAssigner(function (object, source, srcIndex, customizer) {
+              copyObject(source, keysIn(source), object, customizer);
+            });
+
+            /**
+             * This method is like `_.assign` except that it accepts `customizer`
+             * which is invoked to produce the assigned values. If `customizer` returns
+             * `undefined`, assignment is handled by the method instead. The `customizer`
+             * is invoked with five arguments: (objValue, srcValue, key, object, source).
+             *
+             * **Note:** This method mutates `object`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Object
+             * @param {Object} object The destination object.
+             * @param {...Object} sources The source objects.
+             * @param {Function} [customizer] The function to customize assigned values.
+             * @returns {Object} Returns `object`.
+             * @see _.assignInWith
+             * @example
+             *
+             * function customizer(objValue, srcValue) {
+             *   return _.isUndefined(objValue) ? srcValue : objValue;
+             * }
+             *
+             * var defaults = _.partialRight(_.assignWith, customizer);
+             *
+             * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
+             * // => { 'a': 1, 'b': 2 }
+             */
+            var assignWith = createAssigner(function (object, source, srcIndex, customizer) {
+              copyObject(source, keys(source), object, customizer);
+            });
+
+            /**
+             * Creates an array of values corresponding to `paths` of `object`.
+             *
+             * @static
+             * @memberOf _
+             * @since 1.0.0
+             * @category Object
+             * @param {Object} object The object to iterate over.
+             * @param {...(string|string[])} [paths] The property paths to pick.
+             * @returns {Array} Returns the picked values.
+             * @example
+             *
+             * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
+             *
+             * _.at(object, ['a[0].b.c', 'a[1]']);
+             * // => [3, 4]
+             */
+            var at = flatRest(baseAt);
+
+            /**
+             * Creates an object that inherits from the `prototype` object. If a
+             * `properties` object is given, its own enumerable string keyed properties
+             * are assigned to the created object.
+             *
+             * @static
+             * @memberOf _
+             * @since 2.3.0
+             * @category Object
+             * @param {Object} prototype The object to inherit from.
+             * @param {Object} [properties] The properties to assign to the object.
+             * @returns {Object} Returns the new object.
+             * @example
+             *
+             * function Shape() {
+             *   this.x = 0;
+             *   this.y = 0;
+             * }
+             *
+             * function Circle() {
+             *   Shape.call(this);
+             * }
+             *
+             * Circle.prototype = _.create(Shape.prototype, {
+             *   'constructor': Circle
+             * });
+             *
+             * var circle = new Circle;
+             * circle instanceof Circle;
+             * // => true
+             *
+             * circle instanceof Shape;
+             * // => true
+             */
+            function create(prototype, properties) {
+              var result = baseCreate(prototype);
+              return properties == null ? result : baseAssign(result, properties);
+            }
+
+            /**
+             * Assigns own and inherited enumerable string keyed properties of source
+             * objects to the destination object for all destination properties that
+             * resolve to `undefined`. Source objects are applied from left to right.
+             * Once a property is set, additional values of the same property are ignored.
+             *
+             * **Note:** This method mutates `object`.
+             *
+             * @static
+             * @since 0.1.0
+             * @memberOf _
+             * @category Object
+             * @param {Object} object The destination object.
+             * @param {...Object} [sources] The source objects.
+             * @returns {Object} Returns `object`.
+             * @see _.defaultsDeep
+             * @example
+             *
+             * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
+             * // => { 'a': 1, 'b': 2 }
+             */
+            var defaults = baseRest(function (object, sources) {
+              object = Object(object);
+
+              var index = -1;
+              var length = sources.length;
+              var guard = length > 2 ? sources[2] : undefined;
+
+              if (guard && isIterateeCall(sources[0], sources[1], guard)) {
+                length = 1;
+              }
+
+              while (++index < length) {
+                var source = sources[index];
+                var props = keysIn(source);
+                var propsIndex = -1;
+                var propsLength = props.length;
+
+                while (++propsIndex < propsLength) {
+                  var key = props[propsIndex];
+                  var value = object[key];
+
+                  if (
+                    value === undefined ||
+                    (eq(value, objectProto[key]) && !hasOwnProperty.call(object, key))
+                  ) {
+                    object[key] = source[key];
+                  }
+                }
+              }
+
+              return object;
+            });
+
+            /**
+             * This method is like `_.defaults` except that it recursively assigns
+             * default properties.
+             *
+             * **Note:** This method mutates `object`.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.10.0
+             * @category Object
+             * @param {Object} object The destination object.
+             * @param {...Object} [sources] The source objects.
+             * @returns {Object} Returns `object`.
+             * @see _.defaults
+             * @example
+             *
+             * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } });
+             * // => { 'a': { 'b': 2, 'c': 3 } }
+             */
+            var defaultsDeep = baseRest(function (args) {
+              args.push(undefined, customDefaultsMerge);
+              return apply(mergeWith, undefined, args);
+            });
+
+            /**
+             * This method is like `_.find` except that it returns the key of the first
+             * element `predicate` returns truthy for instead of the element itself.
+             *
+             * @static
+             * @memberOf _
+             * @since 1.1.0
+             * @category Object
+             * @param {Object} object The object to inspect.
+             * @param {Function} [predicate=_.identity] The function invoked per iteration.
+             * @returns {string|undefined} Returns the key of the matched element,
+             *  else `undefined`.
+             * @example
+             *
+             * var users = {
+             *   'barney':  { 'age': 36, 'active': true },
+             *   'fred':    { 'age': 40, 'active': false },
+             *   'pebbles': { 'age': 1,  'active': true }
+             * };
+             *
+             * _.findKey(users, function(o) { return o.age < 40; });
+             * // => 'barney' (iteration order is not guaranteed)
+             *
+             * // The `_.matches` iteratee shorthand.
+             * _.findKey(users, { 'age': 1, 'active': true });
+             * // => 'pebbles'
+             *
+             * // The `_.matchesProperty` iteratee shorthand.
+             * _.findKey(users, ['active', false]);
+             * // => 'fred'
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.findKey(users, 'active');
+             * // => 'barney'
+             */
+            function findKey(object, predicate) {
+              return baseFindKey(object, getIteratee(predicate, 3), baseForOwn);
+            }
+
+            /**
+             * This method is like `_.findKey` except that it iterates over elements of
+             * a collection in the opposite order.
+             *
+             * @static
+             * @memberOf _
+             * @since 2.0.0
+             * @category Object
+             * @param {Object} object The object to inspect.
+             * @param {Function} [predicate=_.identity] The function invoked per iteration.
+             * @returns {string|undefined} Returns the key of the matched element,
+             *  else `undefined`.
+             * @example
+             *
+             * var users = {
+             *   'barney':  { 'age': 36, 'active': true },
+             *   'fred':    { 'age': 40, 'active': false },
+             *   'pebbles': { 'age': 1,  'active': true }
+             * };
+             *
+             * _.findLastKey(users, function(o) { return o.age < 40; });
+             * // => returns 'pebbles' assuming `_.findKey` returns 'barney'
+             *
+             * // The `_.matches` iteratee shorthand.
+             * _.findLastKey(users, { 'age': 36, 'active': true });
+             * // => 'barney'
+             *
+             * // The `_.matchesProperty` iteratee shorthand.
+             * _.findLastKey(users, ['active', false]);
+             * // => 'fred'
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.findLastKey(users, 'active');
+             * // => 'pebbles'
+             */
+            function findLastKey(object, predicate) {
+              return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight);
+            }
+
+            /**
+             * Iterates over own and inherited enumerable string keyed properties of an
+             * object and invokes `iteratee` for each property. The iteratee is invoked
+             * with three arguments: (value, key, object). Iteratee functions may exit
+             * iteration early by explicitly returning `false`.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.3.0
+             * @category Object
+             * @param {Object} object The object to iterate over.
+             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+             * @returns {Object} Returns `object`.
+             * @see _.forInRight
+             * @example
+             *
+             * function Foo() {
+             *   this.a = 1;
+             *   this.b = 2;
+             * }
+             *
+             * Foo.prototype.c = 3;
+             *
+             * _.forIn(new Foo, function(value, key) {
+             *   console.log(key);
+             * });
+             * // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed).
+             */
+            function forIn(object, iteratee) {
+              return object == null ? object : baseFor(object, getIteratee(iteratee, 3), keysIn);
+            }
+
+            /**
+             * This method is like `_.forIn` except that it iterates over properties of
+             * `object` in the opposite order.
+             *
+             * @static
+             * @memberOf _
+             * @since 2.0.0
+             * @category Object
+             * @param {Object} object The object to iterate over.
+             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+             * @returns {Object} Returns `object`.
+             * @see _.forIn
+             * @example
+             *
+             * function Foo() {
+             *   this.a = 1;
+             *   this.b = 2;
+             * }
+             *
+             * Foo.prototype.c = 3;
+             *
+             * _.forInRight(new Foo, function(value, key) {
+             *   console.log(key);
+             * });
+             * // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'.
+             */
+            function forInRight(object, iteratee) {
+              return object == null ? object : baseForRight(object, getIteratee(iteratee, 3), keysIn);
+            }
+
+            /**
+             * Iterates over own enumerable string keyed properties of an object and
+             * invokes `iteratee` for each property. The iteratee is invoked with three
+             * arguments: (value, key, object). Iteratee functions may exit iteration
+             * early by explicitly returning `false`.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.3.0
+             * @category Object
+             * @param {Object} object The object to iterate over.
+             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+             * @returns {Object} Returns `object`.
+             * @see _.forOwnRight
+             * @example
+             *
+             * function Foo() {
+             *   this.a = 1;
+             *   this.b = 2;
+             * }
+             *
+             * Foo.prototype.c = 3;
+             *
+             * _.forOwn(new Foo, function(value, key) {
+             *   console.log(key);
+             * });
+             * // => Logs 'a' then 'b' (iteration order is not guaranteed).
+             */
+            function forOwn(object, iteratee) {
+              return object && baseForOwn(object, getIteratee(iteratee, 3));
+            }
+
+            /**
+             * This method is like `_.forOwn` except that it iterates over properties of
+             * `object` in the opposite order.
+             *
+             * @static
+             * @memberOf _
+             * @since 2.0.0
+             * @category Object
+             * @param {Object} object The object to iterate over.
+             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+             * @returns {Object} Returns `object`.
+             * @see _.forOwn
+             * @example
+             *
+             * function Foo() {
+             *   this.a = 1;
+             *   this.b = 2;
+             * }
+             *
+             * Foo.prototype.c = 3;
+             *
+             * _.forOwnRight(new Foo, function(value, key) {
+             *   console.log(key);
+             * });
+             * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'.
+             */
+            function forOwnRight(object, iteratee) {
+              return object && baseForOwnRight(object, getIteratee(iteratee, 3));
+            }
+
+            /**
+             * Creates an array of function property names from own enumerable properties
+             * of `object`.
+             *
+             * @static
+             * @since 0.1.0
+             * @memberOf _
+             * @category Object
+             * @param {Object} object The object to inspect.
+             * @returns {Array} Returns the function names.
+             * @see _.functionsIn
+             * @example
+             *
+             * function Foo() {
+             *   this.a = _.constant('a');
+             *   this.b = _.constant('b');
+             * }
+             *
+             * Foo.prototype.c = _.constant('c');
+             *
+             * _.functions(new Foo);
+             * // => ['a', 'b']
+             */
+            function functions(object) {
+              return object == null ? [] : baseFunctions(object, keys(object));
+            }
+
+            /**
+             * Creates an array of function property names from own and inherited
+             * enumerable properties of `object`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Object
+             * @param {Object} object The object to inspect.
+             * @returns {Array} Returns the function names.
+             * @see _.functions
+             * @example
+             *
+             * function Foo() {
+             *   this.a = _.constant('a');
+             *   this.b = _.constant('b');
+             * }
+             *
+             * Foo.prototype.c = _.constant('c');
+             *
+             * _.functionsIn(new Foo);
+             * // => ['a', 'b', 'c']
+             */
+            function functionsIn(object) {
+              return object == null ? [] : baseFunctions(object, keysIn(object));
+            }
+
+            /**
+             * Gets the value at `path` of `object`. If the resolved value is
+             * `undefined`, the `defaultValue` is returned in its place.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.7.0
+             * @category Object
+             * @param {Object} object The object to query.
+             * @param {Array|string} path The path of the property to get.
+             * @param {*} [defaultValue] The value returned for `undefined` resolved values.
+             * @returns {*} Returns the resolved value.
+             * @example
+             *
+             * var object = { 'a': [{ 'b': { 'c': 3 } }] };
+             *
+             * _.get(object, 'a[0].b.c');
+             * // => 3
+             *
+             * _.get(object, ['a', '0', 'b', 'c']);
+             * // => 3
+             *
+             * _.get(object, 'a.b.c', 'default');
+             * // => 'default'
+             */
+            function get(object, path, defaultValue) {
+              var result = object == null ? undefined : baseGet(object, path);
+              return result === undefined ? defaultValue : result;
+            }
+
+            /**
+             * Checks if `path` is a direct property of `object`.
+             *
+             * @static
+             * @since 0.1.0
+             * @memberOf _
+             * @category Object
+             * @param {Object} object The object to query.
+             * @param {Array|string} path The path to check.
+             * @returns {boolean} Returns `true` if `path` exists, else `false`.
+             * @example
+             *
+             * var object = { 'a': { 'b': 2 } };
+             * var other = _.create({ 'a': _.create({ 'b': 2 }) });
+             *
+             * _.has(object, 'a');
+             * // => true
+             *
+             * _.has(object, 'a.b');
+             * // => true
+             *
+             * _.has(object, ['a', 'b']);
+             * // => true
+             *
+             * _.has(other, 'a');
+             * // => false
+             */
+            function has(object, path) {
+              return object != null && hasPath(object, path, baseHas);
+            }
+
+            /**
+             * Checks if `path` is a direct or inherited property of `object`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Object
+             * @param {Object} object The object to query.
+             * @param {Array|string} path The path to check.
+             * @returns {boolean} Returns `true` if `path` exists, else `false`.
+             * @example
+             *
+             * var object = _.create({ 'a': _.create({ 'b': 2 }) });
+             *
+             * _.hasIn(object, 'a');
+             * // => true
+             *
+             * _.hasIn(object, 'a.b');
+             * // => true
+             *
+             * _.hasIn(object, ['a', 'b']);
+             * // => true
+             *
+             * _.hasIn(object, 'b');
+             * // => false
+             */
+            function hasIn(object, path) {
+              return object != null && hasPath(object, path, baseHasIn);
+            }
+
+            /**
+             * Creates an object composed of the inverted keys and values of `object`.
+             * If `object` contains duplicate values, subsequent values overwrite
+             * property assignments of previous values.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.7.0
+             * @category Object
+             * @param {Object} object The object to invert.
+             * @returns {Object} Returns the new inverted object.
+             * @example
+             *
+             * var object = { 'a': 1, 'b': 2, 'c': 1 };
+             *
+             * _.invert(object);
+             * // => { '1': 'c', '2': 'b' }
+             */
+            var invert = createInverter(function (result, value, key) {
+              if (value != null && typeof value.toString != 'function') {
+                value = nativeObjectToString.call(value);
+              }
+
+              result[value] = key;
+            }, constant(identity));
+
+            /**
+             * This method is like `_.invert` except that the inverted object is generated
+             * from the results of running each element of `object` thru `iteratee`. The
+             * corresponding inverted value of each inverted key is an array of keys
+             * responsible for generating the inverted value. The iteratee is invoked
+             * with one argument: (value).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.1.0
+             * @category Object
+             * @param {Object} object The object to invert.
+             * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+             * @returns {Object} Returns the new inverted object.
+             * @example
+             *
+             * var object = { 'a': 1, 'b': 2, 'c': 1 };
+             *
+             * _.invertBy(object);
+             * // => { '1': ['a', 'c'], '2': ['b'] }
+             *
+             * _.invertBy(object, function(value) {
+             *   return 'group' + value;
+             * });
+             * // => { 'group1': ['a', 'c'], 'group2': ['b'] }
+             */
+            var invertBy = createInverter(function (result, value, key) {
+              if (value != null && typeof value.toString != 'function') {
+                value = nativeObjectToString.call(value);
+              }
+
+              if (hasOwnProperty.call(result, value)) {
+                result[value].push(key);
+              } else {
+                result[value] = [key];
+              }
+            }, getIteratee);
+
+            /**
+             * Invokes the method at `path` of `object`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Object
+             * @param {Object} object The object to query.
+             * @param {Array|string} path The path of the method to invoke.
+             * @param {...*} [args] The arguments to invoke the method with.
+             * @returns {*} Returns the result of the invoked method.
+             * @example
+             *
+             * var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] };
+             *
+             * _.invoke(object, 'a[0].b.c.slice', 1, 3);
+             * // => [2, 3]
+             */
+            var invoke = baseRest(baseInvoke);
+
+            /**
+             * Creates an array of the own enumerable property names of `object`.
+             *
+             * **Note:** Non-object values are coerced to objects. See the
+             * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
+             * for more details.
+             *
+             * @static
+             * @since 0.1.0
+             * @memberOf _
+             * @category Object
+             * @param {Object} object The object to query.
+             * @returns {Array} Returns the array of property names.
+             * @example
+             *
+             * function Foo() {
+             *   this.a = 1;
+             *   this.b = 2;
+             * }
+             *
+             * Foo.prototype.c = 3;
+             *
+             * _.keys(new Foo);
+             * // => ['a', 'b'] (iteration order is not guaranteed)
+             *
+             * _.keys('hi');
+             * // => ['0', '1']
+             */
+            function keys(object) {
+              return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);
+            }
+
+            /**
+             * Creates an array of the own and inherited enumerable property names of `object`.
+             *
+             * **Note:** Non-object values are coerced to objects.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Object
+             * @param {Object} object The object to query.
+             * @returns {Array} Returns the array of property names.
+             * @example
+             *
+             * function Foo() {
+             *   this.a = 1;
+             *   this.b = 2;
+             * }
+             *
+             * Foo.prototype.c = 3;
+             *
+             * _.keysIn(new Foo);
+             * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
+             */
+            function keysIn(object) {
+              return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);
+            }
+
+            /**
+             * The opposite of `_.mapValues`; this method creates an object with the
+             * same values as `object` and keys generated by running each own enumerable
+             * string keyed property of `object` thru `iteratee`. The iteratee is invoked
+             * with three arguments: (value, key, object).
+             *
+             * @static
+             * @memberOf _
+             * @since 3.8.0
+             * @category Object
+             * @param {Object} object The object to iterate over.
+             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+             * @returns {Object} Returns the new mapped object.
+             * @see _.mapValues
+             * @example
+             *
+             * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) {
+             *   return key + value;
+             * });
+             * // => { 'a1': 1, 'b2': 2 }
+             */
+            function mapKeys(object, iteratee) {
+              var result = {};
+              iteratee = getIteratee(iteratee, 3);
+
+              baseForOwn(object, function (value, key, object) {
+                baseAssignValue(result, iteratee(value, key, object), value);
+              });
+              return result;
+            }
+
+            /**
+             * Creates an object with the same keys as `object` and values generated
+             * by running each own enumerable string keyed property of `object` thru
+             * `iteratee`. The iteratee is invoked with three arguments:
+             * (value, key, object).
+             *
+             * @static
+             * @memberOf _
+             * @since 2.4.0
+             * @category Object
+             * @param {Object} object The object to iterate over.
+             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+             * @returns {Object} Returns the new mapped object.
+             * @see _.mapKeys
+             * @example
+             *
+             * var users = {
+             *   'fred':    { 'user': 'fred',    'age': 40 },
+             *   'pebbles': { 'user': 'pebbles', 'age': 1 }
+             * };
+             *
+             * _.mapValues(users, function(o) { return o.age; });
+             * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
+             *
+             * // The `_.property` iteratee shorthand.
+             * _.mapValues(users, 'age');
+             * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
+             */
+            function mapValues(object, iteratee) {
+              var result = {};
+              iteratee = getIteratee(iteratee, 3);
+
+              baseForOwn(object, function (value, key, object) {
+                baseAssignValue(result, key, iteratee(value, key, object));
+              });
+              return result;
+            }
+
+            /**
+             * This method is like `_.assign` except that it recursively merges own and
+             * inherited enumerable string keyed properties of source objects into the
+             * destination object. Source properties that resolve to `undefined` are
+             * skipped if a destination value exists. Array and plain object properties
+             * are merged recursively. Other objects and value types are overridden by
+             * assignment. Source objects are applied from left to right. Subsequent
+             * sources overwrite property assignments of previous sources.
+             *
+             * **Note:** This method mutates `object`.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.5.0
+             * @category Object
+             * @param {Object} object The destination object.
+             * @param {...Object} [sources] The source objects.
+             * @returns {Object} Returns `object`.
+             * @example
+             *
+             * var object = {
+             *   'a': [{ 'b': 2 }, { 'd': 4 }]
+             * };
+             *
+             * var other = {
+             *   'a': [{ 'c': 3 }, { 'e': 5 }]
+             * };
+             *
+             * _.merge(object, other);
+             * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
+             */
+            var merge = createAssigner(function (object, source, srcIndex) {
+              baseMerge(object, source, srcIndex);
+            });
+
+            /**
+             * This method is like `_.merge` except that it accepts `customizer` which
+             * is invoked to produce the merged values of the destination and source
+             * properties. If `customizer` returns `undefined`, merging is handled by the
+             * method instead. The `customizer` is invoked with six arguments:
+             * (objValue, srcValue, key, object, source, stack).
+             *
+             * **Note:** This method mutates `object`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Object
+             * @param {Object} object The destination object.
+             * @param {...Object} sources The source objects.
+             * @param {Function} customizer The function to customize assigned values.
+             * @returns {Object} Returns `object`.
+             * @example
+             *
+             * function customizer(objValue, srcValue) {
+             *   if (_.isArray(objValue)) {
+             *     return objValue.concat(srcValue);
+             *   }
+             * }
+             *
+             * var object = { 'a': [1], 'b': [2] };
+             * var other = { 'a': [3], 'b': [4] };
+             *
+             * _.mergeWith(object, other, customizer);
+             * // => { 'a': [1, 3], 'b': [2, 4] }
+             */
+            var mergeWith = createAssigner(function (object, source, srcIndex, customizer) {
+              baseMerge(object, source, srcIndex, customizer);
+            });
+
+            /**
+             * The opposite of `_.pick`; this method creates an object composed of the
+             * own and inherited enumerable property paths of `object` that are not omitted.
+             *
+             * **Note:** This method is considerably slower than `_.pick`.
+             *
+             * @static
+             * @since 0.1.0
+             * @memberOf _
+             * @category Object
+             * @param {Object} object The source object.
+             * @param {...(string|string[])} [paths] The property paths to omit.
+             * @returns {Object} Returns the new object.
+             * @example
+             *
+             * var object = { 'a': 1, 'b': '2', 'c': 3 };
+             *
+             * _.omit(object, ['a', 'c']);
+             * // => { 'b': '2' }
+             */
+            var omit = flatRest(function (object, paths) {
+              var result = {};
+              if (object == null) {
+                return result;
+              }
+              var isDeep = false;
+              paths = arrayMap(paths, function (path) {
+                path = castPath(path, object);
+                isDeep || (isDeep = path.length > 1);
+                return path;
+              });
+              copyObject(object, getAllKeysIn(object), result);
+              if (isDeep) {
+                result = baseClone(
+                  result,
+                  CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG,
+                  customOmitClone
+                );
+              }
+              var length = paths.length;
+              while (length--) {
+                baseUnset(result, paths[length]);
+              }
+              return result;
+            });
+
+            /**
+             * The opposite of `_.pickBy`; this method creates an object composed of
+             * the own and inherited enumerable string keyed properties of `object` that
+             * `predicate` doesn't return truthy for. The predicate is invoked with two
+             * arguments: (value, key).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Object
+             * @param {Object} object The source object.
+             * @param {Function} [predicate=_.identity] The function invoked per property.
+             * @returns {Object} Returns the new object.
+             * @example
+             *
+             * var object = { 'a': 1, 'b': '2', 'c': 3 };
+             *
+             * _.omitBy(object, _.isNumber);
+             * // => { 'b': '2' }
+             */
+            function omitBy(object, predicate) {
+              return pickBy(object, negate(getIteratee(predicate)));
+            }
+
+            /**
+             * Creates an object composed of the picked `object` properties.
+             *
+             * @static
+             * @since 0.1.0
+             * @memberOf _
+             * @category Object
+             * @param {Object} object The source object.
+             * @param {...(string|string[])} [paths] The property paths to pick.
+             * @returns {Object} Returns the new object.
+             * @example
+             *
+             * var object = { 'a': 1, 'b': '2', 'c': 3 };
+             *
+             * _.pick(object, ['a', 'c']);
+             * // => { 'a': 1, 'c': 3 }
+             */
+            var pick = flatRest(function (object, paths) {
+              return object == null ? {} : basePick(object, paths);
+            });
+
+            /**
+             * Creates an object composed of the `object` properties `predicate` returns
+             * truthy for. The predicate is invoked with two arguments: (value, key).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Object
+             * @param {Object} object The source object.
+             * @param {Function} [predicate=_.identity] The function invoked per property.
+             * @returns {Object} Returns the new object.
+             * @example
+             *
+             * var object = { 'a': 1, 'b': '2', 'c': 3 };
+             *
+             * _.pickBy(object, _.isNumber);
+             * // => { 'a': 1, 'c': 3 }
+             */
+            function pickBy(object, predicate) {
+              if (object == null) {
+                return {};
+              }
+              var props = arrayMap(getAllKeysIn(object), function (prop) {
+                return [prop];
+              });
+              predicate = getIteratee(predicate);
+              return basePickBy(object, props, function (value, path) {
+                return predicate(value, path[0]);
+              });
+            }
+
+            /**
+             * This method is like `_.get` except that if the resolved value is a
+             * function it's invoked with the `this` binding of its parent object and
+             * its result is returned.
+             *
+             * @static
+             * @since 0.1.0
+             * @memberOf _
+             * @category Object
+             * @param {Object} object The object to query.
+             * @param {Array|string} path The path of the property to resolve.
+             * @param {*} [defaultValue] The value returned for `undefined` resolved values.
+             * @returns {*} Returns the resolved value.
+             * @example
+             *
+             * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] };
+             *
+             * _.result(object, 'a[0].b.c1');
+             * // => 3
+             *
+             * _.result(object, 'a[0].b.c2');
+             * // => 4
+             *
+             * _.result(object, 'a[0].b.c3', 'default');
+             * // => 'default'
+             *
+             * _.result(object, 'a[0].b.c3', _.constant('default'));
+             * // => 'default'
+             */
+            function result(object, path, defaultValue) {
+              path = castPath(path, object);
+
+              var index = -1,
+                length = path.length;
+
+              // Ensure the loop is entered when path is empty.
+              if (!length) {
+                length = 1;
+                object = undefined;
+              }
+              while (++index < length) {
+                var value = object == null ? undefined : object[toKey(path[index])];
+                if (value === undefined) {
+                  index = length;
+                  value = defaultValue;
+                }
+                object = isFunction(value) ? value.call(object) : value;
+              }
+              return object;
+            }
+
+            /**
+             * Sets the value at `path` of `object`. If a portion of `path` doesn't exist,
+             * it's created. Arrays are created for missing index properties while objects
+             * are created for all other missing properties. Use `_.setWith` to customize
+             * `path` creation.
+             *
+             * **Note:** This method mutates `object`.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.7.0
+             * @category Object
+             * @param {Object} object The object to modify.
+             * @param {Array|string} path The path of the property to set.
+             * @param {*} value The value to set.
+             * @returns {Object} Returns `object`.
+             * @example
+             *
+             * var object = { 'a': [{ 'b': { 'c': 3 } }] };
+             *
+             * _.set(object, 'a[0].b.c', 4);
+             * console.log(object.a[0].b.c);
+             * // => 4
+             *
+             * _.set(object, ['x', '0', 'y', 'z'], 5);
+             * console.log(object.x[0].y.z);
+             * // => 5
+             */
+            function set(object, path, value) {
+              return object == null ? object : baseSet(object, path, value);
+            }
+
+            /**
+             * This method is like `_.set` except that it accepts `customizer` which is
+             * invoked to produce the objects of `path`.  If `customizer` returns `undefined`
+             * path creation is handled by the method instead. The `customizer` is invoked
+             * with three arguments: (nsValue, key, nsObject).
+             *
+             * **Note:** This method mutates `object`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Object
+             * @param {Object} object The object to modify.
+             * @param {Array|string} path The path of the property to set.
+             * @param {*} value The value to set.
+             * @param {Function} [customizer] The function to customize assigned values.
+             * @returns {Object} Returns `object`.
+             * @example
+             *
+             * var object = {};
+             *
+             * _.setWith(object, '[0][1]', 'a', Object);
+             * // => { '0': { '1': 'a' } }
+             */
+            function setWith(object, path, value, customizer) {
+              customizer = typeof customizer == 'function' ? customizer : undefined;
+              return object == null ? object : baseSet(object, path, value, customizer);
+            }
+
+            /**
+             * Creates an array of own enumerable string keyed-value pairs for `object`
+             * which can be consumed by `_.fromPairs`. If `object` is a map or set, its
+             * entries are returned.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @alias entries
+             * @category Object
+             * @param {Object} object The object to query.
+             * @returns {Array} Returns the key-value pairs.
+             * @example
+             *
+             * function Foo() {
+             *   this.a = 1;
+             *   this.b = 2;
+             * }
+             *
+             * Foo.prototype.c = 3;
+             *
+             * _.toPairs(new Foo);
+             * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed)
+             */
+            var toPairs = createToPairs(keys);
+
+            /**
+             * Creates an array of own and inherited enumerable string keyed-value pairs
+             * for `object` which can be consumed by `_.fromPairs`. If `object` is a map
+             * or set, its entries are returned.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @alias entriesIn
+             * @category Object
+             * @param {Object} object The object to query.
+             * @returns {Array} Returns the key-value pairs.
+             * @example
+             *
+             * function Foo() {
+             *   this.a = 1;
+             *   this.b = 2;
+             * }
+             *
+             * Foo.prototype.c = 3;
+             *
+             * _.toPairsIn(new Foo);
+             * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed)
+             */
+            var toPairsIn = createToPairs(keysIn);
+
+            /**
+             * An alternative to `_.reduce`; this method transforms `object` to a new
+             * `accumulator` object which is the result of running each of its own
+             * enumerable string keyed properties thru `iteratee`, with each invocation
+             * potentially mutating the `accumulator` object. If `accumulator` is not
+             * provided, a new object with the same `[[Prototype]]` will be used. The
+             * iteratee is invoked with four arguments: (accumulator, value, key, object).
+             * Iteratee functions may exit iteration early by explicitly returning `false`.
+             *
+             * @static
+             * @memberOf _
+             * @since 1.3.0
+             * @category Object
+             * @param {Object} object The object to iterate over.
+             * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+             * @param {*} [accumulator] The custom accumulator value.
+             * @returns {*} Returns the accumulated value.
+             * @example
+             *
+             * _.transform([2, 3, 4], function(result, n) {
+             *   result.push(n *= n);
+             *   return n % 2 == 0;
+             * }, []);
+             * // => [4, 9]
+             *
+             * _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
+             *   (result[value] || (result[value] = [])).push(key);
+             * }, {});
+             * // => { '1': ['a', 'c'], '2': ['b'] }
+             */
+            function transform(object, iteratee, accumulator) {
+              var isArr = isArray(object),
+                isArrLike = isArr || isBuffer(object) || isTypedArray(object);
+
+              iteratee = getIteratee(iteratee, 4);
+              if (accumulator == null) {
+                var Ctor = object && object.constructor;
+                if (isArrLike) {
+                  accumulator = isArr ? new Ctor() : [];
+                } else if (isObject(object)) {
+                  accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {};
+                } else {
+                  accumulator = {};
+                }
+              }
+              (isArrLike ? arrayEach : baseForOwn)(object, function (value, index, object) {
+                return iteratee(accumulator, value, index, object);
+              });
+              return accumulator;
+            }
+
+            /**
+             * Removes the property at `path` of `object`.
+             *
+             * **Note:** This method mutates `object`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Object
+             * @param {Object} object The object to modify.
+             * @param {Array|string} path The path of the property to unset.
+             * @returns {boolean} Returns `true` if the property is deleted, else `false`.
+             * @example
+             *
+             * var object = { 'a': [{ 'b': { 'c': 7 } }] };
+             * _.unset(object, 'a[0].b.c');
+             * // => true
+             *
+             * console.log(object);
+             * // => { 'a': [{ 'b': {} }] };
+             *
+             * _.unset(object, ['a', '0', 'b', 'c']);
+             * // => true
+             *
+             * console.log(object);
+             * // => { 'a': [{ 'b': {} }] };
+             */
+            function unset(object, path) {
+              return object == null ? true : baseUnset(object, path);
+            }
+
+            /**
+             * This method is like `_.set` except that accepts `updater` to produce the
+             * value to set. Use `_.updateWith` to customize `path` creation. The `updater`
+             * is invoked with one argument: (value).
+             *
+             * **Note:** This method mutates `object`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.6.0
+             * @category Object
+             * @param {Object} object The object to modify.
+             * @param {Array|string} path The path of the property to set.
+             * @param {Function} updater The function to produce the updated value.
+             * @returns {Object} Returns `object`.
+             * @example
+             *
+             * var object = { 'a': [{ 'b': { 'c': 3 } }] };
+             *
+             * _.update(object, 'a[0].b.c', function(n) { return n * n; });
+             * console.log(object.a[0].b.c);
+             * // => 9
+             *
+             * _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; });
+             * console.log(object.x[0].y.z);
+             * // => 0
+             */
+            function update(object, path, updater) {
+              return object == null ? object : baseUpdate(object, path, castFunction(updater));
+            }
+
+            /**
+             * This method is like `_.update` except that it accepts `customizer` which is
+             * invoked to produce the objects of `path`.  If `customizer` returns `undefined`
+             * path creation is handled by the method instead. The `customizer` is invoked
+             * with three arguments: (nsValue, key, nsObject).
+             *
+             * **Note:** This method mutates `object`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.6.0
+             * @category Object
+             * @param {Object} object The object to modify.
+             * @param {Array|string} path The path of the property to set.
+             * @param {Function} updater The function to produce the updated value.
+             * @param {Function} [customizer] The function to customize assigned values.
+             * @returns {Object} Returns `object`.
+             * @example
+             *
+             * var object = {};
+             *
+             * _.updateWith(object, '[0][1]', _.constant('a'), Object);
+             * // => { '0': { '1': 'a' } }
+             */
+            function updateWith(object, path, updater, customizer) {
+              customizer = typeof customizer == 'function' ? customizer : undefined;
+              return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer);
+            }
+
+            /**
+             * Creates an array of the own enumerable string keyed property values of `object`.
+             *
+             * **Note:** Non-object values are coerced to objects.
+             *
+             * @static
+             * @since 0.1.0
+             * @memberOf _
+             * @category Object
+             * @param {Object} object The object to query.
+             * @returns {Array} Returns the array of property values.
+             * @example
+             *
+             * function Foo() {
+             *   this.a = 1;
+             *   this.b = 2;
+             * }
+             *
+             * Foo.prototype.c = 3;
+             *
+             * _.values(new Foo);
+             * // => [1, 2] (iteration order is not guaranteed)
+             *
+             * _.values('hi');
+             * // => ['h', 'i']
+             */
+            function values(object) {
+              return object == null ? [] : baseValues(object, keys(object));
+            }
+
+            /**
+             * Creates an array of the own and inherited enumerable string keyed property
+             * values of `object`.
+             *
+             * **Note:** Non-object values are coerced to objects.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category Object
+             * @param {Object} object The object to query.
+             * @returns {Array} Returns the array of property values.
+             * @example
+             *
+             * function Foo() {
+             *   this.a = 1;
+             *   this.b = 2;
+             * }
+             *
+             * Foo.prototype.c = 3;
+             *
+             * _.valuesIn(new Foo);
+             * // => [1, 2, 3] (iteration order is not guaranteed)
+             */
+            function valuesIn(object) {
+              return object == null ? [] : baseValues(object, keysIn(object));
+            }
+
+            /*------------------------------------------------------------------------*/
+
+            /**
+             * Clamps `number` within the inclusive `lower` and `upper` bounds.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category Number
+             * @param {number} number The number to clamp.
+             * @param {number} [lower] The lower bound.
+             * @param {number} upper The upper bound.
+             * @returns {number} Returns the clamped number.
+             * @example
+             *
+             * _.clamp(-10, -5, 5);
+             * // => -5
+             *
+             * _.clamp(10, -5, 5);
+             * // => 5
+             */
+            function clamp(number, lower, upper) {
+              if (upper === undefined) {
+                upper = lower;
+                lower = undefined;
+              }
+              if (upper !== undefined) {
+                upper = toNumber(upper);
+                upper = upper === upper ? upper : 0;
+              }
+              if (lower !== undefined) {
+                lower = toNumber(lower);
+                lower = lower === lower ? lower : 0;
+              }
+              return baseClamp(toNumber(number), lower, upper);
+            }
+
+            /**
+             * Checks if `n` is between `start` and up to, but not including, `end`. If
+             * `end` is not specified, it's set to `start` with `start` then set to `0`.
+             * If `start` is greater than `end` the params are swapped to support
+             * negative ranges.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.3.0
+             * @category Number
+             * @param {number} number The number to check.
+             * @param {number} [start=0] The start of the range.
+             * @param {number} end The end of the range.
+             * @returns {boolean} Returns `true` if `number` is in the range, else `false`.
+             * @see _.range, _.rangeRight
+             * @example
+             *
+             * _.inRange(3, 2, 4);
+             * // => true
+             *
+             * _.inRange(4, 8);
+             * // => true
+             *
+             * _.inRange(4, 2);
+             * // => false
+             *
+             * _.inRange(2, 2);
+             * // => false
+             *
+             * _.inRange(1.2, 2);
+             * // => true
+             *
+             * _.inRange(5.2, 4);
+             * // => false
+             *
+             * _.inRange(-3, -2, -6);
+             * // => true
+             */
+            function inRange(number, start, end) {
+              start = toFinite(start);
+              if (end === undefined) {
+                end = start;
+                start = 0;
+              } else {
+                end = toFinite(end);
+              }
+              number = toNumber(number);
+              return baseInRange(number, start, end);
+            }
+
+            /**
+             * Produces a random number between the inclusive `lower` and `upper` bounds.
+             * If only one argument is provided a number between `0` and the given number
+             * is returned. If `floating` is `true`, or either `lower` or `upper` are
+             * floats, a floating-point number is returned instead of an integer.
+             *
+             * **Note:** JavaScript follows the IEEE-754 standard for resolving
+             * floating-point values which can produce unexpected results.
+             *
+             * @static
+             * @memberOf _
+             * @since 0.7.0
+             * @category Number
+             * @param {number} [lower=0] The lower bound.
+             * @param {number} [upper=1] The upper bound.
+             * @param {boolean} [floating] Specify returning a floating-point number.
+             * @returns {number} Returns the random number.
+             * @example
+             *
+             * _.random(0, 5);
+             * // => an integer between 0 and 5
+             *
+             * _.random(5);
+             * // => also an integer between 0 and 5
+             *
+             * _.random(5, true);
+             * // => a floating-point number between 0 and 5
+             *
+             * _.random(1.2, 5.2);
+             * // => a floating-point number between 1.2 and 5.2
+             */
+            function random(lower, upper, floating) {
+              if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) {
+                upper = floating = undefined;
+              }
+              if (floating === undefined) {
+                if (typeof upper == 'boolean') {
+                  floating = upper;
+                  upper = undefined;
+                } else if (typeof lower == 'boolean') {
+                  floating = lower;
+                  lower = undefined;
+                }
+              }
+              if (lower === undefined && upper === undefined) {
+                lower = 0;
+                upper = 1;
+              } else {
+                lower = toFinite(lower);
+                if (upper === undefined) {
+                  upper = lower;
+                  lower = 0;
+                } else {
+                  upper = toFinite(upper);
+                }
+              }
+              if (lower > upper) {
+                var temp = lower;
+                lower = upper;
+                upper = temp;
+              }
+              if (floating || lower % 1 || upper % 1) {
+                var rand = nativeRandom();
+                return nativeMin(
+                  lower + rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1))),
+                  upper
+                );
+              }
+              return baseRandom(lower, upper);
+            }
+
+            /*------------------------------------------------------------------------*/
+
+            /**
+             * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase).
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category String
+             * @param {string} [string=''] The string to convert.
+             * @returns {string} Returns the camel cased string.
+             * @example
+             *
+             * _.camelCase('Foo Bar');
+             * // => 'fooBar'
+             *
+             * _.camelCase('--foo-bar--');
+             * // => 'fooBar'
+             *
+             * _.camelCase('__FOO_BAR__');
+             * // => 'fooBar'
+             */
+            var camelCase = createCompounder(function (result, word, index) {
+              word = word.toLowerCase();
+              return result + (index ? capitalize(word) : word);
+            });
+
+            /**
+             * Converts the first character of `string` to upper case and the remaining
+             * to lower case.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category String
+             * @param {string} [string=''] The string to capitalize.
+             * @returns {string} Returns the capitalized string.
+             * @example
+             *
+             * _.capitalize('FRED');
+             * // => 'Fred'
+             */
+            function capitalize(string) {
+              return upperFirst(toString(string).toLowerCase());
+            }
+
+            /**
+             * Deburrs `string` by converting
+             * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)
+             * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A)
+             * letters to basic Latin letters and removing
+             * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category String
+             * @param {string} [string=''] The string to deburr.
+             * @returns {string} Returns the deburred string.
+             * @example
+             *
+             * _.deburr('déjà vu');
+             * // => 'deja vu'
+             */
+            function deburr(string) {
+              string = toString(string);
+              return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');
+            }
+
+            /**
+             * Checks if `string` ends with the given target string.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category String
+             * @param {string} [string=''] The string to inspect.
+             * @param {string} [target] The string to search for.
+             * @param {number} [position=string.length] The position to search up to.
+             * @returns {boolean} Returns `true` if `string` ends with `target`,
+             *  else `false`.
+             * @example
+             *
+             * _.endsWith('abc', 'c');
+             * // => true
+             *
+             * _.endsWith('abc', 'b');
+             * // => false
+             *
+             * _.endsWith('abc', 'b', 2);
+             * // => true
+             */
+            function endsWith(string, target, position) {
+              string = toString(string);
+              target = baseToString(target);
+
+              var length = string.length;
+              position = position === undefined ? length : baseClamp(toInteger(position), 0, length);
+
+              var end = position;
+              position -= target.length;
+              return position >= 0 && string.slice(position, end) == target;
+            }
+
+            /**
+             * Converts the characters "&", "<", ">", '"', and "'" in `string` to their
+             * corresponding HTML entities.
+             *
+             * **Note:** No other characters are escaped. To escape additional
+             * characters use a third-party library like [_he_](https://mths.be/he).
+             *
+             * Though the ">" character is escaped for symmetry, characters like
+             * ">" and "/" don't need escaping in HTML and have no special meaning
+             * unless they're part of a tag or unquoted attribute value. See
+             * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands)
+             * (under "semi-related fun fact") for more details.
+             *
+             * When working with HTML you should always
+             * [quote attribute values](http://wonko.com/post/html-escaping) to reduce
+             * XSS vectors.
+             *
+             * @static
+             * @since 0.1.0
+             * @memberOf _
+             * @category String
+             * @param {string} [string=''] The string to escape.
+             * @returns {string} Returns the escaped string.
+             * @example
+             *
+             * _.escape('fred, barney, & pebbles');
+             * // => 'fred, barney, & pebbles'
+             */
+            function escape(string) {
+              string = toString(string);
+              return string && reHasUnescapedHtml.test(string)
+                ? string.replace(reUnescapedHtml, escapeHtmlChar)
+                : string;
+            }
+
+            /**
+             * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+",
+             * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category String
+             * @param {string} [string=''] The string to escape.
+             * @returns {string} Returns the escaped string.
+             * @example
+             *
+             * _.escapeRegExp('[lodash](https://lodash.com/)');
+             * // => '\[lodash\]\(https://lodash\.com/\)'
+             */
+            function escapeRegExp(string) {
+              string = toString(string);
+              return string && reHasRegExpChar.test(string) ? string.replace(reRegExpChar, '\\$&') : string;
+            }
+
+            /**
+             * Converts `string` to
+             * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles).
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category String
+             * @param {string} [string=''] The string to convert.
+             * @returns {string} Returns the kebab cased string.
+             * @example
+             *
+             * _.kebabCase('Foo Bar');
+             * // => 'foo-bar'
+             *
+             * _.kebabCase('fooBar');
+             * // => 'foo-bar'
+             *
+             * _.kebabCase('__FOO_BAR__');
+             * // => 'foo-bar'
+             */
+            var kebabCase = createCompounder(function (result, word, index) {
+              return result + (index ? '-' : '') + word.toLowerCase();
+            });
+
+            /**
+             * Converts `string`, as space separated words, to lower case.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category String
+             * @param {string} [string=''] The string to convert.
+             * @returns {string} Returns the lower cased string.
+             * @example
+             *
+             * _.lowerCase('--Foo-Bar--');
+             * // => 'foo bar'
+             *
+             * _.lowerCase('fooBar');
+             * // => 'foo bar'
+             *
+             * _.lowerCase('__FOO_BAR__');
+             * // => 'foo bar'
+             */
+            var lowerCase = createCompounder(function (result, word, index) {
+              return result + (index ? ' ' : '') + word.toLowerCase();
+            });
+
+            /**
+             * Converts the first character of `string` to lower case.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category String
+             * @param {string} [string=''] The string to convert.
+             * @returns {string} Returns the converted string.
+             * @example
+             *
+             * _.lowerFirst('Fred');
+             * // => 'fred'
+             *
+             * _.lowerFirst('FRED');
+             * // => 'fRED'
+             */
+            var lowerFirst = createCaseFirst('toLowerCase');
+
+            /**
+             * Pads `string` on the left and right sides if it's shorter than `length`.
+             * Padding characters are truncated if they can't be evenly divided by `length`.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category String
+             * @param {string} [string=''] The string to pad.
+             * @param {number} [length=0] The padding length.
+             * @param {string} [chars=' '] The string used as padding.
+             * @returns {string} Returns the padded string.
+             * @example
+             *
+             * _.pad('abc', 8);
+             * // => '  abc   '
+             *
+             * _.pad('abc', 8, '_-');
+             * // => '_-abc_-_'
+             *
+             * _.pad('abc', 3);
+             * // => 'abc'
+             */
+            function pad(string, length, chars) {
+              string = toString(string);
+              length = toInteger(length);
+
+              var strLength = length ? stringSize(string) : 0;
+              if (!length || strLength >= length) {
+                return string;
+              }
+              var mid = (length - strLength) / 2;
+              return createPadding(nativeFloor(mid), chars) + string + createPadding(nativeCeil(mid), chars);
+            }
+
+            /**
+             * Pads `string` on the right side if it's shorter than `length`. Padding
+             * characters are truncated if they exceed `length`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category String
+             * @param {string} [string=''] The string to pad.
+             * @param {number} [length=0] The padding length.
+             * @param {string} [chars=' '] The string used as padding.
+             * @returns {string} Returns the padded string.
+             * @example
+             *
+             * _.padEnd('abc', 6);
+             * // => 'abc   '
+             *
+             * _.padEnd('abc', 6, '_-');
+             * // => 'abc_-_'
+             *
+             * _.padEnd('abc', 3);
+             * // => 'abc'
+             */
+            function padEnd(string, length, chars) {
+              string = toString(string);
+              length = toInteger(length);
+
+              var strLength = length ? stringSize(string) : 0;
+              return length && strLength < length
+                ? string + createPadding(length - strLength, chars)
+                : string;
+            }
+
+            /**
+             * Pads `string` on the left side if it's shorter than `length`. Padding
+             * characters are truncated if they exceed `length`.
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category String
+             * @param {string} [string=''] The string to pad.
+             * @param {number} [length=0] The padding length.
+             * @param {string} [chars=' '] The string used as padding.
+             * @returns {string} Returns the padded string.
+             * @example
+             *
+             * _.padStart('abc', 6);
+             * // => '   abc'
+             *
+             * _.padStart('abc', 6, '_-');
+             * // => '_-_abc'
+             *
+             * _.padStart('abc', 3);
+             * // => 'abc'
+             */
+            function padStart(string, length, chars) {
+              string = toString(string);
+              length = toInteger(length);
+
+              var strLength = length ? stringSize(string) : 0;
+              return length && strLength < length
+                ? createPadding(length - strLength, chars) + string
+                : string;
+            }
+
+            /**
+             * Converts `string` to an integer of the specified radix. If `radix` is
+             * `undefined` or `0`, a `radix` of `10` is used unless `value` is a
+             * hexadecimal, in which case a `radix` of `16` is used.
+             *
+             * **Note:** This method aligns with the
+             * [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`.
+             *
+             * @static
+             * @memberOf _
+             * @since 1.1.0
+             * @category String
+             * @param {string} string The string to convert.
+             * @param {number} [radix=10] The radix to interpret `value` by.
+             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+             * @returns {number} Returns the converted integer.
+             * @example
+             *
+             * _.parseInt('08');
+             * // => 8
+             *
+             * _.map(['6', '08', '10'], _.parseInt);
+             * // => [6, 8, 10]
+             */
+            function parseInt(string, radix, guard) {
+              if (guard || radix == null) {
+                radix = 0;
+              } else if (radix) {
+                radix = +radix;
+              }
+              return nativeParseInt(toString(string).replace(reTrimStart, ''), radix || 0);
+            }
+
+            /**
+             * Repeats the given string `n` times.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category String
+             * @param {string} [string=''] The string to repeat.
+             * @param {number} [n=1] The number of times to repeat the string.
+             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+             * @returns {string} Returns the repeated string.
+             * @example
+             *
+             * _.repeat('*', 3);
+             * // => '***'
+             *
+             * _.repeat('abc', 2);
+             * // => 'abcabc'
+             *
+             * _.repeat('abc', 0);
+             * // => ''
+             */
+            function repeat(string, n, guard) {
+              if (guard ? isIterateeCall(string, n, guard) : n === undefined) {
+                n = 1;
+              } else {
+                n = toInteger(n);
+              }
+              return baseRepeat(toString(string), n);
+            }
+
+            /**
+             * Replaces matches for `pattern` in `string` with `replacement`.
+             *
+             * **Note:** This method is based on
+             * [`String#replace`](https://mdn.io/String/replace).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category String
+             * @param {string} [string=''] The string to modify.
+             * @param {RegExp|string} pattern The pattern to replace.
+             * @param {Function|string} replacement The match replacement.
+             * @returns {string} Returns the modified string.
+             * @example
+             *
+             * _.replace('Hi Fred', 'Fred', 'Barney');
+             * // => 'Hi Barney'
+             */
+            function replace() {
+              var args = arguments,
+                string = toString(args[0]);
+
+              return args.length < 3 ? string : string.replace(args[1], args[2]);
+            }
+
+            /**
+             * Converts `string` to
+             * [snake case](https://en.wikipedia.org/wiki/Snake_case).
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category String
+             * @param {string} [string=''] The string to convert.
+             * @returns {string} Returns the snake cased string.
+             * @example
+             *
+             * _.snakeCase('Foo Bar');
+             * // => 'foo_bar'
+             *
+             * _.snakeCase('fooBar');
+             * // => 'foo_bar'
+             *
+             * _.snakeCase('--FOO-BAR--');
+             * // => 'foo_bar'
+             */
+            var snakeCase = createCompounder(function (result, word, index) {
+              return result + (index ? '_' : '') + word.toLowerCase();
+            });
+
+            /**
+             * Splits `string` by `separator`.
+             *
+             * **Note:** This method is based on
+             * [`String#split`](https://mdn.io/String/split).
+             *
+             * @static
+             * @memberOf _
+             * @since 4.0.0
+             * @category String
+             * @param {string} [string=''] The string to split.
+             * @param {RegExp|string} separator The separator pattern to split by.
+             * @param {number} [limit] The length to truncate results to.
+             * @returns {Array} Returns the string segments.
+             * @example
+             *
+             * _.split('a-b-c', '-', 2);
+             * // => ['a', 'b']
+             */
+            function split(string, separator, limit) {
+              if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) {
+                separator = limit = undefined;
+              }
+              limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0;
+              if (!limit) {
+                return [];
+              }
+              string = toString(string);
+              if (string && (typeof separator == 'string' || (separator != null && !isRegExp(separator)))) {
+                separator = baseToString(separator);
+                if (!separator && hasUnicode(string)) {
+                  return castSlice(stringToArray(string), 0, limit);
+                }
+              }
+              return string.split(separator, limit);
+            }
+
+            /**
+             * Converts `string` to
+             * [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage).
+             *
+             * @static
+             * @memberOf _
+             * @since 3.1.0
+             * @category String
+             * @param {string} [string=''] The string to convert.
+             * @returns {string} Returns the start cased string.
+             * @example
+             *
+             * _.startCase('--foo-bar--');
+             * // => 'Foo Bar'
+             *
+             * _.startCase('fooBar');
+             * // => 'Foo Bar'
+             *
+             * _.startCase('__FOO_BAR__');
+             * // => 'FOO BAR'
+             */
+            var startCase = createCompounder(function (result, word, index) {
+              return result + (index ? ' ' : '') + upperFirst(word);
+            });
+
+            /**
+             * Checks if `string` starts with the given target string.
+             *
+             * @static
+             * @memberOf _
+             * @since 3.0.0
+             * @category String
+             * @param {string} [string=''] The string to inspect.
+             * @param {string} [target] The string to search for.
+             * @param {number} [position=0] The position to search from.
+             * @returns {boolean} Returns `true` if `string` starts with `target`,
+             *  else `false`.
+             * @example
+             *
+             * _.startsWith('abc', 'a');
+             * // => true
+             *
+             * _.startsWith('abc', 'b');
+             * // => false
+             *
+             * _.startsWith('abc', 'b', 1);
+             * // => true
+             */
+            function startsWith(string, target, position) {
+              string = toString(string);
+              position = position == null ? 0 : baseClamp(toInteger(position), 0, string.length);
+
+              target = baseToString(target);
+              return string.slice(position, position + target.length) == target;
+            }
+
+            /**
+             * Creates a compiled template function that can interpolate data properties
+             * in "interpolate" delimiters, HTML-escape interpolated data properties in
+             * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data
+             * properties may be accessed as free variables in the template. If a setting
+             * object is given, it takes precedence over `_.templateSettings` values.
+             *
+             * **Note:** In the development build `_.template` utilizes
+             * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl)
+             * for easier debugging.
+             *
+             * For more information on precompiling templates see
+             * [lodash's custom builds documentation](https://lodash.com/custom-builds).
+             *
+             * For more information on Chrome extension sandboxes see
+             * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval).
+             *
+             * @static
+             * @since 0.1.0
+             * @memberOf _
+             * @category String
+             * @param {string} [string=''] The template string.
+             * @param {Object} [options={}] The options object.
+             * @param {RegExp} [options.escape=_.templateSettings.escape]
+             *  The HTML "escape" delimiter.
+             * @param {RegExp} [options.evaluate=_.templateSettings.evaluate]
+             *  The "evaluate" delimiter.
+             * @param {Object} [options.imports=_.templateSettings.imports]
+             *  An object to import into the template as free variables.
+             * @param {RegExp} [options.interpolate=_.templateSettings.interpolate]
+             *  The "interpolate" delimiter.
+             * @param {string} [options.sourceURL='lodash.templateSources[n]']
+             *  The sourceURL of the compiled template.
+             * @param {string} [options.variable='obj']
+             *  The data object variable name.
+             * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+             * @returns {Function} Returns the compiled template function.
+             * @example
+             *
+             * // Use the "interpolate" delimiter to create a compiled template.
+             * var compiled = _.template('hello <%= user %>!');
+             * compiled({ 'user': 'fred' });
+             * // => 'hello fred!'
+             *
+             * // Use the HTML "escape" delimiter to escape data property values.
+             * var compiled = _.template('<%- value %>');
+             * compiled({ 'value': '