merge mozilla-inbound to mozilla-central. r=merge a=merge
authorSebastian Hengst <archaeopteryx@coole-files.de>
Sun, 11 Jun 2017 10:35:34 +0200
changeset 411514 799d43edb324395cf02da6b028e803712334615f
parent 411487 a040e8315026ea31bd92aa26333d69f689b1ccd7 (current diff)
parent 411513 330ef64c2e3885ab843fd57fd6faaad49b232147 (diff)
child 411515 9fffb8a06c945820854e22a4ba826f49a8cd2f27
child 411517 11e9775fd375003197c01c05ccd4091ba6dd0222
child 411522 1b58c5233eaa7968dc289d9113130ea6bf2985c8
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone55.0a1
first release with
nightly linux32
799d43edb324 / 55.0a1 / 20170611100318 / files
nightly linux64
799d43edb324 / 55.0a1 / 20170611100318 / files
nightly mac
799d43edb324 / 55.0a1 / 20170611030208 / files
nightly win32
799d43edb324 / 55.0a1 / 20170611030208 / files
nightly win64
799d43edb324 / 55.0a1 / 20170611030208 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central. r=merge a=merge MozReview-Commit-ID: C5HD11ptDT0
browser/base/content/browser-tabsintitlebar.js
js/src/jit-test/tests/ion/bug1365782-1.js
js/src/jit-test/tests/ion/bug1365782-2.js
--- a/accessible/tests/browser/e10s/browser.ini
+++ b/accessible/tests/browser/e10s/browser.ini
@@ -1,9 +1,10 @@
 [DEFAULT]
+skip-if = e10s && os == 'win' && release_or_beta
 support-files =
   head.js
   doc_treeupdate_ariadialog.html
   doc_treeupdate_ariaowns.html
   doc_treeupdate_imagemap.html
   doc_treeupdate_removal.xhtml
   doc_treeupdate_visibility.html
   doc_treeupdate_whitespace.html
--- a/accessible/tests/browser/states/browser.ini
+++ b/accessible/tests/browser/states/browser.ini
@@ -1,9 +1,10 @@
 [DEFAULT]
+skip-if = e10s && os == 'win' && release_or_beta
 support-files =
   head.js
   !/accessible/tests/browser/events.js
   !/accessible/tests/browser/shared-head.js
   !/accessible/tests/mochitest/*.js
 
 [browser_test_link.js]
-[browser_test_visibility.js]
\ No newline at end of file
+[browser_test_visibility.js]
--- a/browser/base/content/browser-tabsintitlebar.js
+++ b/browser/base/content/browser-tabsintitlebar.js
@@ -171,16 +171,26 @@ var TabsInTitlebar = {
         fullMenuHeight = verticalMargins(menuStyles) + menuHeight;
       }
 
       // And get the height of what's in the titlebar:
       let titlebarContentHeight = rect(titlebarContent).height;
 
       // Begin setting CSS properties which will cause a reflow
 
+      if (AppConstants.MOZ_PHOTON_THEME &&
+          AppConstants.isPlatformAndVersionAtLeast("win", "10.0")) {
+        if (!menuHeight) {
+          titlebarContentHeight = Math.max(titlebarContentHeight, fullTabsHeight);
+          $("titlebar-buttonbox").style.height = titlebarContentHeight + "px";
+        } else {
+          $("titlebar-buttonbox").style.removeProperty("height");
+        }
+      }
+
       // If the menubar is around (menuHeight is non-zero), try to adjust
       // its full height (i.e. including margins) to match the titlebar,
       // by changing the menubar's bottom padding
       if (menuHeight) {
         // Calculate the difference between the titlebar's height and that of the menubar
         let menuTitlebarDelta = titlebarContentHeight - fullMenuHeight;
         let paddingBottom;
         // The titlebar is bigger:
--- a/devtools/client/debugger/new/debugger.css
+++ b/devtools/client/debugger/new/debugger.css
@@ -1,8 +1,12 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 .landing-page {
   flex: 1;
   display: flex;
   width: 100vw;
   height: 100vh;
   flex-direction: row;
   align-items: stretch;
   /* Customs properties */
@@ -94,16 +98,20 @@
 }
 
 .landing-page .panel .footer-note {
   padding: var(--base-spacing) 0;
   text-align: center;
   font-size: 14px;
   color: var(--theme-comment);
 }
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 .landing-page .tab-group {
   flex: 1;
   overflow-y: auto;
 }
 
 .landing-page .tab-list {
   list-style: none;
   padding: 0;
@@ -152,16 +160,20 @@
 .landing-page .tab.active .tab-title {
   color: inherit;
 }
 
 .landing-page .tab:focus .tab-url,
 .landing-page .tab.active .tab-url {
   color: var(--theme-highlight-gray);
 }
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 .landing-page .sidebar {
   display: flex;
   background-color: var(--theme-tab-toolbar-background);
   width: 200px;
   flex-direction: column;
   border-right: 1px solid var(--theme-splitter-color);
 }
 
@@ -205,16 +217,20 @@
   color: var(--theme-selection-color);
   cursor: pointer;
 }
 
 .landing-page .sidebar li:hover a,
 .landing-page .sidebar li:focus a {
   color: inherit;
 }
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 menu {
   display: inline;
   padding: 0;
 }
 
 menu > menuitem::after {
   content: "\25BA";
   float: right;
@@ -290,16 +306,20 @@ menuseparator {
 #contextmenu-mask.show {
   position: fixed;
   top: 0;
   left: 0;
   width: 100%;
   height: 100%;
   z-index: 999;
 }
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 :root.theme-light,
 :root .theme-light {
   --theme-search-overlays-semitransparent: rgba(221, 225, 228, 0.66);
 }
 
 * {
   box-sizing: border-box;
 }
@@ -1744,20 +1764,16 @@ html .toggle-button-end.vertical svg {
 .theme-dark {
   --theme-conditional-breakpoint-color: #9fa4a9;
 }
 
 .theme-light {
   --theme-conditional-breakpoint-color: #ccd1d5;
 }
 
-.theme-firebug {
-  --theme-conditional-breakpoint-color: #ccd1d5;
-}
-
 .out-of-scope .CodeMirror-line,
 .out-of-scope .CodeMirror-linenumber {
   opacity: 0.8;
 }
 
 /**
  * There's a known codemirror flex issue with chrome that this addresses.
  * BUG https://github.com/devtools-html/debugger.html/issues/63
@@ -1983,35 +1999,16 @@ html[dir="rtl"] .editor-mount {
 .cm-highlight-end::before {
   border-right-width: 1px;
   border-right-style: solid;
   border-right-color: var(--theme-comment-alt);
   margin: 0 -1px -1px 0;
   border-top-right-radius: 2px;
   border-bottom-right-radius: 2px;
 }
-
-.why-paused {
-  background-color: var(--theme-body-background);
-  border-bottom: 1px solid var(--theme-splitter-color);
-  color: var(--theme-highlight-blue);
-  padding: 10px 10px 10px 20px;
-  white-space: normal;
-  opacity: 0.9;
-  font-size: 12px;
-  flex: 0 1 auto;
-}
-
-.theme-dark .secondary-panes .why-paused {
-  color: white;
-}
-
-.why-paused .message {
-  font-size: 10px;
-}
 .breakpoints-toggle {
   margin: 2px 3px;
 }
 
 .breakpoints-list * {
   -moz-user-select: none;
   user-select: none;
 }
@@ -2211,16 +2208,43 @@ html .breakpoints-list .breakpoint.pause
 .frames ul .frames-group .frames-list li {
   padding-left: 30px;
 }
 
 .frames ul .frames-group .frames-list {
   border-top: 1px solid var(--theme-splitter-color);
   border-bottom: 1px solid var(--theme-splitter-color);
 }
+
+.why-paused {
+  background-color: var(--theme-body-background);
+  color: var(--theme-body-color);
+  padding: 10px 10px 10px 20px;
+  white-space: normal;
+  opacity: 0.6;
+  font-size: 12px;
+  flex: 0 1 auto;
+  text-align: center;
+  font-style: italic;
+  font-weight: 300;
+}
+
+.theme-dark .secondary-panes .why-paused {
+  color: white;
+}
+
+.why-paused .message {
+  font-size: 10px;
+}
+
+.why-paused .message.warning {
+  font-size: 10px;
+  color: var(--theme-graphs-full-red);
+  font-weight: bold;
+}
 .frames ul {
   list-style: none;
   margin: 0;
   padding: 0;
 }
 
 .frames ul li {
   cursor: pointer;
--- a/devtools/client/debugger/new/debugger.js
+++ b/devtools/client/debugger/new/debugger.js
@@ -58,69 +58,71 @@ return /******/ (function(modules) { // 
 
 
 /***/ },
 /* 1 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
-	var React = __webpack_require__(2);
-	var ReactDOM = __webpack_require__(31);
+	var _react = __webpack_require__(2);
+
+	var _react2 = _interopRequireDefault(_react);
+
+	var _reactDom = __webpack_require__(31);
+
+	var _reactDom2 = _interopRequireDefault(_reactDom);
+
+	var _devtoolsLaunchpad = __webpack_require__(131);
+
+	var _devtoolsConfig = __webpack_require__(828);
+
+	var _client = __webpack_require__(888);
+
+	var _bootstrap = __webpack_require__(897);
+
+	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
 	//
 	// if (process.env.NODE_ENV !== "production") {
 	//   const Perf = require("react-addons-perf");
 	//   window.Perf = Perf;
 	// }
 
-	var _require = __webpack_require__(131),
-	    bootstrap = _require.bootstrap,
-	    L10N = _require.L10N,
-	    unmountRoot = _require.unmountRoot;
-
-	var _require2 = __webpack_require__(828),
-	    isFirefoxPanel = _require2.isFirefoxPanel;
-
-	var _require3 = __webpack_require__(888),
-	    onConnect = _require3.onConnect;
-
-	var _require4 = __webpack_require__(897),
-	    teardownWorkers = _require4.teardownWorkers;
-
-	if (isFirefoxPanel()) {
+	if ((0, _devtoolsConfig.isFirefoxPanel)()) {
 	  module.exports = {
 	    bootstrap: (_ref) => {
 	      var threadClient = _ref.threadClient,
 	          tabTarget = _ref.tabTarget,
 	          debuggerClient = _ref.debuggerClient,
 	          sourceMaps = _ref.sourceMaps;
 
-	      return onConnect({
+	      return (0, _client.onConnect)({
 	        tab: { clientType: "firefox" },
 	        tabConnection: {
 	          tabTarget,
 	          threadClient,
 	          debuggerClient
 	        }
 	      }, {
 	        sourceMaps
 	      });
 	    },
 	    destroy: () => {
-	      unmountRoot(ReactDOM);
-	      teardownWorkers();
+	      (0, _devtoolsLaunchpad.unmountRoot)(_reactDom2.default);
+	      (0, _bootstrap.teardownWorkers)();
 	    }
 	  };
 	} else {
-	  window.L10N = L10N;
+	  window.L10N = _devtoolsLaunchpad.L10N;
 	  // $FlowIgnore:
 	  window.L10N.setBundle(__webpack_require__(960));
 
-	  bootstrap(React, ReactDOM).then(connection => {
-	    onConnect(connection, {
+	  (0, _devtoolsLaunchpad.bootstrap)(_react2.default, _reactDom2.default).then(connection => {
+	    (0, _client.onConnect)(connection, {
 	      sourceMaps: __webpack_require__(898)
 	    });
 	  });
 	}
 
 /***/ },
 /* 2 */
 /***/ function(module, exports) {
@@ -3302,25 +3304,31 @@ return /******/ (function(modules) { // 
 	        actions = _ref7.actions,
 	        LaunchpadApp = _ref7.LaunchpadApp;
 
 	    renderRoot(React, ReactDOM, LaunchpadApp, store);
 	    yield connectClients(actions);
 	    setInterval(_asyncToGenerator(function* () {
 	      return yield getTabs(actions);
 	    }), 3000);
+
+	    return undefined;
 	  });
 
 	  return function bootstrap(_x3, _x4) {
 	    return _ref5.apply(this, arguments);
 	  };
 	})();
 
 	function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(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 Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	/* global window, document, DebuggerConfig */
 
 	var _require = __webpack_require__(3),
 	    bindActionCreators = _require.bindActionCreators,
 	    combineReducers = _require.combineReducers;
 
 	var _require2 = __webpack_require__(151),
 	    Provider = _require2.Provider;
@@ -3337,17 +3345,17 @@ return /******/ (function(modules) { // 
 	    isDevelopment = _require5.isDevelopment;
 
 	var L10N = __webpack_require__(185);
 
 	var _require6 = __webpack_require__(966),
 	    showMenu = _require6.showMenu,
 	    buildMenu = _require6.buildMenu;
 
-	setConfig(({"environment":"firefox-panel","logging":false,"clientLogging":false,"firefox":{"mcPath":"./firefox"},"workers":{"parserURL":"resource://devtools/client/debugger/new/parser-worker.js","prettyPrintURL":"resource://devtools/client/debugger/new/pretty-print-worker.js"},"features":{"blackbox":{"enabled":true},"chromeScopes":{"enabled":false},"eventListeners":{"enabled":false},"codeCoverage":{"enabled":false},"searchNav":{"enabled":true},"collapseFrame":{"enabled":true}}}));
+	setConfig(({"environment":"firefox-panel","logging":false,"clientLogging":false,"firefox":{"mcPath":"./firefox"},"workers":{"parserURL":"resource://devtools/client/debugger/new/parser-worker.js","prettyPrintURL":"resource://devtools/client/debugger/new/pretty-print-worker.js","searchURL":"resource://devtools/client/debugger/new/search-worker.js"},"features":{"blackbox":{"enabled":true},"chromeScopes":{"enabled":false},"eventListeners":{"enabled":false},"codeCoverage":{"enabled":false},"codeFolding":{"enabled":false},"searchNav":{"enabled":true},"collapseFrame":{"enabled":true}}}));
 
 	// Set various flags before requiring app code.
 	if (getValue("logging.client")) {
 	  // DevToolsUtils.dumpn.wantLogging = true;
 	}
 
 	var _require7 = __webpack_require__(885),
 	    firefox = _require7.firefox,
@@ -3517,16 +3525,20 @@ return /******/ (function(modules) { // 
 	module.exports = configureStore;
 
 /***/ },
 /* 133 */
 /***/ function(module, exports) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	/**
 	 * A middleware which acts like a service, because it is stateful
 	 * and "long-running" in the background. It provides the ability
 	 * for actions to install a function to be run once when a specific
 	 * condition is met by an action coming through the system. Think of
 	 * it as a thunk that blocks until the condition is met. Example:
 	 *
 	 * ```js
@@ -3586,16 +3598,20 @@ return /******/ (function(modules) { // 
 	exports.waitUntilService = waitUntilService;
 
 /***/ },
 /* 134 */
 /***/ function(module, exports) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	/**
 	 * A middleware that logs all actions coming through the system
 	 * to the console.
 	 */
 	function log(_ref) {
 	  var dispatch = _ref.dispatch,
 	      getState = _ref.getState;
 
@@ -3717,16 +3733,20 @@ return /******/ (function(modules) { // 
 	exports.promise = promiseMiddleware;
 
 /***/ },
 /* 137 */
 /***/ function(module, exports) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	/**
 	 * Returns a deferred object, with a resolve and reject property.
 	 * https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred
 	 */
 	module.exports = function defer() {
 	  var resolve = void 0,
 	      reject = void 0;
 	  var promise = new Promise(function () {
@@ -3969,16 +3989,20 @@ return /******/ (function(modules) { // 
 
 /***/ },
 /* 139 */,
 /* 140 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var assert = __webpack_require__(141);
 
 	function reportException(who, exception) {
 	  var msg = `${who} threw an exception: `;
 	  console.error(msg, exception);
 	}
 
 	function executeSoon(fn) {
@@ -3992,30 +4016,38 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 141 */
 /***/ function(module, exports) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	function assert(condition, message) {
 	  if (!condition) {
 	    throw new Error(`Assertion failure: ${message}`);
 	  }
 	}
 
 	module.exports = assert;
 
 /***/ },
 /* 142 */
 /***/ function(module, exports) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	/**
 	 * A middleware that allows thunks (functions) to be dispatched. If
 	 * it's a thunk, it is called with an argument that contains
 	 * `dispatch`, `getState`, and any additional args passed in via the
 	 * middleware constructure. This allows the action to create multiple
 	 * actions (most likely asynchronously).
 	 */
 	function thunk(makeArgs) {
@@ -4033,16 +4065,20 @@ return /******/ (function(modules) { // 
 	exports.thunk = thunk;
 
 /***/ },
 /* 143 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var tabs = __webpack_require__(144);
 	var config = __webpack_require__(148);
 
 	module.exports = {
 	  tabs,
 	  config
 	};
 
@@ -9144,16 +9180,20 @@ return /******/ (function(modules) { // 
 	}));
 
 /***/ },
 /* 147 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var Immutable = __webpack_require__(146);
 
 	// When our app state is fully types, we should be able to get rid of
 	// this function. This is only temporarily necessary to support
 	// converting typed objects to immutable.js, which usually happens in
 	// reducers.
 	function fromJS(value) {
 	  if (Array.isArray(value)) {
@@ -9225,16 +9265,20 @@ return /******/ (function(modules) { // 
 	module.exports = update;
 
 /***/ },
 /* 149 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var React = __webpack_require__(2);
 	var PropTypes = React.PropTypes;
 
 	var ImPropTypes = __webpack_require__(150);
 
 	var _require = __webpack_require__(151),
 	    connect = _require.connect;
 
@@ -9247,25 +9291,25 @@ return /******/ (function(modules) { // 
 	    getConfig = _require3.getConfig;
 
 	var _require4 = __webpack_require__(828),
 	    getValue = _require4.getValue;
 
 	var LandingPage = React.createFactory(__webpack_require__(167));
 
 	var LaunchpadApp = React.createClass({
+	  displayName: "LaunchpadApp",
+
 	  propTypes: {
 	    tabs: ImPropTypes.map.isRequired,
 	    filterString: PropTypes.string,
 	    actions: PropTypes.object,
 	    config: PropTypes.object
 	  },
 
-	  displayName: "LaunchpadApp",
-
 	  render() {
 	    var _props = this.props,
 	        filterString = _props.filterString,
 	        _props$actions = _props.actions,
 	        setValue = _props$actions.setValue,
 	        filterTabs = _props$actions.filterTabs,
 	        config = _props.config;
 
@@ -10267,16 +10311,20 @@ return /******/ (function(modules) { // 
 
 
 /***/ },
 /* 160 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var _require = __webpack_require__(161),
 	    score = _require.score;
 
 	function getTabs(state) {
 	  var tabs = state.tabs.get("tabs");
 	  var filterString = getFilterString(state);
 
 	  if (filterString === "") {
@@ -11220,16 +11268,20 @@ return /******/ (function(modules) { // 
 
 
 /***/ },
 /* 167 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var React = __webpack_require__(2);
 
 	__webpack_require__(168);
 	var dom = React.DOM;
 
 	var ImPropTypes = __webpack_require__(150);
 	var configMap = __webpack_require__(145).sidePanelItems;
 	var Tabs = React.createFactory(__webpack_require__(172));
@@ -11244,30 +11296,30 @@ return /******/ (function(modules) { // 
 
 	function firstTimeMessage(title, urlPart) {
 	  return dom.div({ className: "footer-note" }, `First time connecting to ${title}? Checkout out the `, dom.a({
 	    href: `${githubUrl}/docs/getting-setup.md#starting-${urlPart}`
 	  }, "docs"), ".");
 	}
 
 	var LandingPage = React.createClass({
+	  displayName: "LandingPage",
+
 	  propTypes: {
 	    tabs: ImPropTypes.map.isRequired,
 	    supportsFirefox: React.PropTypes.bool.isRequired,
 	    supportsChrome: React.PropTypes.bool.isRequired,
 	    title: React.PropTypes.string.isRequired,
 	    filterString: React.PropTypes.string,
 	    onFilterChange: React.PropTypes.func.isRequired,
 	    onTabClick: React.PropTypes.func.isRequired,
 	    config: React.PropTypes.object.isRequired,
 	    setValue: React.PropTypes.func.isRequired
 	  },
 
-	  displayName: "LandingPage",
-
 	  getInitialState() {
 	    return {
 	      selectedPane: configMap.Firefox.name,
 	      firefoxConnected: false,
 	      chromeConnected: false
 	    };
 	  },
 
@@ -11431,37 +11483,41 @@ return /******/ (function(modules) { // 
 /* 169 */,
 /* 170 */,
 /* 171 */,
 /* 172 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var React = __webpack_require__(2);
 
 	__webpack_require__(173);
 	var dom = React.DOM;
 
 	var classnames = __webpack_require__(175);
 
 	function getTabURL(tab, paramName) {
 	  var tabID = tab.get("id");
 	  return `/?${paramName}=${tabID}`;
 	}
 
 	var Tabs = React.createClass({
+	  displayName: "Tabs",
+
 	  propTypes: {
 	    targets: React.PropTypes.object.isRequired,
 	    paramName: React.PropTypes.string.isRequired,
 	    onTabClick: React.PropTypes.func.isRequired
 	  },
 
-	  displayName: "Tabs",
-
 	  onTabClick(tab, paramName) {
 	    this.props.onTabClick(getTabURL(tab, paramName));
 	  },
 
 	  render() {
 	    var _props = this.props,
 	        targets = _props.targets,
 	        paramName = _props.paramName;
@@ -11558,35 +11614,38 @@ return /******/ (function(modules) { // 
 
 
 /***/ },
 /* 176 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var React = __webpack_require__(2);
 
 	__webpack_require__(177);
 	var dom = React.DOM;
 
 	var classnames = __webpack_require__(175);
 
 	var Sidebar = React.createClass({
+	  displayName: "Sidebar",
 
 	  propTypes: {
 	    supportsFirefox: React.PropTypes.bool.isRequired,
 	    supportsChrome: React.PropTypes.bool.isRequired,
 	    title: React.PropTypes.string.isRequired,
 	    selectedPane: React.PropTypes.string.isRequired,
 	    onSideBarItemClick: React.PropTypes.func.isRequired
 	  },
 
-	  displayName: "Sidebar",
-
 	  render() {
 	    var connections = [];
 
 	    if (this.props.supportsFirefox) {
 	      connections.push("Firefox");
 	    }
 
 	    if (this.props.supportsChrome) {
@@ -11624,31 +11683,35 @@ return /******/ (function(modules) { // 
 
 /***/ },
 /* 178 */,
 /* 179 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var React = __webpack_require__(2);
 	var dom = React.DOM;
 
 	var _require = __webpack_require__(966),
 	    showMenu = _require.showMenu,
 	    buildMenu = _require.buildMenu;
 
 	var Settings = React.createClass({
+	  displayName: "Settings",
+
 	  propTypes: {
 	    config: React.PropTypes.object.isRequired,
 	    setValue: React.PropTypes.func.isRequired
 	  },
 
-	  displayName: "Settings",
-
 	  onConfigContextMenu(event, key) {
 	    event.preventDefault();
 
 	    var _props = this.props,
 	        setValue = _props.setValue,
 	        config = _props.config;
 
 
@@ -11745,16 +11808,20 @@ return /******/ (function(modules) { // 
 
 /***/ },
 /* 180 */,
 /* 181 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var tabs = __webpack_require__(182);
 	var config = __webpack_require__(183);
 
 	module.exports = Object.assign({}, tabs, config);
 
 /***/ },
 /* 182 */
 /***/ function(module, exports, __webpack_require__) {
@@ -11849,16 +11916,20 @@ return /******/ (function(modules) { // 
 /***/ },
 /* 183 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(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 Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var _require = __webpack_require__(828),
 	    _setConfig = _require.setConfig;
 
 	var _require2 = __webpack_require__(131),
 	    updateTheme = _require2.updateTheme,
 	    updateDir = _require2.updateDir;
 
 	/**
@@ -11932,16 +12003,20 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 184 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var _require = __webpack_require__(828),
 	    isDevelopment = _require.isDevelopment,
 	    isTesting = _require.isTesting;
 
 	function debugGlobal(field, value) {
 	  if (isDevelopment() || isTesting()) {
 	    window[field] = value;
 	  }
@@ -11954,16 +12029,20 @@ return /******/ (function(modules) { // 
 /***/ },
 /* 185 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var _require = __webpack_require__(975),
 	    sprintf = _require.sprintf;
 
 	var _require2 = __webpack_require__(883),
 	    parse = _require2.parse;
 
 	var strings = {};
 
@@ -12021,16 +12100,20 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 186 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var classnames = __webpack_require__(175);
 	__webpack_require__(187);
 
 	module.exports = function (className) {
 	  var root = document.createElement("div");
 	  root.className = classnames(className);
 	  root.style.setProperty("flex", 1);
 	  return root;
@@ -12132,16 +12215,22 @@ return /******/ (function(modules) { // 
 	exports.default = configureStore;
 
 /***/ },
 /* 190 */
 /***/ function(module, exports) {
 
 	"use strict";
 
+	Object.defineProperty(exports, "__esModule", {
+	  value: true
+	});
+	exports.waitUntilService = waitUntilService;
+
+
 	/**
 	 * A middleware which acts like a service, because it is stateful
 	 * and "long-running" in the background. It provides the ability
 	 * for actions to install a function to be run once when a specific
 	 * condition is met by an action coming through the system. Think of
 	 * it as a thunk that blocks until the condition is met. Example:
 	 *
 	 * ```js
@@ -12193,17 +12282,16 @@ return /******/ (function(modules) { // 
 	      pending.push(action);
 	      return null;
 	    }
 	    var result = next(action);
 	    checkPending(action);
 	    return result;
 	  };
 	}
-	exports.waitUntilService = waitUntilService;
 
 /***/ },
 /* 191 */
 /***/ function(module, exports) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
@@ -13269,16 +13357,22 @@ return /******/ (function(modules) { // 
 	}
 
 /***/ },
 /* 224 */
 /***/ function(module, exports) {
 
 	"use strict";
 
+	Object.defineProperty(exports, "__esModule", {
+	  value: true
+	});
+	exports.thunk = thunk;
+
+
 	/**
 	 * A middleware that allows thunks (functions) to be dispatched. If
 	 * it's a thunk, it is called with an argument that contains
 	 * `dispatch`, `getState`, and any additional args passed in via the
 	 * middleware constructure. This allows the action to create multiple
 	 * actions (most likely asynchronously).
 	 */
 	function thunk(makeArgs) {
@@ -13289,30 +13383,30 @@ return /******/ (function(modules) { // 
 	    var args = { dispatch, getState };
 
 	    return next => action => {
 	      return typeof action === "function" ? action(makeArgs ? makeArgs(args, getState()) : args) : next(action);
 	    };
 	  };
 	}
 
-	exports.thunk = thunk;
-
 /***/ },
 /* 225 */,
 /* 226 */
 /***/ function(module, exports, __webpack_require__) {
 
 	// @flow
 
-	var { PrefsHelper } = __webpack_require__(830);
-	const { Services: { pref } } = __webpack_require__(830);
 	const { isDevelopment } = __webpack_require__(828);
+	const { Services, PrefsHelper } = __webpack_require__(830);
+
 	const prefsSchemaVersion = "1.0.0";
 
+	const pref = Services.pref;
+
 	if (isDevelopment()) {
 	  pref("devtools.debugger.client-source-maps-enabled", true);
 	  pref("devtools.debugger.pause-on-exceptions", false);
 	  pref("devtools.debugger.ignore-caught-exceptions", false);
 	  pref("devtools.debugger.call-stack-visible", false);
 	  pref("devtools.debugger.scopes-visible", false);
 	  pref("devtools.debugger.start-panel-collapsed", false);
 	  pref("devtools.debugger.end-panel-collapsed", false);
@@ -13709,22 +13803,21 @@ return /******/ (function(modules) { // 
 	      }
 
 	      location = {
 	        line: action.line,
 	        url: action.source.url
 	      };
 
 	      _prefs.prefs.pendingSelectedLocation = location;
-
 	      return state.set("selectedLocation", {
 	        sourceId: action.source.id,
 	        line: action.line
 	      }).set("pendingSelectedLocation", location).merge({
-	        tabs: updateTabList({ sources: state }, action.source.url, action.tabIndex)
+	        tabs: updateTabList({ sources: state }, action.source.url)
 	      });
 
 	    case "CLEAR_SELECTED_SOURCE":
 	      location = { url: "" };
 	      _prefs.prefs.pendingSelectedLocation = location;
 
 	      return state.set("selectedLocation", { sourceId: "" }).set("pendingSelectedLocation", location);
 
@@ -13732,16 +13825,21 @@ return /******/ (function(modules) { // 
 	      location = {
 	        url: action.url,
 	        line: action.line
 	      };
 
 	      _prefs.prefs.pendingSelectedLocation = location;
 	      return state.set("pendingSelectedLocation", location);
 
+	    case "MOVE_TAB":
+	      return state.merge({
+	        tabs: updateTabList({ sources: state }, action.url, action.tabIndex)
+	      });
+
 	    case "CLOSE_TAB":
 	      _prefs.prefs.tabs = action.tabs;
 	      return state.merge({ tabs: action.tabs });
 
 	    case "CLOSE_TABS":
 	      _prefs.prefs.tabs = action.tabs;
 	      return state.merge({ tabs: action.tabs });
 
@@ -13767,19 +13865,19 @@ return /******/ (function(modules) { // 
 	  return state;
 	}
 
 	function getTextPropsFromAction(action) {
 	  var source = action.source;
 	  var sourceText = action.value;
 
 	  if (action.status === "start") {
-	    return { loading: true };
+	    return { id: source.id, loading: true };
 	  } else if (action.status === "error") {
-	    return { error: action.error, loading: false };
+	    return { id: source.id, error: action.error, loading: false };
 	  }
 	  return {
 	    text: sourceText.text,
 	    id: source.id,
 	    contentType: sourceText.contentType,
 	    loading: false
 	  };
 	}
@@ -14813,59 +14911,65 @@ return /******/ (function(modules) { // 
 	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 	exports.getLoadedObject = getLoadedObject;
 	exports.getObjectProperties = getObjectProperties;
 	exports.getIsWaitingOnBreak = getIsWaitingOnBreak;
 	exports.getShouldPauseOnExceptions = getShouldPauseOnExceptions;
 	exports.getShouldIgnoreCaughtExceptions = getShouldIgnoreCaughtExceptions;
 	exports.getFrames = getFrames;
+	exports.getFrameScopes = getFrameScopes;
 	exports.getDebuggeeUrl = getDebuggeeUrl;
 	exports.getChromeScopes = getChromeScopes;
 
 	var _reselect = __webpack_require__(993);
 
 	var _prefs = __webpack_require__(226);
 
 	var State = exports.State = () => ({
 	  pause: undefined,
 	  isWaitingOnBreak: false,
 	  frames: undefined,
 	  selectedFrameId: undefined,
+	  frameScopes: {},
 	  loadedObjects: {},
 	  shouldPauseOnExceptions: _prefs.prefs.pauseOnExceptions,
 	  shouldIgnoreCaughtExceptions: _prefs.prefs.ignoreCaughtExceptions,
 	  debuggeeUrl: ""
 	});
 
 	function update() {
 	  var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : State();
 	  var action = arguments[1];
 
 	  switch (action.type) {
 	    case "PAUSED":
 	      {
-	        var _selectedFrameId = action.selectedFrameId,
+	        var _selectedFrameId2 = action.selectedFrameId,
 	            _frames = action.frames,
+	            _scopes = action.scopes,
 	            _loadedObjects = action.loadedObjects,
 	            pauseInfo = action.pauseInfo;
 
 	        pauseInfo.isInterrupted = pauseInfo.why.type === "interrupted";
 
+	        var _frameScopes = { [_selectedFrameId2]: _scopes };
+
 	        // turn this into an object keyed by object id
 	        var objectMap = {};
 	        _loadedObjects.forEach(obj => {
 	          objectMap[obj.value.objectId] = obj;
 	        });
 
 	        return Object.assign({}, state, {
 	          isWaitingOnBreak: false,
 	          pause: pauseInfo,
-	          selectedFrameId: _selectedFrameId,
+	          selectedFrameId: _selectedFrameId2,
 	          frames: _frames,
+	          frameScopes: _frameScopes,
 	          loadedObjects: objectMap
 	        });
 	      }
 
 	    case "RESUME":
 	      return Object.assign({}, state, {
 	        pause: null,
 	        frames: null,
@@ -14884,17 +14988,24 @@ return /******/ (function(modules) { // 
 	        return Object.assign({}, state, { pause: _pause, frames: _frames2 });
 	      }
 
 	      break;
 	    case "BREAK_ON_NEXT":
 	      return Object.assign({}, state, { isWaitingOnBreak: true });
 
 	    case "SELECT_FRAME":
-	      return Object.assign({}, state, { selectedFrameId: action.frame.id });
+	      var frame = action.frame,
+	          scopes = action.scopes;
+
+	      var _selectedFrameId = frame.id;
+	      return _extends({}, state, {
+	        frameScopes: _extends({}, state.frameScopes, { [_selectedFrameId]: scopes }),
+	        selectedFrameId: _selectedFrameId
+	      });
 
 	    case "LOAD_OBJECT_PROPERTIES":
 	      if (action.status === "start") {
 	        return _extends({}, state, {
 	          loadedObjects: _extends({}, state.loadedObjects, {
 	            [action.objectId]: {}
 	          })
 	        });
@@ -14973,16 +15084,20 @@ return /******/ (function(modules) { // 
 	function getShouldIgnoreCaughtExceptions(state) {
 	  return state.pause.shouldIgnoreCaughtExceptions;
 	}
 
 	function getFrames(state) {
 	  return state.pause.frames;
 	}
 
+	function getFrameScopes(state, frameId) {
+	  return state.pause.frameScopes[frameId];
+	}
+
 	var getSelectedFrameId = (0, _reselect.createSelector)(getPauseState, pauseWrapper => {
 	  return pauseWrapper.selectedFrameId;
 	});
 
 	var getSelectedFrame = exports.getSelectedFrame = (0, _reselect.createSelector)(getSelectedFrameId, getFrames, (selectedFrameId, frames) => {
 	  if (!frames) {
 	    return null;
 	  }
@@ -15008,16 +15123,18 @@ return /******/ (function(modules) { // 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
 	exports.getSymbolSearchState = exports.getFileSearchState = exports.getProjectSearchState = exports.State = undefined;
 	exports.getFileSearchQueryState = getFileSearchQueryState;
 	exports.getFileSearchModifierState = getFileSearchModifierState;
+	exports.getSymbolSearchResults = getSymbolSearchResults;
+	exports.getSearchResults = getSearchResults;
 	exports.getFrameworkGroupingState = getFrameworkGroupingState;
 	exports.getSymbolSearchType = getSymbolSearchType;
 	exports.getShownSource = getShownSource;
 	exports.getPaneCollapse = getPaneCollapse;
 	exports.getHighlightedLineRange = getHighlightedLineRange;
 
 	var _makeRecord = __webpack_require__(230);
 
@@ -15038,16 +15155,21 @@ return /******/ (function(modules) { // 
 	  fileSearchModifiers: (0, _makeRecord2.default)({
 	    caseSensitive: _prefs.prefs.fileSearchCaseSensitive,
 	    wholeWord: _prefs.prefs.fileSearchWholeWord,
 	    regexMatch: _prefs.prefs.fileSearchRegexMatch
 	  })(),
 	  projectSearchOn: false,
 	  symbolSearchOn: false,
 	  symbolSearchType: "functions",
+	  symbolSearchResults: [],
+	  searchResults: {
+	    index: -1,
+	    count: 0
+	  },
 	  shownSource: "",
 	  startPanelCollapsed: _prefs.prefs.startPanelCollapsed,
 	  endPanelCollapsed: _prefs.prefs.endPanelCollapsed,
 	  frameworkGroupingOn: _prefs.prefs.frameworkGroupingOn,
 	  highlightedLineRange: undefined
 	});
 
 	function update() {
@@ -15076,16 +15198,26 @@ return /******/ (function(modules) { // 
 	        return state.set("symbolSearchOn", action.value);
 	      }
 
 	    case "UPDATE_FILE_SEARCH_QUERY":
 	      {
 	        return state.set("fileSearchQuery", action.query);
 	      }
 
+	    case "UPDATE_SEARCH_RESULTS":
+	      {
+	        return state.set("searchResults", action.results);
+	      }
+
+	    case "UPDATE_SYMBOL_SEARCH_RESULTS":
+	      {
+	        return state.set("symbolSearchResults", action.results);
+	      }
+
 	    case "TOGGLE_FILE_SEARCH_MODIFIER":
 	      {
 	        var actionVal = !state.getIn(["fileSearchModifiers", action.modifier]);
 
 	        if (action.modifier == "caseSensitive") {
 	          _prefs.prefs.fileSearchCaseSensitive = actionVal;
 	        }
 
@@ -15155,16 +15287,24 @@ return /******/ (function(modules) { // 
 	function getFileSearchQueryState(state) {
 	  return state.ui.get("fileSearchQuery");
 	}
 
 	function getFileSearchModifierState(state) {
 	  return state.ui.get("fileSearchModifiers");
 	}
 
+	function getSymbolSearchResults(state) {
+	  return state.ui.get("symbolSearchResults");
+	}
+
+	function getSearchResults(state) {
+	  return state.ui.get("searchResults");
+	}
+
 	function getFrameworkGroupingState(state) {
 	  return state.ui.get("frameworkGroupingOn");
 	}
 
 	function getSymbolSearchType(state) {
 	  return state.ui.get("symbolSearchType");
 	}
 
@@ -15324,16 +15464,17 @@ return /******/ (function(modules) { // 
 	  getBreakpointsForSource: breakpoints.getBreakpointsForSource,
 	  getBreakpointsDisabled: breakpoints.getBreakpointsDisabled,
 	  getBreakpointsLoading: breakpoints.getBreakpointsLoading,
 
 	  getPause: pause.getPause,
 	  getChromeScopes: pause.getChromeScopes,
 	  getLoadedObjects: pause.getLoadedObjects,
 	  getLoadedObject: pause.getLoadedObject,
+	  getFrameScopes: pause.getFrameScopes,
 	  getObjectProperties: pause.getObjectProperties,
 	  getIsWaitingOnBreak: pause.getIsWaitingOnBreak,
 	  getShouldPauseOnExceptions: pause.getShouldPauseOnExceptions,
 	  getShouldIgnoreCaughtExceptions: pause.getShouldIgnoreCaughtExceptions,
 	  getFrames: pause.getFrames,
 	  getSelectedFrame: pause.getSelectedFrame,
 	  getDebuggeeUrl: pause.getDebuggeeUrl,
 
@@ -15341,16 +15482,18 @@ return /******/ (function(modules) { // 
 	  getCoverageEnabled: coverage.getCoverageEnabled,
 
 	  getEventListeners: eventListeners.getEventListeners,
 
 	  getProjectSearchState: ui.getProjectSearchState,
 	  getFileSearchState: ui.getFileSearchState,
 	  getFileSearchQueryState: ui.getFileSearchQueryState,
 	  getFileSearchModifierState: ui.getFileSearchModifierState,
+	  getSymbolSearchResults: ui.getSymbolSearchResults,
+	  getSearchResults: ui.getSearchResults,
 	  getFrameworkGroupingState: ui.getFrameworkGroupingState,
 	  getSymbolSearchState: ui.getSymbolSearchState,
 	  getSymbolSearchType: ui.getSymbolSearchType,
 	  getShownSource: ui.getShownSource,
 	  getPaneCollapse: ui.getPaneCollapse,
 
 	  getExpressions: expressions.getExpressions,
 	  getVisibleExpressions: expressions.getVisibleExpressions,
@@ -15644,79 +15787,103 @@ return /******/ (function(modules) { // 
 	    return yield sourceMaps.getGeneratedLocation(location, source.toJS());
 	  });
 
 	  return function _getGeneratedLocation(_x2, _x3, _x4) {
 	    return _ref.apply(this, arguments);
 	  };
 	})();
 
-	var syncClientBreakpoint = (() => {
-	  var _ref2 = _asyncToGenerator(function* (sourceId, client, sourceMaps, pendingBreakpoint) {
-	    var generatedSourceId = sourceMaps.isOriginalId(sourceId) ? (0, _devtoolsSourceMap.originalToGeneratedId)(sourceId) : sourceId;
-
-	    // this is the generatedLocation of the pending breakpoint, with
-	    // the source id updated to reflect the new connection
-	    var oldGeneratedLocation = _extends({}, pendingBreakpoint.generatedLocation, {
-	      sourceId: generatedSourceId
-	    });
-
-	    // early return if breakpoint is disabled with overrides to update
-	    // the id as expected, without talking to server
-	    if (pendingBreakpoint.disabled) {
-	      return {
-	        id: generatedSourceId,
-	        actualLocation: _extends({}, pendingBreakpoint.location, { id: sourceId }),
-	        oldGeneratedLocation
-	      };
-	    }
-
-	    // If we are not disabled, set the breakpoint on the server and get
-	    // that info so we can set it on our breakpoints.
-	    var clientBreakpoint = yield client.setBreakpoint(oldGeneratedLocation, pendingBreakpoint.condition, sourceMaps.isOriginalId(sourceId));
-
-	    // Original location is the location in the src file
+	var _formatClientBreakpoint = (() => {
+	  var _ref2 = _asyncToGenerator(function* (clientBreakpoint, sourceMaps, location) {
 	    var clientOriginalLocation = yield sourceMaps.getOriginalLocation(clientBreakpoint.actualLocation);
 
 	    // make sure that we are re-adding the same type of breakpoint. Column
 	    // or line
-	    var actualLocation = (0, _breakpoint.equalizeLocationColumn)(clientOriginalLocation, pendingBreakpoint.location);
+	    var actualLocation = (0, _breakpoint.equalizeLocationColumn)(clientOriginalLocation, location);
 
 	    // the generatedLocation might have slid, so now we can adjust it
 	    var generatedLocation = clientBreakpoint.actualLocation;
 
 	    var id = clientBreakpoint.id,
 	        hitCount = clientBreakpoint.hitCount;
 
 	    return { id, actualLocation, hitCount, generatedLocation };
 	  });
 
-	  return function syncClientBreakpoint(_x5, _x6, _x7, _x8) {
+	  return function _formatClientBreakpoint(_x5, _x6, _x7) {
 	    return _ref2.apply(this, arguments);
 	  };
 	})();
 
+	// we have three forms of syncing: disabled syncing, existing server syncing
+	// and adding a new breakpoint
+
+
+	var syncClientBreakpoint = (() => {
+	  var _ref3 = _asyncToGenerator(function* (sourceId, client, sourceMaps, pendingBreakpoint) {
+	    var generatedSourceId = sourceMaps.isOriginalId(sourceId) ? (0, _devtoolsSourceMap.originalToGeneratedId)(sourceId) : sourceId;
+
+	    // this is the generatedLocation of the pending breakpoint, with
+	    // the source id updated to reflect the new connection
+	    var oldGeneratedLocation = _extends({}, pendingBreakpoint.generatedLocation, {
+	      sourceId: generatedSourceId
+	    });
+
+	    /** ******* CASE 1: Disabled ***********/
+	    // early return if breakpoint is disabled, send overrides to update
+	    // the id as expected
+	    if (pendingBreakpoint.disabled) {
+	      return {
+	        id: generatedSourceId,
+	        actualLocation: _extends({}, pendingBreakpoint.location, { id: sourceId }),
+	        generatedLocation: oldGeneratedLocation
+	      };
+	    }
+
+	    /** ******* CASE 2: Merge Server Breakpoint ***********/
+	    // early return if breakpoint exists on the server, send overrides
+	    // to update the id as expected
+	    var existingClient = client.getBreakpointByLocation(oldGeneratedLocation);
+
+	    if (existingClient) {
+	      return _formatClientBreakpoint(existingClient, sourceMaps, pendingBreakpoint.location);
+	    }
+
+	    /** ******* CASE 3: Add New Breakpoint ***********/
+	    // If we are not disabled, set the breakpoint on the server and get
+	    // that info so we can set it on our breakpoints.
+	    var clientBreakpoint = yield client.setBreakpoint(oldGeneratedLocation, pendingBreakpoint.condition, sourceMaps.isOriginalId(sourceId));
+
+	    return _formatClientBreakpoint(clientBreakpoint, sourceMaps, pendingBreakpoint.location);
+	  });
+
+	  return function syncClientBreakpoint(_x8, _x9, _x10, _x11) {
+	    return _ref3.apply(this, arguments);
+	  };
+	})();
+
 	var addClientBreakpoint = (() => {
-	  var _ref3 = _asyncToGenerator(function* (state, client, sourceMaps, breakpoint) {
+	  var _ref4 = _asyncToGenerator(function* (state, client, sourceMaps, breakpoint) {
 	    var location = breakpoint.location;
 	    var source = (0, _selectors.getSource)(state, location.sourceId);
 	    var generatedLocation = yield _getGeneratedLocation(source, sourceMaps, location);
 
 	    var clientBreakpoint = yield client.setBreakpoint(generatedLocation, breakpoint.condition, sourceMaps.isOriginalId(breakpoint.location.sourceId));
 
 	    var actualLocation = yield sourceMaps.getOriginalLocation(clientBreakpoint.actualLocation);
 
 	    var id = clientBreakpoint.id,
 	        hitCount = clientBreakpoint.hitCount;
 
 	    return { id, actualLocation, hitCount, generatedLocation };
 	  });
 
-	  return function addClientBreakpoint(_x9, _x10, _x11, _x12) {
-	    return _ref3.apply(this, arguments);
+	  return function addClientBreakpoint(_x12, _x13, _x14, _x15) {
+	    return _ref4.apply(this, arguments);
 	  };
 	})();
 
 	/**
 	 * Enabling a breakpoint
 	 * will reuse the existing breakpoint information that is stored.
 	 *
 	 * @memberof actions/breakpoints
@@ -15768,21 +15935,21 @@ return /******/ (function(modules) { // 
 	    generatedLocation,
 	    location
 	  };
 
 	  return properties;
 	}
 
 	function enableBreakpoint(location) {
-	  return (_ref4) => {
-	    var dispatch = _ref4.dispatch,
-	        getState = _ref4.getState,
-	        client = _ref4.client,
-	        sourceMaps = _ref4.sourceMaps;
+	  return (_ref5) => {
+	    var dispatch = _ref5.dispatch,
+	        getState = _ref5.getState,
+	        client = _ref5.client,
+	        sourceMaps = _ref5.sourceMaps;
 
 	    var breakpoint = (0, _selectors.getBreakpoint)(getState(), location);
 	    if (!breakpoint) {
 	      throw new Error("attempted to enable a breakpoint that does not exist");
 	    }
 
 	    return dispatch({
 	      type: "ENABLE_BREAKPOINT",
@@ -15797,21 +15964,21 @@ return /******/ (function(modules) { // 
 	 * contact the server for more data.
 	 *
 	 * @memberof actions/breakpoints
 	 * @static
 	 * @param {String} $1.sourceId String  value
 	 * @param {PendingBreakpoint} $1.location PendingBreakpoint  value
 	 */
 	function syncBreakpoint(sourceId, pendingBreakpoint) {
-	  return (_ref5) => {
-	    var dispatch = _ref5.dispatch,
-	        getState = _ref5.getState,
-	        client = _ref5.client,
-	        sourceMaps = _ref5.sourceMaps;
+	  return (_ref6) => {
+	    var dispatch = _ref6.dispatch,
+	        getState = _ref6.getState,
+	        client = _ref6.client,
+	        sourceMaps = _ref6.sourceMaps;
 	    var _pendingBreakpoint$lo = pendingBreakpoint.location,
 	        line = _pendingBreakpoint$lo.line,
 	        sourceUrl = _pendingBreakpoint$lo.sourceUrl,
 	        column = _pendingBreakpoint$lo.column;
 
 	    var location = { sourceId, sourceUrl, line, column };
 	    var breakpoint = _createBreakpoint(location, pendingBreakpoint);
 
@@ -15829,24 +15996,24 @@ return /******/ (function(modules) { // 
 	 * Add a new breakpoint
 	 *
 	 * @memberof actions/breakpoints
 	 * @static
 	 * @param {String} $1.condition Conditional breakpoint condition value
 	 * @param {Boolean} $1.disabled Disable value for breakpoint value
 	 */
 	function addBreakpoint(location) {
-	  var _ref6 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
-	      condition = _ref6.condition;
-
-	  return (_ref7) => {
-	    var dispatch = _ref7.dispatch,
-	        getState = _ref7.getState,
-	        client = _ref7.client,
-	        sourceMaps = _ref7.sourceMaps;
+	  var _ref7 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
+	      condition = _ref7.condition;
+
+	  return (_ref8) => {
+	    var dispatch = _ref8.dispatch,
+	        getState = _ref8.getState,
+	        client = _ref8.client,
+	        sourceMaps = _ref8.sourceMaps;
 
 	    if (_breakpointExists(getState(), location)) {
 	      return Promise.resolve();
 	    }
 
 	    var breakpoint = _createBreakpoint(location, { condition });
 	    return dispatch({
 	      type: "ADD_BREAKPOINT",
@@ -15859,20 +16026,20 @@ return /******/ (function(modules) { // 
 
 	/**
 	 * Disable a single breakpoint
 	 *
 	 * @memberof actions/breakpoints
 	 * @static
 	 */
 	function disableBreakpoint(location) {
-	  return (_ref8) => {
-	    var dispatch = _ref8.dispatch,
-	        getState = _ref8.getState,
-	        client = _ref8.client;
+	  return (_ref9) => {
+	    var dispatch = _ref9.dispatch,
+	        getState = _ref9.getState,
+	        client = _ref9.client;
 
 	    var bp = (0, _selectors.getBreakpoint)(getState(), location);
 	    if (!bp) {
 	      throw new Error("attempt to disable a breakpoint that does not exist");
 	    }
 	    if (bp.loading) {
 	      // TODO(jwl): make this wait until the breakpoint is saved if it
 	      // is still loading
@@ -15892,20 +16059,20 @@ return /******/ (function(modules) { // 
 
 	/**
 	 * Remove a single breakpoint
 	 *
 	 * @memberof actions/breakpoints
 	 * @static
 	 */
 	function removeBreakpoint(location) {
-	  return (_ref9) => {
-	    var dispatch = _ref9.dispatch,
-	        getState = _ref9.getState,
-	        client = _ref9.client;
+	  return (_ref10) => {
+	    var dispatch = _ref10.dispatch,
+	        getState = _ref10.getState,
+	        client = _ref10.client;
 
 	    var bp = (0, _selectors.getBreakpoint)(getState(), location);
 	    if (!bp) {
 	      throw new Error("attempt to remove breakpoint that does not exist");
 	    }
 	    if (bp.loading) {
 	      // TODO(jwl): make this wait until the breakpoint is saved if it
 	      // is still loading
@@ -15932,29 +16099,29 @@ return /******/ (function(modules) { // 
 
 	/**
 	 * Toggle All Breakpoints
 	 *
 	 * @memberof actions/breakpoints
 	 * @static
 	 */
 	function toggleAllBreakpoints(shouldDisableBreakpoints) {
-	  return (_ref10) => {
-	    var dispatch = _ref10.dispatch,
-	        getState = _ref10.getState;
+	  return (_ref11) => {
+	    var dispatch = _ref11.dispatch,
+	        getState = _ref11.getState;
 
 	    var breakpoints = (0, _selectors.getBreakpoints)(getState());
 	    return dispatch({
 	      type: "TOGGLE_BREAKPOINTS",
 	      shouldDisableBreakpoints,
 	      [_promise.PROMISE]: _asyncToGenerator(function* () {
-	        for (var _ref12 of breakpoints) {
-	          var _ref13 = _slicedToArray(_ref12, 2);
-
-	          var breakpoint = _ref13[1];
+	        for (var _ref13 of breakpoints) {
+	          var _ref14 = _slicedToArray(_ref13, 2);
+
+	          var breakpoint = _ref14[1];
 
 	          if (shouldDisableBreakpoints) {
 	            yield dispatch(disableBreakpoint(breakpoint.location));
 	          } else {
 	            yield dispatch(enableBreakpoint(breakpoint.location));
 	          }
 	        }
 	      })()
@@ -15970,24 +16137,24 @@ return /******/ (function(modules) { // 
 	 * @static
 	 * @param {Location} location
 	 *        @see DebuggerController.Breakpoints.addBreakpoint
 	 * @param {string} condition
 	 *        The condition to set on the breakpoint
 	 * @param {Boolean} $1.disabled Disable value for breakpoint value
 	 */
 	function setBreakpointCondition(location) {
-	  var _ref14 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
-	      condition = _ref14.condition;
-
-	  return (_ref15) => {
-	    var dispatch = _ref15.dispatch,
-	        getState = _ref15.getState,
-	        client = _ref15.client,
-	        sourceMaps = _ref15.sourceMaps;
+	  var _ref15 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
+	      condition = _ref15.condition;
+
+	  return (_ref16) => {
+	    var dispatch = _ref16.dispatch,
+	        getState = _ref16.getState,
+	        client = _ref16.client,
+	        sourceMaps = _ref16.sourceMaps;
 
 	    var bp = (0, _selectors.getBreakpoint)(getState(), location);
 	    if (!bp) {
 	      return dispatch(addBreakpoint(location, { condition }));
 	    }
 
 	    if (bp.loading) {
 	      // TODO(jwl): when this function is called, make sure the action
@@ -16715,26 +16882,21 @@ return /******/ (function(modules) { // 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
 
 	var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
 
 	var checkPendingBreakpoint = (() => {
 	  var _ref = _asyncToGenerator(function* (state, dispatch, pendingBreakpoint, source) {
-	    var _pendingBreakpoint$lo = pendingBreakpoint.location,
-	        line = _pendingBreakpoint$lo.line,
-	        sourceUrl = _pendingBreakpoint$lo.sourceUrl,
-	        column = _pendingBreakpoint$lo.column;
+	    var sourceUrl = pendingBreakpoint.location.sourceUrl;
 
 	    var sameSource = sourceUrl && sourceUrl === source.url;
-	    var location = { sourceId: source.id, sourceUrl, line, column };
-	    var bp = (0, _selectors.getBreakpoint)(state, location);
-
-	    if (sameSource && !bp) {
+
+	    if (sameSource) {
 	      yield dispatch((0, _breakpoints.syncBreakpoint)(source.id, pendingBreakpoint));
 	    }
 	  });
 
 	  return function checkPendingBreakpoint(_x, _x2, _x3, _x4) {
 	    return _ref.apply(this, arguments);
 	  };
 	})();
@@ -16764,16 +16926,17 @@ return /******/ (function(modules) { // 
 	 */
 
 
 	exports.newSource = newSource;
 	exports.newSources = newSources;
 	exports.selectSourceURL = selectSourceURL;
 	exports.selectSource = selectSource;
 	exports.jumpToMappedLocation = jumpToMappedLocation;
+	exports.moveTab = moveTab;
 	exports.closeTab = closeTab;
 	exports.closeTabs = closeTabs;
 	exports.togglePrettyPrint = togglePrettyPrint;
 	exports.toggleBlackBox = toggleBlackBox;
 	exports.loadSourceText = loadSourceText;
 	exports.getTextForSources = getTextForSources;
 
 	var _defer = __webpack_require__(194);
@@ -16952,17 +17115,16 @@ return /******/ (function(modules) { // 
 
 	    if (!client) {
 	      // No connection, do nothing. This happens when the debugger is
 	      // shut down too fast and it tries to display a default source.
 	      return;
 	    }
 
 	    var source = (0, _selectors.getSource)(getState(), id);
-
 	    if (!source) {
 	      // If there is no source we deselect the current selected source
 	      return dispatch({ type: "CLEAR_SELECTED_SOURCE" });
 	    }
 
 	    dispatch({ type: "TOGGLE_PROJECT_SEARCH", value: false });
 
 	    return dispatch({
@@ -17006,16 +17168,24 @@ return /******/ (function(modules) { // 
 	    });
 
 	    return function (_x13) {
 	      return _ref12.apply(this, arguments);
 	    };
 	  })();
 	}
 
+	function moveTab(url, tabIndex) {
+	  return {
+	    type: "MOVE_TAB",
+	    url,
+	    tabIndex
+	  };
+	}
+
 	/**
 	 * @memberof actions/sources
 	 * @static
 	 */
 	function closeTab(url) {
 	  return (_ref14) => {
 	    var dispatch = _ref14.dispatch,
 	        getState = _ref14.getState,
@@ -17302,17 +17472,22 @@ return /******/ (function(modules) { // 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
 	exports.updateFrameLocations = updateFrameLocations;
 	exports.getPauseReason = getPauseReason;
 
-	var get = __webpack_require__(67);
+	var _get = __webpack_require__(67);
+
+	var _get2 = _interopRequireDefault(_get);
+
+	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
 	function updateFrameLocations(frames, sourceMaps) {
 	  if (!frames || frames.length == 0) {
 	    return Promise.resolve(frames);
 	  }
 
 	  return Promise.all(frames.map(frame => {
 	    return sourceMaps.getOriginalLocation(frame.location).then(loc => {
 	      return Object.assign({}, frame, {
@@ -17344,17 +17519,17 @@ return /******/ (function(modules) { // 
 	  other: "whyPaused.other"
 	};
 
 	function getPauseReason(pauseInfo) {
 	  if (!pauseInfo) {
 	    return null;
 	  }
 
-	  var reasonType = get(pauseInfo, "why.type", null);
+	  var reasonType = (0, _get2.default)(pauseInfo, "why.type", null);
 	  if (!reasons[reasonType]) {
 	    console.log("Please file an issue: reasonType=", reasonType);
 	  }
 	  return reasons[reasonType];
 	}
 
 /***/ },
 /* 256 */,
@@ -17364,38 +17539,32 @@ return /******/ (function(modules) { // 
 	"use strict";
 
 	var _devtoolsConfig = __webpack_require__(828);
 
 	var _source = __webpack_require__(233);
 
 	var _devtoolsSourceMap = __webpack_require__(898);
 
-	var _buildQuery = __webpack_require__(258);
-
-	var _buildQuery2 = _interopRequireDefault(_buildQuery);
-
 	var _sourceDocuments = __webpack_require__(260);
 
 	var sourceDocumentUtils = _interopRequireWildcard(_sourceDocuments);
 
 	var _expression = __webpack_require__(904);
 
 	var expressionUtils = _interopRequireWildcard(_expression);
 
 	var _sourceSearch = __webpack_require__(261);
 
 	var sourceSearchUtils = _interopRequireWildcard(_sourceSearch);
 
 	var _devtoolsSourceEditor = __webpack_require__(994);
 
 	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 }; }
-
 	var getDocument = sourceDocumentUtils.getDocument;
 	var findNext = sourceSearchUtils.findNext,
 	    findPrev = sourceSearchUtils.findPrev;
 
 
 	function shouldShowPrettyPrint(selectedSource) {
 	  if (!selectedSource) {
 	    return false;
@@ -17417,27 +17586,34 @@ return /******/ (function(modules) { // 
 	function shouldShowFooter(selectedSource, horizontal) {
 	  if (!horizontal) {
 	    return true;
 	  }
 
 	  return shouldShowPrettyPrint(selectedSource);
 	}
 
-	function isTextForSource(sourceText) {
-	  return !sourceText.get("loading") && !sourceText.get("error");
-	}
-
 	function breakpointAtLocation(breakpoints, _ref) {
 	  var line = _ref.line,
 	      _ref$column = _ref.column,
 	      column = _ref$column === undefined ? undefined : _ref$column;
 
 	  return breakpoints.find(bp => {
-	    return bp.location.line === line + 1 && bp.location.column === column;
+	    var sameLine = bp.location.line === line + 1;
+	    if (!sameLine) {
+	      return false;
+	    }
+
+	    // NOTE: when column breakpoints are disabled we want to find
+	    // the first breakpoint
+	    if (!(0, _devtoolsConfig.isEnabled)("columnBreakpoints")) {
+	      return true;
+	    }
+
+	    return bp.location.column === column;
 	  });
 	}
 
 	function traverseResults(e, ctx, query, dir, modifiers) {
 	  e.stopPropagation();
 	  e.preventDefault();
 
 	  if (dir == "prev") {
@@ -17485,110 +17661,23 @@ return /******/ (function(modules) { // 
 	    this.setText(sourceText.get("text"));
 	  }
 	}
 
 	module.exports = Object.assign({}, expressionUtils, sourceDocumentUtils, sourceSearchUtils, _devtoolsSourceEditor.SourceEditorUtils, {
 	  createEditor,
 	  shouldShowPrettyPrint,
 	  shouldShowFooter,
-	  buildQuery: _buildQuery2.default,
-	  isTextForSource,
 	  breakpointAtLocation,
 	  traverseResults,
 	  updateDocument
 	});
 
 /***/ },
-/* 258 */
-/***/ function(module, exports, __webpack_require__) {
-
-	"use strict";
-
-	Object.defineProperty(exports, "__esModule", {
-	  value: true
-	});
-	exports.default = buildQuery;
-
-	var _escapeRegExp = __webpack_require__(259);
-
-	var _escapeRegExp2 = _interopRequireDefault(_escapeRegExp);
-
-	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-	/**
-	 * Ignore doing outline matches for less than 3 whitespaces
-	 *
-	 * @memberof utils/source-search
-	 * @static
-	 */
-	function ignoreWhiteSpace(str) {
-	  return (/^\s{0,2}$/.test(str) ? "(?!\\s*.*)" : str
-	  );
-	}
-
-
-	function wholeMatch(query, wholeWord) {
-	  if (query == "" || !wholeWord) {
-	    return query;
-	  }
-
-	  return `\\b${query}\\b`;
-	}
-
-	function buildFlags(caseSensitive, isGlobal) {
-	  if (caseSensitive && isGlobal) {
-	    return "g";
-	  }
-
-	  if (!caseSensitive && isGlobal) {
-	    return "gi";
-	  }
-
-	  if (!caseSensitive && !isGlobal) {
-	    return "i";
-	  }
-
-	  return;
-	}
-
-	function buildQuery(originalQuery, modifiers, _ref) {
-	  var _ref$isGlobal = _ref.isGlobal,
-	      isGlobal = _ref$isGlobal === undefined ? false : _ref$isGlobal,
-	      _ref$ignoreSpaces = _ref.ignoreSpaces,
-	      ignoreSpaces = _ref$ignoreSpaces === undefined ? false : _ref$ignoreSpaces;
-	  var caseSensitive = modifiers.caseSensitive,
-	      regexMatch = modifiers.regexMatch,
-	      wholeWord = modifiers.wholeWord;
-
-
-	  if (originalQuery == "") {
-	    return new RegExp(originalQuery);
-	  }
-
-	  var query = originalQuery;
-	  if (ignoreSpaces) {
-	    query = ignoreWhiteSpace(query);
-	  }
-
-	  if (!regexMatch) {
-	    query = (0, _escapeRegExp2.default)(query);
-	  }
-
-	  query = wholeMatch(query, wholeWord);
-	  var flags = buildFlags(caseSensitive, isGlobal);
-
-	  if (flags) {
-	    return new RegExp(query, flags);
-	  }
-
-	  return new RegExp(query);
-	}
-
-/***/ },
+/* 258 */,
 /* 259 */
 /***/ function(module, exports, __webpack_require__) {
 
 	var toString = __webpack_require__(108);
 
 	/**
 	 * Used to match `RegExp`
 	 * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
@@ -17657,19 +17746,19 @@ return /******/ (function(modules) { // 
 /* 261 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
-	exports.getMatchIndex = exports.removeOverlay = exports.findPrev = exports.findNext = exports.find = exports.countMatches = exports.clearIndex = exports.buildQuery = undefined;
-
-	var _buildQuery = __webpack_require__(258);
+	exports.getMatchIndex = exports.removeOverlay = exports.findPrev = exports.findNext = exports.find = exports.clearIndex = exports.buildQuery = undefined;
+
+	var _buildQuery = __webpack_require__(1116);
 
 	var _buildQuery2 = _interopRequireDefault(_buildQuery);
 
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 	/**
 	 * @memberof utils/source-search
 	 * @static
@@ -17949,27 +18038,18 @@ return /******/ (function(modules) { // 
 	  return doSearch(ctx, true, query, keepSelection, modifiers);
 	}
 
 	function clearIndex(ctx, query, modifiers) {
 	  var state = getSearchState(ctx.cm, query, modifiers);
 	  state.matchIndex = -1;
 	}
 
-	function countMatches(query, text, modifiers) {
-	  var regexQuery = (0, _buildQuery2.default)(query, modifiers, {
-	    isGlobal: true
-	  });
-	  var match = text.match(regexQuery);
-	  return match ? match.length : 0;
-	}
-
 	exports.buildQuery = _buildQuery2.default;
 	exports.clearIndex = clearIndex;
-	exports.countMatches = countMatches;
 	exports.find = find;
 	exports.findNext = findNext;
 	exports.findPrev = findPrev;
 	exports.removeOverlay = removeOverlay;
 	exports.getMatchIndex = getMatchIndex;
 
 /***/ },
 /* 262 */
@@ -19684,23 +19764,27 @@ return /******/ (function(modules) { // 
 	      var dispatch = _ref3.dispatch,
 	          getState = _ref3.getState,
 	          client = _ref3.client,
 	          sourceMaps = _ref3.sourceMaps;
 	      var frames = pauseInfo.frames,
 	          why = pauseInfo.why,
 	          loadedObjects = pauseInfo.loadedObjects;
 
+
 	      frames = yield (0, _pause.updateFrameLocations)(frames, sourceMaps);
 	      var frame = frames[0];
 
+	      var scopes = yield client.getFrameScopes(frame);
+
 	      dispatch({
 	        type: "PAUSED",
 	        pauseInfo: { why, frame, frames },
 	        frames: frames,
+	        scopes,
 	        selectedFrameId: frame.id,
 	        loadedObjects: loadedObjects || []
 	      });
 
 	      dispatch((0, _expressions.evaluateExpressions)(frame.id));
 
 	      dispatch((0, _sources.selectSource)(frame.location.sourceId, { line: frame.location.line }));
 	    });
@@ -19844,37 +19928,48 @@ return /******/ (function(modules) { // 
 	  };
 	}
 
 	/**
 	 * @memberof actions/pause
 	 * @static
 	 */
 	function selectFrame(frame) {
-	  return (_ref12) => {
-	    var dispatch = _ref12.dispatch;
-
-	    dispatch((0, _expressions.evaluateExpressions)(frame.id));
-	    dispatch((0, _sources.selectSource)(frame.location.sourceId, { line: frame.location.line }));
-	    dispatch({
-	      type: "SELECT_FRAME",
-	      frame
-	    });
-	  };
+	  return (() => {
+	    var _ref12 = _asyncToGenerator(function* (_ref13) {
+	      var dispatch = _ref13.dispatch,
+	          client = _ref13.client;
+
+	      dispatch((0, _expressions.evaluateExpressions)(frame.id));
+	      dispatch((0, _sources.selectSource)(frame.location.sourceId, { line: frame.location.line }));
+
+	      var scopes = yield client.getFrameScopes(frame);
+
+	      dispatch({
+	        type: "SELECT_FRAME",
+	        frame,
+	        scopes
+	      });
+	    });
+
+	    return function (_x2) {
+	      return _ref12.apply(this, arguments);
+	    };
+	  })();
 	}
 
 	/**
 	 * @memberof actions/pause
 	 * @static
 	 */
 	function loadObjectProperties(object) {
-	  return (_ref13) => {
-	    var dispatch = _ref13.dispatch,
-	        client = _ref13.client,
-	        getState = _ref13.getState;
+	  return (_ref14) => {
+	    var dispatch = _ref14.dispatch,
+	        client = _ref14.client,
+	        getState = _ref14.getState;
 
 	    var objectId = object.actor || object.objectId;
 
 	    if ((0, _selectors.getLoadedObject)(getState(), objectId)) {
 	      return;
 	    }
 
 	    dispatch({
@@ -19973,16 +20068,18 @@ return /******/ (function(modules) { // 
 	  value: true
 	});
 	exports.toggleProjectSearch = toggleProjectSearch;
 	exports.toggleFileSearch = toggleFileSearch;
 	exports.toggleSymbolSearch = toggleSymbolSearch;
 	exports.toggleFrameworkGrouping = toggleFrameworkGrouping;
 	exports.setSelectedSymbolType = setSelectedSymbolType;
 	exports.setFileSearchQuery = setFileSearchQuery;
+	exports.updateSearchResults = updateSearchResults;
+	exports.updateSymbolSearchResults = updateSymbolSearchResults;
 	exports.toggleFileSearchModifier = toggleFileSearchModifier;
 	exports.showSource = showSource;
 	exports.togglePaneCollapse = togglePaneCollapse;
 	exports.highlightLineRange = highlightLineRange;
 	exports.clearHighlightLineRange = clearHighlightLineRange;
 
 	var _selectors = __webpack_require__(242);
 
@@ -20067,16 +20164,30 @@ return /******/ (function(modules) { // 
 
 	function setFileSearchQuery(query) {
 	  return {
 	    type: "UPDATE_FILE_SEARCH_QUERY",
 	    query
 	  };
 	}
 
+	function updateSearchResults(results) {
+	  return {
+	    type: "UPDATE_SEARCH_RESULTS",
+	    results
+	  };
+	}
+
+	function updateSymbolSearchResults(results) {
+	  return {
+	    type: "UPDATE_SYMBOL_SEARCH_RESULTS",
+	    results
+	  };
+	}
+
 	function toggleFileSearchModifier(modifier) {
 	  return { type: "TOGGLE_FILE_SEARCH_MODIFIER", modifier };
 	}
 
 	function showSource(sourceId) {
 	  return (_ref6) => {
 	    var dispatch = _ref6.dispatch,
 	        getState = _ref6.getState;
@@ -21932,16 +22043,18 @@ return /******/ (function(modules) { // 
 	  "column-breakpoint": __webpack_require__(998),
 	  "case-match": __webpack_require__(351),
 	  close: __webpack_require__(352),
 	  domain: __webpack_require__(353),
 	  file: __webpack_require__(354),
 	  folder: __webpack_require__(355),
 	  globe: __webpack_require__(356),
 	  jquery: __webpack_require__(999),
+	  underscore: __webpack_require__(1117),
+	  lodash: __webpack_require__(1118),
 	  "magnifying-glass": __webpack_require__(357),
 	  "arrow-up": __webpack_require__(919),
 	  "arrow-down": __webpack_require__(920),
 	  pause: __webpack_require__(358),
 	  "pause-exceptions": __webpack_require__(359),
 	  plus: __webpack_require__(360),
 	  prettyPrint: __webpack_require__(361),
 	  react: __webpack_require__(1000),
@@ -24692,20 +24805,16 @@ return /******/ (function(modules) { // 
 	    super();
 
 	    this.cbPanel = null;
 	    this.editor = null;
 	    this.pendingJumpLine = null;
 	    this.lastJumpLine = null;
 
 	    this.state = {
-	      searchResults: {
-	        index: -1,
-	        count: 0
-	      },
 	      highlightedLineRange: null,
 	      selectedToken: null
 	    };
 
 	    var self = this;
 	    self.closeConditionalPanel = this.closeConditionalPanel.bind(this);
 	    self.onEscape = this.onEscape.bind(this);
 	    self.onGutterClick = this.onGutterClick.bind(this);
@@ -24713,39 +24822,40 @@ return /******/ (function(modules) { // 
 	    self.onScroll = this.onScroll.bind(this);
 	    self.onSearchAgain = this.onSearchAgain.bind(this);
 	    self.onToggleBreakpoint = this.onToggleBreakpoint.bind(this);
 	    self.previewSelectedToken = (0, _debounce2.default)(this.previewSelectedToken.bind(this), 100);
 	    self.toggleBreakpoint = this.toggleBreakpoint.bind(this);
 	    // eslint-disable-next-line max-len
 	    self.toggleBreakpointDisabledStatus = this.toggleBreakpointDisabledStatus.bind(this);
 	    self.toggleConditionalPanel = this.toggleConditionalPanel.bind(this);
-	    self.updateSearchResults = this.updateSearchResults.bind(this);
 	  }
 
 	  componentWillReceiveProps(nextProps) {
 	    // This lifecycle method is responsible for updating the editor
 	    // text.
-	    var sourceText = nextProps.sourceText,
+	    var selectedSource = nextProps.selectedSource,
 	        selectedLocation = nextProps.selectedLocation;
 
 	    this.clearDebugLine(this.props.selectedFrame);
 
 	    if (nextProps.startPanelSize !== this.props.startPanelSize || nextProps.endPanelSize !== this.props.endPanelSize) {
 	      this.editor.codeMirror.setSize();
 	    }
 
-	    if (!sourceText) {
-	      if (this.props.sourceText) {
+	    if (!selectedSource) {
+	      if (this.props.selectedSource) {
 	        this.showMessage("");
 	      }
-	    } else if (!(0, _editor.isTextForSource)(sourceText)) {
-	      this.showMessage(sourceText.get("error") || L10N.getStr("loadingText"));
-	    } else if (this.props.sourceText !== sourceText) {
-	      this.showSourceText(sourceText, selectedLocation);
+	    } else if (selectedSource.get("loading")) {
+	      this.showMessage(L10N.getStr("loadingText"));
+	    } else if (selectedSource.get("error")) {
+	      this.showMessage(selectedSource.get("error"));
+	    } else if (this.props.selectedSource !== selectedSource) {
+	      this.showSourceText(selectedSource, selectedLocation);
 	    }
 
 	    if (this.props.outOfScopeLocations !== nextProps.outOfScopeLocations) {
 	      (0, _editor.clearLineClass)(this.editor.codeMirror, "out-of-scope");
 	    }
 
 	    this.setDebugLine(nextProps.selectedFrame, selectedLocation);
 	    (0, _editor.resizeBreakpointGutter)(this.editor.codeMirror);
@@ -24836,17 +24946,19 @@ return /******/ (function(modules) { // 
 	    shortcuts.off(searchAgainPrevKey);
 	    shortcuts.off(searchAgainKey);
 	  }
 
 	  componentDidUpdate(prevProps) {
 	    // This is in `componentDidUpdate` so helper functions can expect
 	    // `this.props` to be the current props. This lifecycle method is
 	    // responsible for updating the editor annotations.
-	    var selectedLocation = this.props.selectedLocation;
+	    var _props2 = this.props,
+	        selectedLocation = _props2.selectedLocation,
+	        selectedSource = _props2.selectedSource;
 
 	    // If the location is different and a new line is requested,
 	    // update the pending jump line. Note that if jumping to a line in
 	    // a source where the text hasn't been loaded yet, we will set the
 	    // line here but not jump until rendering the actual source.
 
 	    if (prevProps.selectedLocation !== selectedLocation) {
 	      if (selectedLocation && selectedLocation.line != undefined) {
@@ -24854,17 +24966,17 @@ return /******/ (function(modules) { // 
 	      } else {
 	        this.pendingJumpLine = null;
 	      }
 	    }
 
 	    // Only update and jump around in real source texts. This will
 	    // keep the jump state around until the real source text is
 	    // loaded.
-	    if (this.props.sourceText && (0, _editor.isTextForSource)(this.props.sourceText)) {
+	    if (selectedSource && selectedSource.has("text")) {
 	      this.highlightLine();
 	    }
 	  }
 
 	  onToggleBreakpoint(key, e) {
 	    e.preventDefault();
 	    var codeMirror = this.editor.codeMirror;
 
@@ -24938,19 +25050,19 @@ return /******/ (function(modules) { // 
 	    var _getTokenLocation = (0, _editor.getTokenLocation)(this.editor.codeMirror, target),
 	        line = _getTokenLocation.line,
 	        column = _getTokenLocation.column;
 
 	    this.toggleBreakpoint(line - 1, column - 1);
 	  }
 
 	  onSearchAgain(_, e) {
-	    var _props2 = this.props,
-	        query = _props2.query,
-	        searchModifiers = _props2.searchModifiers;
+	    var _props3 = this.props,
+	        query = _props3.query,
+	        searchModifiers = _props3.searchModifiers;
 	    var codeMirror = this.editor.editor.codeMirror;
 
 	    var ctx = { ed: this.editor, cm: codeMirror };
 
 	    var direction = e.shiftKey ? "prev" : "next";
 	    (0, _editor.traverseResults)(e, ctx, query, direction, searchModifiers.toJS());
 	  }
 
@@ -24958,67 +25070,59 @@ return /******/ (function(modules) { // 
 	    this.props.clearSelection();
 	    return this.setState({ selectedToken: null });
 	  }
 
 	  previewSelectedToken(e) {
 	    var _this = this;
 
 	    return _asyncToGenerator(function* () {
-	      var _props3 = _this.props,
-	          selectedFrame = _props3.selectedFrame,
-	          selectedSource = _props3.selectedSource,
-	          sourceText = _props3.sourceText,
-	          setSelection = _props3.setSelection,
-	          selection = _props3.selection;
+	      var _props4 = _this.props,
+	          selectedFrame = _props4.selectedFrame,
+	          selectedSource = _props4.selectedSource,
+	          sourceText = _props4.sourceText,
+	          setSelection = _props4.setSelection,
+	          selection = _props4.selection;
 
 	      var token = e.target;
 	      var tokenText = token.innerText.trim();
 
 	      if (selection && selection.updating || !selectedFrame || !sourceText || !selectedSource || tokenText === "" || tokenText.match(/\s/) || selectedFrame.location.sourceId !== selectedSource.get("id")) {
 	        return;
 	      }
 
 	      var location = (0, _editor.getTokenLocation)(_this.editor.codeMirror, token);
 	      setSelection(tokenText, location);
 	      _this.setState({ selectedToken: token });
 	    })();
 	  }
 
 	  openMenu(event, codeMirror) {
-	    var _props4 = this.props,
-	        selectedSource = _props4.selectedSource,
-	        selectedLocation = _props4.selectedLocation,
-	        showSource = _props4.showSource,
-	        jumpToMappedLocation = _props4.jumpToMappedLocation,
-	        addExpression = _props4.addExpression,
-	        toggleBlackBox = _props4.toggleBlackBox;
+	    var _props5 = this.props,
+	        selectedSource = _props5.selectedSource,
+	        selectedLocation = _props5.selectedLocation,
+	        showSource = _props5.showSource,
+	        jumpToMappedLocation = _props5.jumpToMappedLocation,
+	        addExpression = _props5.addExpression,
+	        toggleBlackBox = _props5.toggleBlackBox;
 
 
 	    return (0, _EditorMenu2.default)({
 	      codeMirror,
 	      event,
 	      selectedLocation,
 	      selectedSource,
 	      showSource,
 	      jumpToMappedLocation,
 	      addExpression,
 	      toggleBlackBox,
 	      onGutterContextMenu: this.onGutterContextMenu
 	    });
 	  }
 
-	  updateSearchResults(_ref) {
-	    var count = _ref.count,
-	        _ref$index = _ref.index,
-	        index = _ref$index === undefined ? -1 : _ref$index;
-
-	    this.setState({ searchResults: { count, index } });
-	  }
-
 	  onGutterClick(cm, line, gutter, ev) {
 	    var selectedSource = this.props.selectedSource;
 
 	    // ignore right clicks in the gutter
 
 	    if (ev.which === 3 || selectedSource && selectedSource.get("isBlackBoxed")) {
 	      return;
 	    }
@@ -25055,20 +25159,20 @@ return /******/ (function(modules) { // 
 	    });
 	  }
 
 	  toggleConditionalPanel(line) {
 	    if (this.isCbPanelOpen()) {
 	      return this.closeConditionalPanel();
 	    }
 
-	    var _props5 = this.props,
-	        selectedLocation = _props5.selectedLocation,
-	        setBreakpointCondition = _props5.setBreakpointCondition,
-	        breakpoints = _props5.breakpoints;
+	    var _props6 = this.props,
+	        selectedLocation = _props6.selectedLocation,
+	        setBreakpointCondition = _props6.setBreakpointCondition,
+	        breakpoints = _props6.breakpoints;
 
 	    var sourceId = selectedLocation ? selectedLocation.sourceId : "";
 
 	    var bp = (0, _editor.breakpointAtLocation)(breakpoints, { line });
 	    var location = { sourceId, line: line + 1 };
 	    var condition = bp ? bp.condition : "";
 
 	    var setBreakpoint = value => setBreakpointCondition(location, {
@@ -25095,37 +25199,39 @@ return /******/ (function(modules) { // 
 	  }
 
 	  isCbPanelOpen() {
 	    return !!this.cbPanel;
 	  }
 
 	  toggleBreakpoint(line) {
 	    var column = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
-	    var _props6 = this.props,
-	        selectedSource = _props6.selectedSource,
-	        selectedLocation = _props6.selectedLocation,
-	        breakpoints = _props6.breakpoints,
-	        addBreakpoint = _props6.addBreakpoint,
-	        removeBreakpoint = _props6.removeBreakpoint;
+	    var _props7 = this.props,
+	        selectedSource = _props7.selectedSource,
+	        selectedLocation = _props7.selectedLocation,
+	        breakpoints = _props7.breakpoints,
+	        addBreakpoint = _props7.addBreakpoint,
+	        removeBreakpoint = _props7.removeBreakpoint;
 
 	    var bp = (0, _editor.breakpointAtLocation)(breakpoints, { line, column });
 
 	    if (bp && bp.loading || !selectedLocation || !selectedSource) {
 	      return;
 	    }
 
 	    var sourceId = selectedLocation.sourceId;
 
 
 	    if (bp) {
+	      // NOTE: it's possible the breakpoint has slid to a column
+	      column = column || bp.location.column;
 	      removeBreakpoint({
 	        sourceId: sourceId,
 	        line: line + 1,
-	        column: column
+	        column
 	      });
 	    } else {
 	      addBreakpoint({
 	        sourceId: sourceId,
 	        sourceUrl: selectedSource.get("url"),
 	        line: line + 1,
 	        column: column
 	      },
@@ -25257,20 +25363,20 @@ return /******/ (function(modules) { // 
 
 	    return HighlightLines({
 	      editor: this.editor,
 	      highlightedLineRange
 	    });
 	  }
 
 	  renderBreakpoints() {
-	    var _props7 = this.props,
-	        breakpoints = _props7.breakpoints,
-	        sourceText = _props7.sourceText,
-	        selectedSource = _props7.selectedSource;
+	    var _props8 = this.props,
+	        breakpoints = _props8.breakpoints,
+	        sourceText = _props8.sourceText,
+	        selectedSource = _props8.selectedSource;
 
 	    var isLoading = sourceText && sourceText.get("loading");
 
 	    if (isLoading || !breakpoints || selectedSource && selectedSource.get("isBlackBoxed")) {
 	      return;
 	    }
 
 	    var breakpointMarkers = breakpoints.valueSeq().filter(b => (0, _devtoolsConfig.isEnabled)("columnBreakpoints") ? !b.location.column : true).map(bp => Breakpoint({
@@ -25284,38 +25390,38 @@ return /******/ (function(modules) { // 
 	      breakpoint: bp,
 	      editor: this.editor && this.editor.codeMirror
 	    }));
 
 	    return breakpointMarkers.concat(columnBreakpointBookmarks);
 	  }
 
 	  renderHitCounts() {
-	    var _props8 = this.props,
-	        hitCount = _props8.hitCount,
-	        sourceText = _props8.sourceText;
+	    var _props9 = this.props,
+	        hitCount = _props9.hitCount,
+	        sourceText = _props9.sourceText;
 
 	    var isLoading = sourceText && sourceText.get("loading");
 
 	    if (isLoading || !hitCount || !this.editor) {
 	      return;
 	    }
 
 	    return hitCount.filter(marker => marker.get("count") > 0).map(marker => HitMarker({
 	      key: marker.get("line"),
 	      hitData: marker.toJS(),
 	      editor: this.editor.codeMirror
 	    }));
 	  }
 
 	  getInlineEditorStyles() {
-	    var _props9 = this.props,
-	        selectedSource = _props9.selectedSource,
-	        horizontal = _props9.horizontal,
-	        searchOn = _props9.searchOn;
+	    var _props10 = this.props,
+	        selectedSource = _props10.selectedSource,
+	        horizontal = _props10.horizontal,
+	        searchOn = _props10.searchOn;
 
 
 	    var subtractions = [];
 
 	    if ((0, _editor.shouldShowFooter)(selectedSource, horizontal)) {
 	      subtractions.push(cssVars.footerHeight);
 	    }
 
@@ -25326,19 +25432,19 @@ return /******/ (function(modules) { // 
 
 	    return {
 	      height: subtractions.length === 0 ? "100%" : `calc(100% - ${subtractions.join(" - ")})`
 	    };
 	  }
 
 	  renderPreview() {
 	    var selectedToken = this.state.selectedToken;
-	    var _props10 = this.props,
-	        sourceText = _props10.sourceText,
-	        selection = _props10.selection;
+	    var _props11 = this.props,
+	        sourceText = _props11.sourceText,
+	        selection = _props11.selection;
 
 
 	    if (!this.editor || !sourceText) {
 	      return null;
 	    }
 
 	    if (!selection || !selectedToken) {
 	      return;
@@ -25356,19 +25462,19 @@ return /******/ (function(modules) { // 
 	      value,
 	      expression: expression,
 	      popoverTarget: selectedToken,
 	      onClose: () => this.clearPreviewSelection()
 	    });
 	  }
 
 	  inSelectedFrameSource() {
-	    var _props11 = this.props,
-	        selectedLocation = _props11.selectedLocation,
-	        selectedFrame = _props11.selectedFrame;
+	    var _props12 = this.props,
+	        selectedLocation = _props12.selectedLocation,
+	        selectedFrame = _props12.selectedFrame;
 
 	    return selectedFrame && selectedLocation && selectedFrame.location.sourceId == selectedLocation.sourceId;
 	  }
 
 	  renderOutOfScopedLocations() {
 	    var outOfScopeLocations = this.props.outOfScopeLocations;
 
 
@@ -25377,38 +25483,35 @@ return /******/ (function(modules) { // 
 	    }
 
 	    (0, _flatMap2.default)(outOfScopeLocations, location => (0, _range2.default)(location.start.line, location.end.line)).forEach(line => {
 	      this.editor.codeMirror.addLineClass(line - 1, "line", "out-of-scope");
 	    });
 	  }
 
 	  render() {
-	    var _props12 = this.props,
-	        sourceText = _props12.sourceText,
-	        selectSource = _props12.selectSource,
-	        selectedSource = _props12.selectedSource,
-	        highlightLineRange = _props12.highlightLineRange,
-	        clearHighlightLineRange = _props12.clearHighlightLineRange,
-	        coverageOn = _props12.coverageOn,
-	        horizontal = _props12.horizontal;
-	    var searchResults = this.state.searchResults;
+	    var _props13 = this.props,
+	        sourceText = _props13.sourceText,
+	        selectSource = _props13.selectSource,
+	        selectedSource = _props13.selectedSource,
+	        highlightLineRange = _props13.highlightLineRange,
+	        clearHighlightLineRange = _props13.clearHighlightLineRange,
+	        coverageOn = _props13.coverageOn,
+	        horizontal = _props13.horizontal;
 
 
 	    return _react.DOM.div({
 	      className: (0, _classnames2.default)("editor-wrapper", { "coverage-on": coverageOn })
 	    }, SearchBar({
 	      editor: this.editor,
 	      selectSource,
 	      selectedSource,
 	      highlightLineRange,
 	      clearHighlightLineRange,
-	      sourceText,
-	      searchResults,
-	      updateSearchResults: this.updateSearchResults
+	      sourceText
 	    }), _react.DOM.div({
 	      className: "editor-mount devtools-monospace",
 	      style: this.getInlineEditorStyles()
 	    }), this.renderOutOfScopedLocations(), this.renderHighlightLines(), this.renderBreakpoints(), this.renderHitCounts(), Footer({ editor: this.editor, horizontal }), this.renderPreview());
 	  }
 	}
 
 	Editor.displayName = "Editor";
@@ -25762,16 +25865,18 @@ return /******/ (function(modules) { // 
 	var _actions = __webpack_require__(244);
 
 	var _actions2 = _interopRequireDefault(_actions);
 
 	var _selectors = __webpack_require__(242);
 
 	var _editor = __webpack_require__(257);
 
+	var _search = __webpack_require__(1115);
+
 	var _resultList = __webpack_require__(343);
 
 	var _classnames = __webpack_require__(175);
 
 	var _classnames2 = _interopRequireDefault(_classnames);
 
 	var _debounce = __webpack_require__(651);
 
@@ -25786,16 +25891,18 @@ return /******/ (function(modules) { // 
 	var _ResultList2 = __webpack_require__(383);
 
 	var _ResultList3 = _interopRequireDefault(_ResultList2);
 
 	__webpack_require__(653);
 
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
+	function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(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 Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
+
 	var SearchInput = (0, _react.createFactory)(_SearchInput3.default);
 
 	var ResultList = (0, _react.createFactory)(_ResultList3.default);
 
 	function formatSymbol(symbol) {
 	  return {
 	    id: `${symbol.name}:${symbol.location.start.line}`,
 	    title: symbol.name,
@@ -25819,17 +25926,16 @@ return /******/ (function(modules) { // 
 	  };
 	}
 
 	class SearchBar extends _react.Component {
 
 	  constructor(props) {
 	    super(props);
 	    this.state = {
-	      symbolSearchResults: [],
 	      selectedResultIndex: 0,
 	      count: 0,
 	      index: -1
 	    };
 
 	    var self = this;
 	    self.onEscape = this.onEscape.bind(this);
 	    self.clearSearch = this.clearSearch.bind(this);
@@ -25947,20 +26053,23 @@ return /******/ (function(modules) { // 
 
 	    if (ed && modifiers) {
 	      var ctx = { ed, cm: ed.codeMirror };
 	      (0, _editor.removeOverlay)(ctx, query, modifiers.toJS());
 	    }
 	  }
 
 	  closeSearch(e) {
-	    var editor = this.props.editor;
+	    var _props3 = this.props,
+	        editor = _props3.editor,
+	        setFileSearchQuery = _props3.setFileSearchQuery;
 
 
 	    if (this.props.searchOn && editor) {
+	      setFileSearchQuery("");
 	      this.clearSearch();
 	      this.props.toggleFileSearch(false);
 	      this.props.toggleSymbolSearch(false);
 	      this.props.setSelectedSymbolType("functions");
 	      this.props.clearHighlightLineRange();
 	      e.stopPropagation();
 	      e.preventDefault();
 	    }
@@ -26052,87 +26161,90 @@ return /******/ (function(modules) { // 
 	      if (input instanceof HTMLInputElement) {
 	        return input;
 	      }
 	    }
 	    return null;
 	  }
 
 	  updateSymbolSearchResults(query) {
-	    var _props3 = this.props,
-	        selectedSource = _props3.selectedSource,
-	        updateSearchResults = _props3.updateSearchResults,
-	        selectedSymbolType = _props3.selectedSymbolType,
-	        symbols = _props3.symbols;
+	    var _props4 = this.props,
+	        selectedSource = _props4.selectedSource,
+	        updateSearchResults = _props4.updateSearchResults,
+	        updateSymbolSearchResults = _props4.updateSymbolSearchResults,
+	        selectedSymbolType = _props4.selectedSymbolType,
+	        symbols = _props4.symbols;
 
 
 	    if (query == "" || !selectedSource) {
 	      return;
 	    }
 
 	    var symbolSearchResults = (0, _fuzzaldrinPlus.filter)(symbols[selectedSymbolType], query, {
 	      key: "value"
 	    });
 
 	    updateSearchResults({ count: symbolSearchResults.length });
-	    return this.setState({ symbolSearchResults });
+	    updateSymbolSearchResults(symbolSearchResults);
 	  }
 
 	  doSearch(query) {
-	    var _props4 = this.props,
-	        selectedSource = _props4.selectedSource,
-	        setFileSearchQuery = _props4.setFileSearchQuery,
-	        ed = _props4.editor;
+	    var _props5 = this.props,
+	        selectedSource = _props5.selectedSource,
+	        setFileSearchQuery = _props5.setFileSearchQuery,
+	        ed = _props5.editor;
 
 	    if (!selectedSource || !selectedSource.get("text")) {
 	      return;
 	    }
 
 	    setFileSearchQuery(query);
 
 	    if (this.props.symbolSearchOn) {
 	      return this.updateSymbolSearchResults(query);
 	    } else if (ed) {
 	      this.searchContents(query);
 	    }
 	  }
 
 	  searchContents(query) {
-	    var _props5 = this.props,
-	        selectedSource = _props5.selectedSource,
-	        modifiers = _props5.modifiers,
-	        ed = _props5.editor,
-	        index = _props5.searchResults.index;
-
-
-	    if (!ed || !selectedSource || !selectedSource.get("text") || !modifiers) {
-	      return;
-	    }
-
-	    var ctx = { ed, cm: ed.codeMirror };
-
-	    var newCount = (0, _editor.countMatches)(query, selectedSource.get("text"), modifiers.toJS());
-
-	    if (index == -1) {
-	      (0, _editor.clearIndex)(ctx, query, modifiers.toJS());
-	    }
-
-	    var newIndex = (0, _editor.find)(ctx, query, true, modifiers.toJS());
-	    this.props.updateSearchResults({
-	      count: newCount,
-	      index: newIndex
-	    });
+	    var _this = this;
+
+	    return _asyncToGenerator(function* () {
+	      var _props6 = _this.props,
+	          selectedSource = _props6.selectedSource,
+	          modifiers = _props6.modifiers,
+	          ed = _props6.editor,
+	          index = _props6.searchResults.index;
+
+
+	      if (!ed || !selectedSource || !selectedSource.get("text") || !modifiers) {
+	        return;
+	      }
+
+	      var ctx = { ed, cm: ed.codeMirror };
+
+	      var newCount = yield (0, _search.countMatches)(query, selectedSource.get("text"), modifiers.toJS());
+
+	      if (index == -1) {
+	        (0, _editor.clearIndex)(ctx, query, modifiers.toJS());
+	      }
+
+	      var newIndex = (0, _editor.find)(ctx, query, true, modifiers.toJS());
+	      _this.props.updateSearchResults({
+	        count: newCount,
+	        index: newIndex
+	      });
+	    })();
 	  }
 
 	  traverseSymbolResults(rev) {
-	    var _state = this.state,
-	        symbolSearchResults = _state.symbolSearchResults,
-	        selectedResultIndex = _state.selectedResultIndex;
-
-	    var searchResults = symbolSearchResults;
+	    var selectedResultIndex = this.state.selectedResultIndex;
+
+	    var searchResults = this.props.symbolSearchResults;
 	    var resultCount = searchResults.length;
 
 	    if (rev) {
 	      var nextResultIndex = Math.max(0, selectedResultIndex - 1);
 
 	      if (selectedResultIndex === 0) {
 	        nextResultIndex = resultCount - 1;
 	      }
@@ -26153,23 +26265,23 @@ return /******/ (function(modules) { // 
 	    var ed = this.props.editor;
 
 	    if (!ed) {
 	      return;
 	    }
 
 	    var ctx = { ed, cm: ed.codeMirror };
 
-	    var _props6 = this.props,
-	        query = _props6.query,
-	        modifiers = _props6.modifiers,
-	        updateSearchResults = _props6.updateSearchResults,
-	        _props6$searchResults = _props6.searchResults,
-	        count = _props6$searchResults.count,
-	        index = _props6$searchResults.index;
+	    var _props7 = this.props,
+	        query = _props7.query,
+	        modifiers = _props7.modifiers,
+	        updateSearchResults = _props7.updateSearchResults,
+	        _props7$searchResults = _props7.searchResults,
+	        count = _props7$searchResults.count,
+	        index = _props7$searchResults.index;
 
 
 	    if (query === "") {
 	      this.props.toggleFileSearch(true);
 	    }
 
 	    if (index == -1 && modifiers) {
 	      (0, _editor.clearIndex)(ctx, query, modifiers.toJS());
@@ -26196,36 +26308,36 @@ return /******/ (function(modules) { // 
 	      return this.traverseSymbolResults(rev);
 	    }
 
 	    this.traverseCodeResults(rev);
 	  }
 
 	  // Handlers
 	  selectResultItem(e, item) {
-	    var _props7 = this.props,
-	        selectSource = _props7.selectSource,
-	        selectedSource = _props7.selectedSource;
+	    var _props8 = this.props,
+	        selectSource = _props8.selectSource,
+	        selectedSource = _props8.selectedSource;
 
 
 	    if (selectedSource) {
 	      selectSource(selectedSource.get("id"), {
 	        line: item.location.start.line
 	      });
 
 	      this.closeSearch(e);
 	    }
 	  }
 
 	  onSelectResultItem(item) {
-	    var _props8 = this.props,
-	        selectSource = _props8.selectSource,
-	        selectedSource = _props8.selectedSource,
-	        selectedSymbolType = _props8.selectedSymbolType,
-	        highlightLineRange = _props8.highlightLineRange;
+	    var _props9 = this.props,
+	        selectSource = _props9.selectSource,
+	        selectedSource = _props9.selectedSource,
+	        selectedSymbolType = _props9.selectedSymbolType,
+	        highlightLineRange = _props9.highlightLineRange;
 
 
 	    if (selectedSource && selectedSymbolType !== "functions") {
 	      selectSource(selectedSource.get("id"), {
 	        line: item.location.start.line
 	      });
 	    }
 
@@ -26247,18 +26359,19 @@ return /******/ (function(modules) { // 
 	      return;
 	    }
 
 	    this.traverseResults(e, e.shiftKey);
 	    e.preventDefault();
 	  }
 
 	  onKeyDown(e) {
-	    var symbolSearchOn = this.props.symbolSearchOn;
-	    var symbolSearchResults = this.state.symbolSearchResults;
+	    var _props10 = this.props,
+	        symbolSearchOn = _props10.symbolSearchOn,
+	        symbolSearchResults = _props10.symbolSearchResults;
 
 	    if (!symbolSearchOn || this.props.query == "") {
 	      return;
 	    }
 
 	    var searchResults = symbolSearchResults;
 
 	    if (e.key === "ArrowUp") {
@@ -26276,29 +26389,33 @@ return /******/ (function(modules) { // 
 	    } else if (e.key === "Tab") {
 	      this.closeSearch(e);
 	      e.preventDefault();
 	    }
 	  }
 
 	  // Renderers
 	  buildSummaryMsg() {
-	    if (this.props.symbolSearchOn) {
-	      if (this.state.symbolSearchResults.length > 1) {
-	        return L10N.getFormatStr("editor.searchResults", this.state.selectedResultIndex + 1, this.state.symbolSearchResults.length);
-	      } else if (this.state.symbolSearchResults.length === 1) {
+	    var _props11 = this.props,
+	        symbolSearchOn = _props11.symbolSearchOn,
+	        symbolSearchResults = _props11.symbolSearchResults;
+
+	    if (symbolSearchOn) {
+	      if (symbolSearchResults.length > 1) {
+	        return L10N.getFormatStr("editor.searchResults", this.state.selectedResultIndex + 1, symbolSearchResults.length);
+	      } else if (symbolSearchResults.length === 1) {
 	        return L10N.getFormatStr("editor.singleResult");
 	      }
 	    }
 
-	    var _props9 = this.props,
-	        _props9$searchResults = _props9.searchResults,
-	        count = _props9$searchResults.count,
-	        index = _props9$searchResults.index,
-	        query = _props9.query;
+	    var _props12 = this.props,
+	        _props12$searchResult = _props12.searchResults,
+	        count = _props12$searchResult.count,
+	        index = _props12$searchResult.index,
+	        query = _props12.query;
 
 
 	    if (query.trim() == "") {
 	      return "";
 	    }
 
 	    if (count == 0) {
 	      return L10N.getStr("editor.noResults");
@@ -26307,33 +26424,33 @@ return /******/ (function(modules) { // 
 	    if (index == -1) {
 	      return L10N.getFormatStr("sourceSearch.resultsSummary1", count);
 	    }
 
 	    return L10N.getFormatStr("editor.searchResults", index + 1, count);
 	  }
 
 	  buildPlaceHolder() {
-	    var _props10 = this.props,
-	        symbolSearchOn = _props10.symbolSearchOn,
-	        selectedSymbolType = _props10.selectedSymbolType;
+	    var _props13 = this.props,
+	        symbolSearchOn = _props13.symbolSearchOn,
+	        selectedSymbolType = _props13.selectedSymbolType;
 
 	    if (symbolSearchOn) {
 	      // prettier-ignore
 	      return L10N.getFormatStr(`symbolSearch.search.${selectedSymbolType}Placeholder`);
 	    }
 
 	    return L10N.getStr("sourceSearch.search.placeholder");
 	  }
 
 	  renderSearchModifiers() {
-	    var _props11 = this.props,
-	        modifiers = _props11.modifiers,
-	        toggleFileSearchModifier = _props11.toggleFileSearchModifier,
-	        symbolSearchOn = _props11.symbolSearchOn;
+	    var _props14 = this.props,
+	        modifiers = _props14.modifiers,
+	        toggleFileSearchModifier = _props14.toggleFileSearchModifier,
+	        symbolSearchOn = _props14.symbolSearchOn;
 
 
 	    if (symbolSearchOn) {
 	      return null;
 	    }
 
 	    function searchModBtn(modVal, className, svgName, tooltip) {
 	      return _react.DOM.button({
@@ -26345,19 +26462,19 @@ return /******/ (function(modules) { // 
 	      }, (0, _Svg2.default)(svgName));
 	    }
 
 	    return _react.DOM.div({ className: "search-modifiers" }, searchModBtn("regexMatch", "regex-match-btn", "regex-match", L10N.getStr("symbolSearch.searchModifier.regex")), searchModBtn("caseSensitive", "case-sensitive-btn", "case-match", L10N.getStr("symbolSearch.searchModifier.caseSensitive")), searchModBtn("wholeWord", "whole-word-btn", "whole-word-match", L10N.getStr("symbolSearch.searchModifier.wholeWord")));
 	  }
 
 	  renderSearchTypeToggle() {
 	    var toggleSymbolSearch = this.toggleSymbolSearch;
-	    var _props12 = this.props,
-	        symbolSearchOn = _props12.symbolSearchOn,
-	        selectedSymbolType = _props12.selectedSymbolType;
+	    var _props15 = this.props,
+	        symbolSearchOn = _props15.symbolSearchOn,
+	        selectedSymbolType = _props15.selectedSymbolType;
 
 
 	    function searchTypeBtn(searchType) {
 	      return _react.DOM.button({
 	        className: (0, _classnames2.default)("search-type-btn", {
 	          active: symbolSearchOn && selectedSymbolType == searchType
 	        }),
 	        onClick: e => {
@@ -26373,40 +26490,39 @@ return /******/ (function(modules) { // 
 	    return _react.DOM.section({ className: "search-type-toggles" }, _react.DOM.h1({ className: "search-toggle-title" }, L10N.getStr("editor.searchTypeToggleTitle")), searchTypeBtn("functions"), searchTypeBtn("variables"));
 	  }
 
 	  renderBottomBar() {
 	    return _react.DOM.div({ className: "search-bottom-bar" }, this.renderSearchTypeToggle(), this.renderSearchModifiers());
 	  }
 
 	  renderResults() {
-	    var _state2 = this.state,
-	        symbolSearchResults = _state2.symbolSearchResults,
-	        selectedResultIndex = _state2.selectedResultIndex;
-	    var _props13 = this.props,
-	        query = _props13.query,
-	        symbolSearchOn = _props13.symbolSearchOn;
+	    var selectedResultIndex = this.state.selectedResultIndex;
+	    var _props16 = this.props,
+	        query = _props16.query,
+	        symbolSearchResults = _props16.symbolSearchResults,
+	        symbolSearchOn = _props16.symbolSearchOn;
 
 	    if (query == "" || !symbolSearchOn || !symbolSearchResults.length) {
 	      return;
 	    }
 
 	    return ResultList({
 	      items: symbolSearchResults,
 	      selected: selectedResultIndex,
 	      selectItem: this.selectResultItem,
 	      ref: "resultList"
 	    });
 	  }
 
 	  render() {
-	    var _props14 = this.props,
-	        count = _props14.searchResults.count,
-	        query = _props14.query,
-	        searchOn = _props14.searchOn;
+	    var _props17 = this.props,
+	        count = _props17.searchResults.count,
+	        query = _props17.query,
+	        searchOn = _props17.searchOn;
 
 
 	    if (!searchOn) {
 	      return _react.DOM.div();
 	    }
 
 	    return _react.DOM.div({ className: "search-bar" }, SearchInput({
 	      query,
@@ -26445,16 +26561,18 @@ return /******/ (function(modules) { // 
 	}
 
 	exports.default = (0, _reactRedux.connect)(state => {
 	  return {
 	    searchOn: (0, _selectors.getFileSearchState)(state),
 	    query: (0, _selectors.getFileSearchQueryState)(state),
 	    modifiers: (0, _selectors.getFileSearchModifierState)(state),
 	    symbolSearchOn: (0, _selectors.getSymbolSearchState)(state),
+	    symbolSearchResults: (0, _selectors.getSymbolSearchResults)(state),
+	    searchResults: (0, _selectors.getSearchResults)(state),
 	    symbols: _getFormattedSymbols(state),
 	    selectedSymbolType: (0, _selectors.getSymbolSearchType)(state)
 	  };
 	}, dispatch => (0, _redux.bindActionCreators)(_actions2.default, dispatch))(SearchBar);
 
 /***/ },
 /* 434 */,
 /* 435 */,
@@ -28693,20 +28811,16 @@ return /******/ (function(modules) { // 
 	var _devtoolsConfig = __webpack_require__(828);
 
 	var _Svg = __webpack_require__(344);
 
 	var _Svg2 = _interopRequireDefault(_Svg);
 
 	var _prefs = __webpack_require__(226);
 
-	var _WhyPaused2 = __webpack_require__(722);
-
-	var _WhyPaused3 = _interopRequireDefault(_WhyPaused2);
-
 	var _Breakpoints2 = __webpack_require__(725);
 
 	var _Breakpoints3 = _interopRequireDefault(_Breakpoints2);
 
 	var _Expressions2 = __webpack_require__(719);
 
 	var _Expressions3 = _interopRequireDefault(_Expressions2);
 
@@ -28739,18 +28853,16 @@ return /******/ (function(modules) { // 
 	var _Scopes3 = _interopRequireDefault(_Scopes2);
 
 	__webpack_require__(745);
 
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 	function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
 
-	var WhyPaused = (0, _react.createFactory)(_WhyPaused3.default);
-
 	var Breakpoints = (0, _react.createFactory)(_Breakpoints3.default);
 
 	var Expressions = (0, _react.createFactory)(_Expressions3.default);
 
 	var SplitBox = (0, _react.createFactory)(_devtoolsSplitter2.default);
 
 	var Frames = (0, _react.createFactory)(_Frames3.default);
 
@@ -28896,17 +29008,17 @@ return /******/ (function(modules) { // 
 	      endPanel: Accordion({ items: this.getEndItems() })
 	    });
 	  }
 
 	  render() {
 	    return _react.DOM.div({
 	      className: "secondary-panes",
 	      style: { overflowX: "hidden" }
-	    }, CommandBar(), WhyPaused(), this.props.horizontal ? this.renderHorizontalLayout() : this.renderVerticalLayout());
+	    }, CommandBar(), this.props.horizontal ? this.renderHorizontalLayout() : this.renderVerticalLayout());
 	  }
 	}
 
 	SecondaryPanes.propTypes = {
 	  evaluateExpressions: _react.PropTypes.func.isRequired,
 	  pauseData: _react.PropTypes.object,
 	  horizontal: _react.PropTypes.bool,
 	  breakpoints: _reactImmutableProptypes2.default.map.isRequired,
@@ -29173,109 +29285,18 @@ return /******/ (function(modules) { // 
 /***/ },
 /* 720 */
 /***/ function(module, exports) {
 
 	// removed by extract-text-webpack-plugin
 
 /***/ },
 /* 721 */,
-/* 722 */
-/***/ function(module, exports, __webpack_require__) {
-
-	"use strict";
-
-	Object.defineProperty(exports, "__esModule", {
-	  value: true
-	});
-
-	var _react = __webpack_require__(2);
-
-	var _redux = __webpack_require__(3);
-
-	var _reactRedux = __webpack_require__(151);
-
-	var _actions = __webpack_require__(244);
-
-	var _actions2 = _interopRequireDefault(_actions);
-
-	var _selectors = __webpack_require__(242);
-
-	var _isString = __webpack_require__(602);
-
-	var _isString2 = _interopRequireDefault(_isString);
-
-	var _pause = __webpack_require__(255);
-
-	__webpack_require__(723);
-
-	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-	var get = __webpack_require__(67);
-
-	function renderExceptionSummary(exception) {
-	  if ((0, _isString2.default)(exception)) {
-	    return exception;
-	  }
-
-	  var message = get(exception, "preview.message");
-	  var name = get(exception, "preview.name");
-
-	  return `${name}: ${message}`;
-	}
-
-	class WhyPaused extends _react.Component {
-	  renderMessage(pauseInfo) {
-	    if (!pauseInfo) {
-	      return null;
-	    }
-
-	    var message = get(pauseInfo, "why.message");
-	    if (message) {
-	      return _react.DOM.div({ className: "message" }, message);
-	    }
-
-	    var exception = get(pauseInfo, "why.exception");
-	    if (exception) {
-	      return _react.DOM.div({ className: "message" }, renderExceptionSummary(exception));
-	    }
-
-	    return null;
-	  }
-
-	  render() {
-	    var pauseInfo = this.props.pauseInfo;
-
-	    var reason = (0, _pause.getPauseReason)(pauseInfo);
-
-	    if (!reason) {
-	      return null;
-	    }
-
-	    return _react.DOM.div({ className: "pane why-paused" }, _react.DOM.div(null, L10N.getStr(reason)), this.renderMessage(pauseInfo));
-	  }
-	}
-
-	WhyPaused.displayName = "WhyPaused";
-
-	WhyPaused.propTypes = {
-	  pauseInfo: _react.PropTypes.object
-	};
-
-	exports.default = (0, _reactRedux.connect)(state => ({
-	  pauseInfo: (0, _selectors.getPause)(state)
-	}), dispatch => (0, _redux.bindActionCreators)(_actions2.default, dispatch))(WhyPaused);
-
-/***/ },
-/* 723 */
-/***/ function(module, exports) {
-
-	// removed by extract-text-webpack-plugin
-
-/***/ },
+/* 722 */,
+/* 723 */,
 /* 724 */,
 /* 725 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
@@ -29310,28 +29331,29 @@ return /******/ (function(modules) { // 
 	var _path = __webpack_require__(235);
 
 	var _Close = __webpack_require__(378);
 
 	var _Close2 = _interopRequireDefault(_Close);
 
 	__webpack_require__(726);
 
+	var _get = __webpack_require__(67);
+
+	var _get2 = _interopRequireDefault(_get);
+
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
-	var get = __webpack_require__(67);
-
-
 	function isCurrentlyPausedAtBreakpoint(pause, breakpoint) {
 	  if (!pause || pause.isInterrupted) {
 	    return false;
 	  }
 
 	  var bpId = (0, _breakpoint.makeLocationId)(breakpoint.location);
-	  var pausedId = (0, _breakpoint.makeLocationId)(get(pause, "frame.location"));
+	  var pausedId = (0, _breakpoint.makeLocationId)((0, _get2.default)(pause, "frame.location"));
 	  return bpId === pausedId;
 	}
 
 	function renderSourceLocation(source, line, column) {
 	  var url = source.get("url") ? (0, _path.basename)(source.get("url")) : null;
 	  var bpLocation = line + (column ? `:${column}` : "");
 	  // const line = url !== "" ? `: ${line}` : "";
 	  return url ? _react.DOM.div({ className: "location" }, `${(0, _utils.endTruncateStr)(url, 30)}: ${bpLocation}`) : null;
@@ -29718,40 +29740,41 @@ return /******/ (function(modules) { // 
 	function info(text) {
 	  return _react.DOM.div({ className: "pane-info" }, text);
 	}
 
 	class Scopes extends _react.PureComponent {
 
 	  constructor(props) {
 	    var pauseInfo = props.pauseInfo,
-	        selectedFrame = props.selectedFrame;
+	        selectedFrame = props.selectedFrame,
+	        frameScopes = props.frameScopes;
 
 	    for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
 	      args[_key - 1] = arguments[_key];
 	    }
 
 	    super(props, ...args);
 
 	    this.state = {
-	      scopes: (0, _scopes.getScopes)(pauseInfo, selectedFrame)
+	      scopes: (0, _scopes.getScopes)(pauseInfo, selectedFrame, frameScopes)
 	    };
 	  }
 
 	  componentWillReceiveProps(nextProps) {
 	    var _props = this.props,
 	        pauseInfo = _props.pauseInfo,
 	        selectedFrame = _props.selectedFrame;
 
 	    var pauseInfoChanged = pauseInfo !== nextProps.pauseInfo;
 	    var selectedFrameChange = selectedFrame !== nextProps.selectedFrame;
 
 	    if (pauseInfoChanged || selectedFrameChange) {
 	      this.setState({
-	        scopes: (0, _scopes.getScopes)(nextProps.pauseInfo, nextProps.selectedFrame)
+	        scopes: (0, _scopes.getScopes)(nextProps.pauseInfo, nextProps.selectedFrame, nextProps.frameScopes)
 	      });
 	    }
 	  }
 
 	  render() {
 	    var _props2 = this.props,
 	        pauseInfo = _props2.pauseInfo,
 	        loadObjectProperties = _props2.loadObjectProperties,
@@ -29771,67 +29794,72 @@ return /******/ (function(modules) { // 
 	    return _react.DOM.div({ className: "pane scopes-list" }, pauseInfo ? scopeInspector : info(L10N.getStr("scopes.notPaused")));
 	  }
 	}
 
 	Scopes.propTypes = {
 	  pauseInfo: _react.PropTypes.object,
 	  loadedObjects: _react.PropTypes.object,
 	  loadObjectProperties: _react.PropTypes.func,
-	  selectedFrame: _react.PropTypes.object
+	  selectedFrame: _react.PropTypes.object,
+	  frameScopes: _react.PropTypes.object
 	};
 
 	Scopes.displayName = "Scopes";
 
-	exports.default = (0, _reactRedux.connect)(state => ({
-	  pauseInfo: (0, _selectors.getPause)(state),
-	  selectedFrame: (0, _selectors.getSelectedFrame)(state),
-	  loadedObjects: (0, _selectors.getLoadedObjects)(state)
-	}), dispatch => (0, _redux.bindActionCreators)(_actions2.default, dispatch))(Scopes);
+	exports.default = (0, _reactRedux.connect)(state => {
+	  var selectedFrame = (0, _selectors.getSelectedFrame)(state);
+	  var frameScopes = selectedFrame ? (0, _selectors.getFrameScopes)(state, selectedFrame.id) : null;
+	  return {
+	    selectedFrame,
+	    pauseInfo: (0, _selectors.getPause)(state),
+	    frameScopes: frameScopes,
+	    loadedObjects: (0, _selectors.getLoadedObjects)(state)
+	  };
+	}, dispatch => (0, _redux.bindActionCreators)(_actions2.default, dispatch))(Scopes);
 
 /***/ },
 /* 732 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
 	exports.getSpecialVariables = getSpecialVariables;
 	exports.getScopes = getScopes;
-	exports.getVisibleVariablesFromScope = getVisibleVariablesFromScope;
 
 	var _toPairs = __webpack_require__(195);
 
 	var _toPairs2 = _interopRequireDefault(_toPairs);
 
+	var _get = __webpack_require__(67);
+
+	var _get2 = _interopRequireDefault(_get);
+
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
-	function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
-
-	var get = __webpack_require__(67);
-
 	// Create the tree nodes representing all the variables and arguments
 	// for the bindings from a scope.
 	function getBindingVariables(bindings, parentName) {
 	  var args = bindings.arguments.map(arg => (0, _toPairs2.default)(arg)[0]);
 	  var variables = (0, _toPairs2.default)(bindings.variables);
 
 	  return args.concat(variables).map(binding => ({
 	    name: binding[0],
 	    path: `${parentName}/${binding[0]}`,
 	    contents: binding[1]
 	  }));
 	}
 
 	function getSpecialVariables(pauseInfo, path) {
-	  var thrown = get(pauseInfo, "why.frameFinished.throw", undefined);
-
-	  var returned = get(pauseInfo, "why.frameFinished.return", undefined);
+	  var thrown = (0, _get2.default)(pauseInfo, "why.frameFinished.throw", undefined);
+
+	  var returned = (0, _get2.default)(pauseInfo, "why.frameFinished.return", undefined);
 
 	  var vars = [];
 
 	  if (thrown !== undefined) {
 	    vars.push({
 	      name: "<exception>",
 	      path: `${path}/<exception>`,
 	      contents: { value: thrown }
@@ -29861,31 +29889,33 @@ return /******/ (function(modules) { // 
 
 	  return {
 	    name: "<this>",
 	    path: `${path}/<this>`,
 	    contents: { value: this_ }
 	  };
 	}
 
-	function getScopes(pauseInfo, selectedFrame) {
+	function getScopes(pauseInfo, selectedFrame, selectedScope) {
 	  if (!pauseInfo || !selectedFrame) {
 	    return null;
 	  }
 
-	  var selectedScope = selectedFrame.scope;
+	  // NOTE: it's possible that we're inspecting an old server
+	  // that does not support getting frame scopes directly
+	  selectedScope = selectedScope || selectedFrame.scope;
 
 	  if (!selectedScope) {
 	    return null;
 	  }
 
 	  var scopes = [];
 
 	  var scope = selectedScope;
-	  var pausedScopeActor = get(pauseInfo, "frame.scope.actor");
+	  var pausedScopeActor = (0, _get2.default)(pauseInfo, "frame.scope.actor");
 	  var scopeIndex = 1;
 
 	  do {
 	    var _scope = scope,
 	        type = _scope.type,
 	        actor = _scope.actor;
 
 	    var key = `${actor}-${scopeIndex}`;
@@ -29935,41 +29965,16 @@ return /******/ (function(modules) { // 
 	      });
 	    }
 	    scopeIndex++;
 	  } while (scope = scope.parent); // eslint-disable-line no-cond-assign
 
 	  return scopes;
 	}
 
-	/**
-	 * Returns variables that are visible from this scope.
-	 * TODO: returns global variables as well
-	 */
-	function getVisibleVariablesFromScope(pauseInfo, selectedFrame) {
-	  var _ref;
-
-	  var result = new Map();
-
-	  var scopes = getScopes(pauseInfo, selectedFrame);
-	  if (!scopes) {
-	    return result;
-	  }
-
-	  // reverse so that the local variables shadow global variables
-	  var scopeContents = scopes.reverse().map(scope => scope.contents);
-	  scopeContents = (_ref = []).concat.apply(_ref, _toConsumableArray(scopeContents));
-
-	  scopeContents.forEach(content => {
-	    result.set(content.name || null, content);
-	  });
-
-	  return result;
-	}
-
 /***/ },
 /* 733 */,
 /* 734 */,
 /* 735 */,
 /* 736 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
@@ -30483,16 +30488,20 @@ return /******/ (function(modules) { // 
 
 /***/ },
 /* 749 */,
 /* 750 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	Object.defineProperty(exports, "__esModule", {
+	  value: true
+	});
+
 	var _react = __webpack_require__(2);
 
 	var _reactRedux = __webpack_require__(151);
 
 	var _redux = __webpack_require__(3);
 
 	var _immutable = __webpack_require__(146);
 
@@ -30557,22 +30566,26 @@ return /******/ (function(modules) { // 
 	 */
 	function getHiddenTabs(sourceTabs, sourceTabEls) {
 	  sourceTabEls = [].slice.call(sourceTabEls);
 	  function getTopOffset() {
 	    var topOffsets = sourceTabEls.map(t => t.getBoundingClientRect().top);
 	    return Math.min.apply(Math, _toConsumableArray(topOffsets));
 	  }
 
-	  var tabTopOffset = getTopOffset();
-	  return sourceTabs.filter((tab, index) => {
+	  function hasTopOffset(el) {
 	    // adding 10px helps account for cases where the tab might be offset by
 	    // styling such as selected tabs which don't have a border.
-	    var el = sourceTabEls[index];
-	    return el && el.getBoundingClientRect().top > tabTopOffset + 10;
+	    var tabTopOffset = getTopOffset();
+	    return el.getBoundingClientRect().top > tabTopOffset + 10;
+	  }
+
+	  return sourceTabs.filter((tab, index) => {
+	    var element = sourceTabEls[index];
+	    return element && hasTopOffset(element);
 	  });
 	}
 
 	/**
 	 * Clipboard function taken from
 	 * https://dxr.mozilla.org/mozilla-central/source/devtools/shared/platform/content/clipboard.js
 	 */
 	function copyToTheClipboard(string) {
@@ -30708,17 +30721,17 @@ return /******/ (function(modules) { // 
 	      id: "node-menu-show-source",
 	      label: revealInTreeLabel,
 	      accesskey: revealInTreeKey,
 	      disabled: false,
 	      click: () => showSource(tab)
 	    };
 
 	    var copySourceUrl = {
-	      id: "node-menu-close-tabs-to-right",
+	      id: "node-menu-copy-source-url",
 	      label: copyLinkLabel,
 	      accesskey: copyLinkKey,
 	      disabled: false,
 	      click: () => copyToTheClipboard(sourceTab.get("url"))
 	    };
 
 	    var prettyPrint = {
 	      id: "node-menu-pretty-print",
@@ -30747,45 +30760,45 @@ return /******/ (function(modules) { // 
 	   */
 	  updateHiddenSourceTabs() {
 	    if (!this.refs.sourceTabs) {
 	      return;
 	    }
 	    var _props2 = this.props,
 	        selectedSource = _props2.selectedSource,
 	        sourceTabs = _props2.sourceTabs,
-	        selectSource = _props2.selectSource;
+	        moveTab = _props2.moveTab;
 
 	    var sourceTabEls = this.refs.sourceTabs.children;
 	    var hiddenSourceTabs = getHiddenTabs(sourceTabs, sourceTabEls);
 
 	    if (hiddenSourceTabs.indexOf(selectedSource) !== -1) {
-	      return selectSource(selectedSource.get("id"), { tabIndex: 0 });
+	      return moveTab(selectedSource.get("url"), 0);
 	    }
 
 	    this.setState({ hiddenSourceTabs });
 	  }
 
 	  toggleSourcesDropdown(e) {
 	    this.setState({
 	      dropdownShown: !this.state.dropdownShown
 	    });
 	  }
 
 	  renderDropdownSource(source) {
-	    var selectSource = this.props.selectSource;
+	    var moveTab = this.props.moveTab;
 
 	    var filename = (0, _source.getFilename)(source.toJS());
 
 	    return _react.DOM.li({
 	      key: source.get("id"),
 	      onClick: () => {
 	        // const tabIndex = getLastVisibleTabIndex(sourceTabs, sourceTabEls);
 	        var tabIndex = 0;
-	        selectSource(source.get("id"), { tabIndex });
+	        moveTab(source.get("url"), tabIndex);
 	      }
 	    }, filename);
 	  }
 
 	  renderTabs() {
 	    var sourceTabs = this.props.sourceTabs;
 	    if (!sourceTabs) {
 	      return;
@@ -30879,17 +30892,17 @@ return /******/ (function(modules) { // 
 
 	  render() {
 	    return _react.DOM.div({ className: "source-header" }, this.renderStartPanelToggleButton(), this.renderTabs(), this.renderNewButton(), this.renderDropdown(), this.renderEndPanelToggleButton());
 	  }
 	}
 
 	SourceTabs.displayName = "SourceTabs";
 
-	module.exports = (0, _reactRedux.connect)(state => {
+	exports.default = (0, _reactRedux.connect)(state => {
 	  return {
 	    selectedSource: (0, _selectors.getSelectedSource)(state),
 	    sourceTabs: (0, _selectors.getSourcesForTabs)(state),
 	    searchOn: (0, _selectors.getProjectSearchState)(state)
 	  };
 	}, dispatch => (0, _redux.bindActionCreators)(_actions2.default, dispatch))(SourceTabs);
 
 /***/ },
@@ -31065,36 +31078,34 @@ return /******/ (function(modules) { // 
 /* 824 */,
 /* 825 */,
 /* 826 */,
 /* 827 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	Object.defineProperty(exports, "__esModule", {
+	  value: true
+	});
+	exports.getOutOfScopeLocations = exports.getVariablesInScope = exports.getSymbols = exports.getClosestExpression = exports.stopParserWorker = exports.startParserWorker = undefined;
+
 	var _devtoolsUtils = __webpack_require__(900);
 
 	var WorkerDispatcher = _devtoolsUtils.workerUtils.WorkerDispatcher;
 
 
 	var dispatcher = new WorkerDispatcher();
-
-	var getClosestExpression = dispatcher.task("getClosestExpression");
-	var getSymbols = dispatcher.task("getSymbols");
-	var getVariablesInScope = dispatcher.task("getVariablesInScope");
-	var getOutOfScopeLocations = dispatcher.task("getOutOfScopeLocations");
-
-	module.exports = {
-	  getSymbols,
-	  getVariablesInScope,
-	  getOutOfScopeLocations,
-	  getClosestExpression,
-	  startParserWorker: dispatcher.start.bind(dispatcher),
-	  stopParserWorker: dispatcher.stop.bind(dispatcher)
-	};
+	var startParserWorker = exports.startParserWorker = dispatcher.start.bind(dispatcher);
+	var stopParserWorker = exports.stopParserWorker = dispatcher.stop.bind(dispatcher);
+
+	var getClosestExpression = exports.getClosestExpression = dispatcher.task("getClosestExpression");
+	var getSymbols = exports.getSymbols = dispatcher.task("getSymbols");
+	var getVariablesInScope = exports.getVariablesInScope = dispatcher.task("getVariablesInScope");
+	var getOutOfScopeLocations = exports.getOutOfScopeLocations = dispatcher.task("getOutOfScopeLocations");
 
 /***/ },
 /* 828 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	var feature = __webpack_require__(829);
@@ -31199,16 +31210,20 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 830 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var Menu = __webpack_require__(967);
 	var MenuItem = __webpack_require__(970);
 
 	var _require = __webpack_require__(971),
 	    PrefsHelper = _require.PrefsHelper;
 
 	var Services = __webpack_require__(29);
 
@@ -31798,40 +31813,44 @@ return /******/ (function(modules) { // 
 	var startDebuggingTab = (() => {
 	  var _ref2 = _asyncToGenerator(function* (connTarget) {
 	    var clientType = connTarget.type;
 	    var client = clientType === "chrome" ? chrome : firefox;
 
 	    var tabs = yield client.connectClient();
 
 	    if (!tabs) {
-	      return;
+	      return undefined;
 	    }
 
 	    var tab = tabs.find(function (t) {
 	      return t.id.indexOf(connTarget.param) !== -1;
 	    });
 	    if (!tab) {
-	      return;
+	      return undefined;
 	    }
 
 	    var tabConnection = yield client.connectTab(tab.tab);
 
 	    client.initPage({ tab, clientType, tabConnection });
 
 	    return { tab, tabConnection };
 	  });
 
 	  return function startDebuggingTab(_x2) {
 	    return _ref2.apply(this, arguments);
 	  };
 	})();
 
 	function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(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 Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var firefox = __webpack_require__(886);
 	var chrome = __webpack_require__(887);
 
 	function startDebugging(connTarget) {
 	  if (connTarget.type === "node") {
 	    return startDebuggingNode(connTarget.param);
 	  }
 
@@ -31885,46 +31904,52 @@ return /******/ (function(modules) { // 
 	    window.addEventListener("beforeunload", function () {
 	      if (tabTarget !== null) {
 	        tabTarget.destroy();
 	      }
 	    });
 
 	    var tabTarget = yield lookupTabTarget(tab);
 
-	    var _ref3 = yield tabTarget.activeTab.attachThread({}),
+	    var _ref3 = yield tabTarget.activeTab.attachThread({
+	      ignoreFrameEnvironment: true
+	    }),
 	        _ref4 = _slicedToArray(_ref3, 2),
 	        threadClient = _ref4[1];
 
 	    threadClient.resume();
 	    return { debuggerClient, threadClient, tabTarget };
 	  });
 
 	  return function connectTab(_x) {
 	    return _ref2.apply(this, arguments);
 	  };
 	})();
 
 	var getTabs = (() => {
 	  var _ref5 = _asyncToGenerator(function* () {
 	    if (!debuggerClient || !debuggerClient.mainRoot) {
-	      return;
+	      return undefined;
 	    }
 
 	    var response = yield debuggerClient.listTabs();
 	    return createTabs(response.tabs);
 	  });
 
 	  return function getTabs() {
 	    return _ref5.apply(this, arguments);
 	  };
 	})();
 
 	function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(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 Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var _require = __webpack_require__(976),
 	    DebuggerClient = _require.DebuggerClient,
 	    DebuggerTransport = _require.DebuggerTransport,
 	    TargetFactory = _require.TargetFactory,
 	    WebsocketTransport = _require.WebsocketTransport;
 
 	var _require2 = __webpack_require__(828),
 	    getValue = _require2.getValue;
@@ -31997,17 +32022,17 @@ return /******/ (function(modules) { // 
 
 	    var tabs = void 0;
 	    try {
 	      tabs = yield CDP.List({
 	        port: getValue("node.port"),
 	        host: getValue("node.host")
 	      });
 	    } catch (e) {
-	      return;
+	      return undefined;
 	    }
 
 	    return createTabs(tabs, {
 	      clientType: "node",
 	      type: "node"
 	    });
 	  });
 
@@ -32041,16 +32066,20 @@ return /******/ (function(modules) { // 
 
 	  return function connectNode(_x3) {
 	    return _ref5.apply(this, arguments);
 	  };
 	})();
 
 	function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(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 Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var CDP = __webpack_require__(126);
 
 	var _require = __webpack_require__(828),
 	    getValue = _require.getValue;
 
 	var _require2 = __webpack_require__(900),
 	    networkRequest = _require2.networkRequest;
 
@@ -32114,206 +32143,234 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 888 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	Object.defineProperty(exports, "__esModule", {
+	  value: true
+	});
+	exports.onConnect = undefined;
+
 	var onConnect = (() => {
 	  var _ref = _asyncToGenerator(function* (connection, services) {
 	    // NOTE: the landing page does not connect to a JS process
 	    if (!connection) {
 	      return;
 	    }
 
 	    var client = getClient(connection);
 	    var commands = client.clientCommands;
 
-	    var _bootstrapStore = bootstrapStore(commands, services),
+	    var _bootstrapStore = (0, _bootstrap.bootstrapStore)(commands, services),
 	        store = _bootstrapStore.store,
 	        actions = _bootstrapStore.actions,
 	        selectors = _bootstrapStore.selectors;
 
-	    bootstrapWorkers();
+	    (0, _bootstrap.bootstrapWorkers)();
 	    yield client.onConnect(connection, actions);
 	    yield loadFromPrefs(actions);
 
 	    window.getGlobalsForTesting = function () {
 	      return {
 	        store,
 	        actions,
 	        selectors,
 	        client: client.clientCommands,
 	        connection
 	      };
 	    };
 
-	    if (!isFirefoxPanel()) {
+	    if (!(0, _devtoolsConfig.isFirefoxPanel)()) {
 	      console.group("Developement Notes");
 	      var baseUrl = "https://devtools-html.github.io/debugger.html";
 	      var localDevelopmentUrl = `${baseUrl}/docs/local-development.html`;
 	      console.log("Debugging Tips", localDevelopmentUrl);
 	      console.log("getGlobalsForTesting", window.getGlobalsForTesting());
 	      console.groupEnd();
 	    }
 
-	    bootstrapApp(connection, { store, actions });
+	    (0, _bootstrap.bootstrapApp)(connection, { store, actions });
 
 	    return { store, actions, selectors, client: commands };
 	  });
 
 	  return function onConnect(_x, _x2) {
 	    return _ref.apply(this, arguments);
 	  };
 	})();
 
+	var _firefox = __webpack_require__(889);
+
+	var firefox = _interopRequireWildcard(_firefox);
+
+	var _chrome = __webpack_require__(893);
+
+	var chrome = _interopRequireWildcard(_chrome);
+
+	var _prefs = __webpack_require__(226);
+
+	var _devtoolsConfig = __webpack_require__(828);
+
+	var _bootstrap = __webpack_require__(897);
+
+	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 _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(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 Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
 
-	var firefox = __webpack_require__(889);
-	var chrome = __webpack_require__(893);
-
-	var _require = __webpack_require__(226),
-	    prefs = _require.prefs;
-
-	var _require2 = __webpack_require__(828),
-	    isFirefoxPanel = _require2.isFirefoxPanel;
-
-	var _require3 = __webpack_require__(897),
-	    bootstrapApp = _require3.bootstrapApp,
-	    bootstrapStore = _require3.bootstrapStore,
-	    bootstrapWorkers = _require3.bootstrapWorkers;
-
 	function loadFromPrefs(actions) {
-	  var pauseOnExceptions = prefs.pauseOnExceptions,
-	      ignoreCaughtExceptions = prefs.ignoreCaughtExceptions;
+	  var pauseOnExceptions = _prefs.prefs.pauseOnExceptions,
+	      ignoreCaughtExceptions = _prefs.prefs.ignoreCaughtExceptions;
 
 	  if (pauseOnExceptions || ignoreCaughtExceptions) {
 	    return actions.pauseOnExceptions(pauseOnExceptions, ignoreCaughtExceptions);
 	  }
 	}
 
 	function getClient(connection) {
 	  var clientType = connection.tab.clientType;
 
 	  return clientType == "firefox" ? firefox : chrome;
 	}
 
-	module.exports = { onConnect };
+	exports.onConnect = onConnect;
 
 /***/ },
 /* 889 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
+	exports.clientEvents = exports.clientCommands = exports.onConnect = undefined;
 
 	var onConnect = exports.onConnect = (() => {
 	  var _ref = _asyncToGenerator(function* (connection, actions) {
 	    var _connection$tabConnec = connection.tabConnection,
 	        tabTarget = _connection$tabConnec.tabTarget,
 	        threadClient = _connection$tabConnec.threadClient,
 	        debuggerClient = _connection$tabConnec.debuggerClient;
 
 
 	    if (!tabTarget || !threadClient || !debuggerClient) {
 	      return;
 	    }
 
-	    setupCommands({ threadClient, tabTarget, debuggerClient });
+	    (0, _commands.setupCommands)({ threadClient, tabTarget, debuggerClient });
 
 	    if (actions) {
-	      setupEvents({ threadClient, actions });
+	      (0, _events.setupEvents)({ threadClient, actions });
 	    }
 
 	    tabTarget.on("will-navigate", actions.willNavigate);
 	    tabTarget.on("navigate", actions.navigated);
 
 	    yield threadClient.reconfigure({ observeAsmJS: true });
 
 	    // In Firefox, we need to initially request all of the sources. This
 	    // usually fires off individual `newSource` notifications as the
 	    // debugger finds them, but there may be existing sources already in
 	    // the debugger (if it's paused already, or if loading the page from
 	    // bfcache) so explicity fire `newSource` events for all returned
 	    // sources.
-	    var sources = yield clientCommands.fetchSources();
+	    var sources = yield _commands.clientCommands.fetchSources();
 	    yield actions.newSources(sources);
 
 	    // If the threadClient is already paused, make sure to show a
 	    // paused state.
 	    var pausedPacket = threadClient.getLastPausePacket();
 	    if (pausedPacket) {
-	      clientEvents.paused("paused", pausedPacket);
+	      _events.clientEvents.paused("paused", pausedPacket);
 	    }
 	  });
 
 	  return function onConnect(_x, _x2) {
 	    return _ref.apply(this, arguments);
 	  };
 	})();
 
+	var _commands = __webpack_require__(890);
+
+	var _events = __webpack_require__(892);
+
 	function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(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 Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
 
-	var _require = __webpack_require__(890),
-	    setupCommands = _require.setupCommands,
-	    clientCommands = _require.clientCommands;
-
-	var _require2 = __webpack_require__(892),
-	    setupEvents = _require2.setupEvents,
-	    clientEvents = _require2.clientEvents;
-
-	exports.clientCommands = clientCommands;
-	exports.clientEvents = clientEvents;
+	exports.clientCommands = _commands.clientCommands;
+	exports.clientEvents = _events.clientEvents;
 
 /***/ },
 /* 890 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	Object.defineProperty(exports, "__esModule", {
+	  value: true
+	});
+	exports.clientCommands = exports.setupCommands = undefined;
+
+	var getFrameScopes = (() => {
+	  var _ref2 = _asyncToGenerator(function* (frame) {
+	    if (frame.scope) {
+	      return frame.scope;
+	    }
+
+	    return threadClient.getEnvironment(frame.id);
+	  });
+
+	  return function getFrameScopes(_x) {
+	    return _ref2.apply(this, arguments);
+	  };
+	})();
+
 	var blackBox = (() => {
-	  var _ref2 = _asyncToGenerator(function* (sourceId, isBlackBoxed) {
+	  var _ref3 = _asyncToGenerator(function* (sourceId, isBlackBoxed) {
 	    var sourceClient = threadClient.source({ actor: sourceId });
 	    if (isBlackBoxed) {
 	      yield sourceClient.unblackBox();
 	    } else {
 	      yield sourceClient.blackBox();
 	    }
 
 	    return { isBlackBoxed: !isBlackBoxed };
 	  });
 
-	  return function blackBox(_x, _x2) {
-	    return _ref2.apply(this, arguments);
+	  return function blackBox(_x2, _x3) {
+	    return _ref3.apply(this, arguments);
 	  };
 	})();
 
 	var fetchSources = (() => {
-	  var _ref3 = _asyncToGenerator(function* () {
-	    var _ref4 = yield threadClient.getSources(),
-	        sources = _ref4.sources;
-
-	    return sources.map(createSource);
+	  var _ref4 = _asyncToGenerator(function* () {
+	    var _ref5 = yield threadClient.getSources(),
+	        sources = _ref5.sources;
+
+	    return sources.map(_create.createSource);
 	  });
 
 	  return function fetchSources() {
-	    return _ref3.apply(this, arguments);
+	    return _ref4.apply(this, arguments);
 	  };
 	})();
 
+	var _lodash = __webpack_require__(1033);
+
+	var _lodash2 = _interopRequireDefault(_lodash);
+
+	var _create = __webpack_require__(891);
+
+	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
 	function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(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 Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
 
-	var _require = __webpack_require__(891),
-	    createSource = _require.createSource;
-
 	var bpClients = void 0;
 	var threadClient = void 0;
 	var tabTarget = void 0;
 	var debuggerClient = void 0;
 
 	function setupCommands(dependencies) {
 	  threadClient = dependencies.threadClient;
 	  tabTarget = dependencies.tabTarget;
@@ -32349,16 +32406,50 @@ return /******/ (function(modules) { // 
 	  return threadClient.breakOnNext();
 	}
 
 	function sourceContents(sourceId) {
 	  var sourceClient = threadClient.source({ actor: sourceId });
 	  return sourceClient.source();
 	}
 
+	function getBreakpointByLocation(location) {
+	  var values = _lodash2.default.values(bpClients);
+	  var bpClient = values.find(value => {
+	    var _value$location = value.location,
+	        actor = _value$location.actor,
+	        line = _value$location.line,
+	        column = _value$location.column,
+	        condition = _value$location.condition;
+
+	    return location.line === line && location.sourceId === actor && location.column === column && location.condition === condition;
+	  });
+
+	  if (bpClient) {
+	    var _bpClient$location = bpClient.location,
+	        actor = _bpClient$location.actor,
+	        url = _bpClient$location.url,
+	        line = _bpClient$location.line,
+	        column = _bpClient$location.column,
+	        condition = _bpClient$location.condition;
+
+	    return {
+	      id: bpClient.actor,
+	      actualLocation: {
+	        line,
+	        column,
+	        condition,
+	        sourceId: actor,
+	        sourceUrl: url
+	      }
+	    };
+	  }
+	  return null;
+	}
+
 	function setBreakpoint(location, condition, noSliding) {
 	  var sourceClient = threadClient.source({ actor: location.sourceId });
 
 	  return sourceClient.setBreakpoint({
 	    line: location.line,
 	    column: location.column,
 	    condition,
 	    noSliding
@@ -32487,41 +32578,48 @@ return /******/ (function(modules) { // 
 	  eventListeners,
 	  pauseGrip,
 	  resume,
 	  stepIn,
 	  stepOut,
 	  stepOver,
 	  breakOnNext,
 	  sourceContents,
+	  getBreakpointByLocation,
 	  setBreakpoint,
 	  removeBreakpoint,
 	  setBreakpointCondition,
 	  evaluate,
 	  debuggeeCommand,
 	  navigate,
 	  reload,
 	  getProperties,
+	  getFrameScopes,
 	  pauseOnExceptions,
 	  prettyPrint,
 	  disablePrettyPrint,
 	  fetchSources
 	};
 
-	module.exports = {
-	  setupCommands,
-	  clientCommands
-	};
+	exports.setupCommands = setupCommands;
+	exports.clientCommands = clientCommands;
 
 /***/ },
 /* 891 */
 /***/ function(module, exports) {
 
 	"use strict";
 
+	Object.defineProperty(exports, "__esModule", {
+	  value: true
+	});
+	exports.createFrame = createFrame;
+	exports.createSource = createSource;
+	exports.createPause = createPause;
+
 	// This module converts Firefox specific types to the generic types
 
 	function createFrame(frame) {
 	  var title = void 0;
 	  if (frame.type == "call") {
 	    var c = frame.callee;
 	    title = c.name || c.userDisplayName || c.displayName || "(anonymous)";
 	  } else {
@@ -32556,62 +32654,58 @@ return /******/ (function(modules) { // 
 	  var frame = packet.frame || response.frames[0];
 
 	  return Object.assign({}, packet, {
 	    frame: createFrame(frame),
 	    frames: response.frames.map(createFrame)
 	  });
 	}
 
-	module.exports = {
-	  createFrame,
-	  createSource,
-	  createPause
-	};
-
 /***/ },
 /* 892 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	Object.defineProperty(exports, "__esModule", {
+	  value: true
+	});
+	exports.clientEvents = exports.setupEvents = undefined;
+
 	var paused = (() => {
 	  var _ref = _asyncToGenerator(function* (_, packet) {
 	    // If paused by an explicit interrupt, which are generated by the
 	    // slow script dialog and internal events such as setting
 	    // breakpoints, ignore the event.
 	    var why = packet.why;
 
 	    if (why.type === "interrupted" && !packet.why.onNext) {
 	      return;
 	    }
 
 	    // Eagerly fetch the frames
 	    var response = yield threadClient.getFrames(0, CALL_STACK_PAGE_SIZE);
 
 	    if (why.type != "alreadyPaused") {
-	      var pause = createPause(packet, response);
+	      var pause = (0, _create.createPause)(packet, response);
 	      actions.paused(pause);
 	    }
 	  });
 
 	  return function paused(_x, _x2) {
 	    return _ref.apply(this, arguments);
 	  };
 	})();
 
+	var _create = __webpack_require__(891);
+
+	var _devtoolsConfig = __webpack_require__(828);
+
 	function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(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 Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
 
-	var _require = __webpack_require__(891),
-	    createPause = _require.createPause,
-	    createSource = _require.createSource;
-
-	var _require2 = __webpack_require__(828),
-	    isEnabled = _require2.isEnabled;
-
 	var CALL_STACK_PAGE_SIZE = 1000;
 
 	var threadClient = void 0;
 	var actions = void 0;
 
 	function setupEvents(dependencies) {
 	  threadClient = dependencies.threadClient;
 	  actions = dependencies.actions;
@@ -32625,107 +32719,106 @@ return /******/ (function(modules) { // 
 
 	function resumed(_, packet) {
 	  actions.resumed(packet);
 	}
 
 	function newSource(_, _ref2) {
 	  var source = _ref2.source;
 
-	  actions.newSource(createSource(source));
-
-	  if (isEnabled("eventListeners")) {
+	  actions.newSource((0, _create.createSource)(source));
+
+	  if ((0, _devtoolsConfig.isEnabled)("eventListeners")) {
 	    actions.fetchEventListeners();
 	  }
 	}
 
 	var clientEvents = {
 	  paused,
 	  resumed,
 	  newSource
 	};
 
-	module.exports = {
-	  setupEvents,
-	  clientEvents
-	};
+	exports.setupEvents = setupEvents;
+	exports.clientEvents = clientEvents;
 
 /***/ },
 /* 893 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
+	exports.clientEvents = exports.clientCommands = exports.onConnect = undefined;
 
 	var onConnect = exports.onConnect = (() => {
 	  var _ref = _asyncToGenerator(function* (connection, actions) {
 	    var tabConnection = connection.tabConnection,
 	        type = connection.connTarget.type;
 	    var Debugger = tabConnection.Debugger,
 	        Runtime = tabConnection.Runtime,
 	        Page = tabConnection.Page;
 
 
 	    Debugger.enable();
 	    Debugger.setPauseOnExceptions({ state: "none" });
 	    Debugger.setAsyncCallStackDepth({ maxDepth: 0 });
 
 	    if (type == "chrome") {
-	      Page.frameNavigated(pageEvents.frameNavigated);
-	      Page.frameStartedLoading(pageEvents.frameStartedLoading);
-	      Page.frameStoppedLoading(pageEvents.frameStoppedLoading);
-	    }
-
-	    Debugger.scriptParsed(clientEvents.scriptParsed);
-	    Debugger.scriptFailedToParse(clientEvents.scriptFailedToParse);
-	    Debugger.paused(clientEvents.paused);
-	    Debugger.resumed(clientEvents.resumed);
-
-	    setupCommands({ Debugger, Runtime, Page });
-	    setupEvents({ actions, Page, type, Runtime });
+	      Page.frameNavigated(_events.pageEvents.frameNavigated);
+	      Page.frameStartedLoading(_events.pageEvents.frameStartedLoading);
+	      Page.frameStoppedLoading(_events.pageEvents.frameStoppedLoading);
+	    }
+
+	    Debugger.scriptParsed(_events.clientEvents.scriptParsed);
+	    Debugger.scriptFailedToParse(_events.clientEvents.scriptFailedToParse);
+	    Debugger.paused(_events.clientEvents.paused);
+	    Debugger.resumed(_events.clientEvents.resumed);
+
+	    (0, _commands.setupCommands)({ Debugger, Runtime, Page });
+	    (0, _events.setupEvents)({ actions, Page, type, Runtime });
 	  });
 
 	  return function onConnect(_x, _x2) {
 	    return _ref.apply(this, arguments);
 	  };
 	})();
 
+	var _commands = __webpack_require__(894);
+
+	var _events = __webpack_require__(896);
+
 	function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(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 Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
 
-	var _require = __webpack_require__(894),
-	    setupCommands = _require.setupCommands,
-	    clientCommands = _require.clientCommands;
-
-	var _require2 = __webpack_require__(896),
-	    setupEvents = _require2.setupEvents,
-	    clientEvents = _require2.clientEvents,
-	    pageEvents = _require2.pageEvents;
-
-	exports.clientCommands = clientCommands;
-	exports.clientEvents = clientEvents;
+	exports.clientCommands = _commands.clientCommands;
+	exports.clientEvents = _events.clientEvents;
 
 /***/ },
 /* 894 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	Object.defineProperty(exports, "__esModule", {
+	  value: true
+	});
+	exports.clientCommands = exports.setupCommands = undefined;
+
 	var setBreakpoint = (() => {
 	  var _ref3 = _asyncToGenerator(function* (location, condition) {
 	    var _ref4 = yield debuggerAgent.setBreakpoint({
-	      location: toServerLocation(location),
+	      location: (0, _create.toServerLocation)(location),
 	      columnNumber: location.column
 	    }),
 	        breakpointId = _ref4.breakpointId,
 	        serverLocation = _ref4.serverLocation;
 
-	    var actualLocation = fromServerLocation(serverLocation) || location;
+	    var actualLocation = (0, _create.fromServerLocation)(serverLocation) || location;
 
 	    return {
 	      id: breakpointId,
 	      actualLocation: actualLocation
 	    };
 	  });
 
 	  return function setBreakpoint(_x, _x2) {
@@ -32735,33 +32828,30 @@ return /******/ (function(modules) { // 
 
 	var getProperties = (() => {
 	  var _ref5 = _asyncToGenerator(function* (object) {
 	    var _ref6 = yield runtimeAgent.getProperties({
 	      objectId: object.objectId
 	    }),
 	        result = _ref6.result;
 
-	    var loadedObjects = result.map(createLoadedObject);
+	    var loadedObjects = result.map(_create.createLoadedObject);
 
 	    return { loadedObjects };
 	  });
 
 	  return function getProperties(_x3) {
 	    return _ref5.apply(this, arguments);
 	  };
 	})();
 
+	var _create = __webpack_require__(895);
+
 	function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(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 Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
 
-	var _require = __webpack_require__(895),
-	    toServerLocation = _require.toServerLocation,
-	    fromServerLocation = _require.fromServerLocation,
-	    createLoadedObject = _require.createLoadedObject;
-
 	var debuggerAgent = void 0;
 	var runtimeAgent = void 0;
 	var pageAgent = void 0;
 
 	function setupCommands(_ref) {
 	  var Debugger = _ref.Debugger,
 	      Runtime = _ref.Runtime,
 	      Page = _ref.Page;
@@ -32837,27 +32927,32 @@ return /******/ (function(modules) { // 
 	  setBreakpoint,
 	  removeBreakpoint,
 	  evaluate,
 	  debuggeeCommand,
 	  navigate,
 	  getProperties
 	};
 
-	module.exports = {
-	  setupCommands,
-	  clientCommands
-	};
+	exports.setupCommands = setupCommands;
+	exports.clientCommands = clientCommands;
 
 /***/ },
 /* 895 */
 /***/ function(module, exports) {
 
 	"use strict";
 
+	Object.defineProperty(exports, "__esModule", {
+	  value: true
+	});
+	exports.fromServerLocation = fromServerLocation;
+	exports.toServerLocation = toServerLocation;
+	exports.createFrame = createFrame;
+	exports.createLoadedObject = createLoadedObject;
 	function fromServerLocation(serverLocation) {
 	  if (serverLocation) {
 	    return {
 	      sourceId: serverLocation.scriptId,
 	      line: serverLocation.lineNumber + 1,
 	      column: serverLocation.columnNumber
 	    };
 	  }
@@ -32887,70 +32982,66 @@ return /******/ (function(modules) { // 
 	  return {
 	    objectId: value.objectId,
 	    parentId,
 	    name,
 	    value
 	  };
 	}
 
-	module.exports = {
-	  fromServerLocation,
-	  toServerLocation,
-	  createFrame,
-	  createLoadedObject
-	};
-
 /***/ },
 /* 896 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	Object.defineProperty(exports, "__esModule", {
+	  value: true
+	});
+	exports.clientEvents = exports.pageEvents = exports.setupEvents = undefined;
+
 	var paused = (() => {
 	  var _ref2 = _asyncToGenerator(function* (_ref3) {
 	    var callFrames = _ref3.callFrames,
 	        reason = _ref3.reason,
 	        data = _ref3.data,
 	        hitBreakpoints = _ref3.hitBreakpoints,
 	        asyncStackTrace = _ref3.asyncStackTrace;
 
-	    var frames = callFrames.map(createFrame);
+	    var frames = callFrames.map(_create.createFrame);
 	    var frame = frames[0];
 	    var why = Object.assign({}, {
 	      type: reason
 	    }, data);
 
 	    var objectId = frame.scopeChain[0].object.objectId;
 
 	    var _ref4 = yield runtimeAgent.getProperties({
 	      objectId
 	    }),
 	        result = _ref4.result;
 
-	    var loadedObjects = result.map(createLoadedObject);
+	    var loadedObjects = result.map(_create.createLoadedObject);
 
 	    if (clientType == "chrome") {
 	      pageAgent.configureOverlay({ message: "Paused in debugger.html" });
 	    }
 
 	    yield actions.paused({ frame, why, frames, loadedObjects });
 	  });
 
 	  return function paused(_x) {
 	    return _ref2.apply(this, arguments);
 	  };
 	})();
 
+	var _create = __webpack_require__(895);
+
 	function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(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 Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
 
-	var _require = __webpack_require__(895),
-	    createFrame = _require.createFrame,
-	    createLoadedObject = _require.createLoadedObject;
-
 	var actions = void 0;
 	var pageAgent = void 0;
 	var clientType = void 0;
 	var runtimeAgent = void 0;
 
 	function setupEvents(dependencies) {
 	  actions = dependencies.actions;
 	  pageAgent = dependencies.Page;
@@ -33029,21 +33120,19 @@ return /******/ (function(modules) { // 
 	var pageEvents = {
 	  frameNavigated,
 	  frameStartedLoading,
 	  domContentEventFired,
 	  loadEventFired,
 	  frameStoppedLoading
 	};
 
-	module.exports = {
-	  setupEvents,
-	  pageEvents,
-	  clientEvents
-	};
+	exports.setupEvents = setupEvents;
+	exports.pageEvents = pageEvents;
+	exports.clientEvents = clientEvents;
 
 /***/ },
 /* 897 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
@@ -33065,16 +33154,18 @@ return /******/ (function(modules) { // 
 	var _reactDom2 = _interopRequireDefault(_reactDom);
 
 	var _devtoolsConfig = __webpack_require__(828);
 
 	var _devtoolsLaunchpad = __webpack_require__(131);
 
 	var _devtoolsSourceMap = __webpack_require__(898);
 
+	var _search = __webpack_require__(1115);
+
 	var _prettyPrint = __webpack_require__(903);
 
 	var _parser = __webpack_require__(827);
 
 	var _createStore = __webpack_require__(189);
 
 	var _createStore2 = _interopRequireDefault(_createStore);
 
@@ -33125,25 +33216,27 @@ return /******/ (function(modules) { // 
 
 	function bootstrapWorkers() {
 	  if (!(0, _devtoolsConfig.isFirefoxPanel)()) {
 	    // When used in Firefox, the toolbox manages the source map worker.
 	    (0, _devtoolsSourceMap.startSourceMapWorker)((0, _devtoolsConfig.getValue)("workers.sourceMapURL"));
 	  }
 	  (0, _prettyPrint.startPrettyPrintWorker)((0, _devtoolsConfig.getValue)("workers.prettyPrintURL"));
 	  (0, _parser.startParserWorker)((0, _devtoolsConfig.getValue)("workers.parserURL"));
+	  (0, _search.startSearchWorker)((0, _devtoolsConfig.getValue)("workers.searchURL"));
 	}
 
 	function teardownWorkers() {
 	  if (!(0, _devtoolsConfig.isFirefoxPanel)()) {
 	    // When used in Firefox, the toolbox manages the source map worker.
 	    (0, _devtoolsSourceMap.stopSourceMapWorker)();
 	  }
 	  (0, _prettyPrint.stopPrettyPrintWorker)();
 	  (0, _parser.stopParserWorker)();
+	  (0, _search.stopSearchWorker)();
 	}
 
 /***/ },
 /* 898 */
 /***/ function(module, exports, __webpack_require__) {
 
 	const {
 	  originalToGeneratedId,
@@ -33373,17 +33466,22 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 903 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
-	var prettyPrint = (() => {
+	Object.defineProperty(exports, "__esModule", {
+	  value: true
+	});
+	exports.prettyPrint = exports.stopPrettyPrintWorker = exports.startPrettyPrintWorker = undefined;
+
+	var prettyPrint = exports.prettyPrint = (() => {
 	  var _ref = _asyncToGenerator(function* (_ref2) {
 	    var source = _ref2.source,
 	        sourceText = _ref2.sourceText,
 	        url = _ref2.url;
 
 	    var contentType = sourceText ? sourceText.contentType : "";
 	    var indent = 2;
 
@@ -33412,24 +33510,20 @@ return /******/ (function(modules) { // 
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 	function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(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 Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
 
 	var WorkerDispatcher = _devtoolsUtils.workerUtils.WorkerDispatcher;
 
 
 	var dispatcher = new WorkerDispatcher();
+	var startPrettyPrintWorker = exports.startPrettyPrintWorker = dispatcher.start.bind(dispatcher);
+	var stopPrettyPrintWorker = exports.stopPrettyPrintWorker = dispatcher.stop.bind(dispatcher);
 	var _prettyPrint = dispatcher.task("prettyPrint");
 
-	module.exports = {
-	  prettyPrint,
-	  startPrettyPrintWorker: dispatcher.start.bind(dispatcher),
-	  stopPrettyPrintWorker: dispatcher.stop.bind(dispatcher)
-	};
-
 /***/ },
 /* 904 */
 /***/ function(module, exports) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
@@ -37511,16 +37605,20 @@ return /******/ (function(modules) { // 
 
 
 /***/ },
 /* 966 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var _require = __webpack_require__(830),
 	    Menu = _require.Menu,
 	    MenuItem = _require.MenuItem;
 
 	var _require2 = __webpack_require__(828),
 	    isFirefoxPanel = _require2.isFirefoxPanel;
 
 	if (!isFirefoxPanel()) {
@@ -37657,18 +37755,26 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 967 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var EventEmitter = __webpack_require__(968);
 
+	function inToolbox() {
+	  return window.parent.document.documentURI == "about:devtools-toolbox";
+	}
+
 	/**
 	 * A partial implementation of the Menu API provided by electron:
 	 * https://github.com/electron/electron/blob/master/docs/api/menu.md.
 	 *
 	 * Extra features:
 	 *  - Emits an 'open' and 'close' event when the menu is opened/closed
 
 	 * @param String id (non standard)
@@ -37772,17 +37878,20 @@ return /******/ (function(modules) { // 
 	    }
 
 	    if (item.submenu) {
 	      var menupopup = doc.createElement("menupopup");
 	      item.submenu._createMenuItems(menupopup);
 
 	      var menuitem = doc.createElement("menuitem");
 	      menuitem.setAttribute("label", item.label);
-	      menuitem.textContent = item.label;
+	      if (!inToolbox()) {
+	        menuitem.textContent = item.label;
+	      }
+
 	      var menu = doc.createElement("menu");
 	      menu.appendChild(menuitem);
 	      menu.appendChild(menupopup);
 	      if (item.disabled) {
 	        menu.setAttribute("disabled", "true");
 	      }
 	      if (item.accesskey) {
 	        menu.setAttribute("accesskey", item.accesskey);
@@ -37792,17 +37901,21 @@ return /******/ (function(modules) { // 
 	      }
 	      parent.appendChild(menu);
 	    } else if (item.type === "separator") {
 	      var menusep = doc.createElement("menuseparator");
 	      parent.appendChild(menusep);
 	    } else {
 	      var _menuitem = doc.createElement("menuitem");
 	      _menuitem.setAttribute("label", item.label);
-	      _menuitem.textContent = item.label;
+
+	      if (!inToolbox()) {
+	        _menuitem.textContent = item.label;
+	      }
+
 	      _menuitem.addEventListener("command", () => item.click());
 
 	      if (item.type === "checkbox") {
 	        _menuitem.setAttribute("type", "checkbox");
 	      }
 	      if (item.type === "radio") {
 	        _menuitem.setAttribute("type", "radio");
 	      }
@@ -37839,16 +37952,20 @@ return /******/ (function(modules) { // 
 	module.exports = Menu;
 
 /***/ },
 /* 968 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var EventEmitter = function EventEmitter() {};
 	module.exports = EventEmitter;
 
 	var promise = __webpack_require__(969);
 
 	/**
 	 * Decorate an object with event emitter functionality.
 	 *
@@ -37981,16 +38098,20 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 969 */
 /***/ function(module, exports) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	/*
 	 * A sham for https://dxr.mozilla.org/mozilla-central/source/toolkit/modules/Promise.jsm
 	 */
 
 	/**
 	 * Promise.jsm is mostly the Promise web API with a `defer` method. Just drop this in here,
 	 * and use the native web API (although building with webpack/babel, it may replace this
 	 * with it's own version if we want to target environments that do not have `Promise`.
@@ -38013,16 +38134,20 @@ return /******/ (function(modules) { // 
 	module.exports = p;
 
 /***/ },
 /* 970 */
 /***/ function(module, exports) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	/**
 	 * A partial implementation of the MenuItem API provided by electron:
 	 * https://github.com/electron/electron/blob/master/docs/api/menu-item.md.
 	 *
 	 * Missing features:
 	 *   - id String - Unique within a single menu. If defined then it can be used
 	 *                 as a reference to this item by the position attribute.
 	 *   - role String - Define the action of the menu item; when specified the
@@ -38278,16 +38403,20 @@ return /******/ (function(modules) { // 
 /***/ },
 /* 972 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var _require = __webpack_require__(29),
 	    appinfo = _require.appinfo;
 
 	var EventEmitter = __webpack_require__(968);
 	var isOSX = appinfo.OS === "Darwin";
 
 	// List of electron keys mapped to DOM API (DOM_VK_*) key code
 	var ElectronKeysMapping = {
@@ -38797,16 +38926,20 @@ return /******/ (function(modules) { // 
 	})(typeof window === 'undefined' ? undefined : window);
 
 /***/ },
 /* 976 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var _require = __webpack_require__(977),
 	    DebuggerClient = _require.DebuggerClient;
 
 	var _require2 = __webpack_require__(986),
 	    DebuggerTransport = _require2.DebuggerTransport;
 
 	var WebsocketTransport = __webpack_require__(990);
 
@@ -38823,16 +38956,20 @@ return /******/ (function(modules) { // 
 /***/ },
 /* 977 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var _require = __webpack_require__(978),
 	    Ci = _require.Ci,
 	    Cu = _require.Cu,
 	    components = _require.components;
 
 	var DevToolsUtils = __webpack_require__(979);
 	var promise = __webpack_require__(980);
 	var events = __webpack_require__(982);
@@ -40908,16 +41045,20 @@ return /******/ (function(modules) { // 
 	  getFrames: DebuggerClient.requester({
 	    type: "frames",
 	    start: args(0),
 	    count: args(1)
 	  }, {
 	    telemetry: "FRAMES"
 	  }),
 
+	  getEnvironment: function (frameId) {
+	    return this.request({ to: frameId, type: "getEnvironment" });
+	  },
+
 	  /**
 	   * An array of cached frames. Clients can observe the framesadded and
 	   * framescleared event to keep up to date on changes to this cache,
 	   * and can fill it using the fillFrames method.
 	   */
 	  get cachedFrames() {
 	    return this._frameCache;
 	  },
@@ -42057,16 +42198,20 @@ return /******/ (function(modules) { // 
 	eventSource(EnvironmentClient.prototype);
 
 /***/ },
 /* 978 */
 /***/ function(module, exports) {
 
 	'use strict';
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	/*
 	 * A sham for https://developer.mozilla.org/en-US/Add-ons/SDK/Low-Level_APIs/chrome
 	 */
 
 	var ourServices = {
 	  nsIClipboardHelper: {
 	    copyString: () => {}
 	  },
@@ -42137,16 +42282,20 @@ return /******/ (function(modules) { // 
 /***/ },
 /* 979 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	/* General utilities used throughout devtools. */
 	var _require = __webpack_require__(978),
 	    Ci = _require.Ci,
 	    Cu = _require.Cu,
 	    Cc = _require.Cc,
 	    components = _require.components;
 
 	var promise = __webpack_require__(980);
@@ -42708,16 +42857,20 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 980 */
 /***/ function(module, exports) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var p = typeof window != "undefined" ? window.Promise : Promise;
 	p.defer = function defer() {
 	  var resolve, reject;
 	  var promise = new Promise(function () {
 	    resolve = arguments[0];
 	    reject = arguments[1];
 	  });
 	  return {
@@ -42730,24 +42883,32 @@ return /******/ (function(modules) { // 
 	module.exports = p;
 
 /***/ },
 /* 981 */
 /***/ function(module, exports) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	module.exports = { AppConstants: {} };
 
 /***/ },
 /* 982 */
 /***/ function(module, exports, __webpack_require__) {
 
 	/* WEBPACK VAR INJECTION */(function(module) {"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	module.metadata = {
 	  "stability": "unstable"
 	};
 
 	var UNCAUGHT_ERROR = 'An error event was emitted for which there was no listener.';
 	var BAD_LISTENER = 'The event listener must be a function.';
 
 	var _require = __webpack_require__(983),
@@ -42985,16 +43146,20 @@ return /******/ (function(modules) { // 
 	/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(51)(module)))
 
 /***/ },
 /* 984 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var _require = __webpack_require__(978),
 	    Cc = _require.Cc,
 	    Ci = _require.Ci,
 	    Cu = _require.Cu;
 
 	var DevToolsUtils = __webpack_require__(979);
 	var EventEmitter = __webpack_require__(985);
 	var promise = __webpack_require__(980);
@@ -43797,16 +43962,20 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 986 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var DevToolsUtils = __webpack_require__(979);
 	var dumpn = DevToolsUtils.dumpn,
 	    dumpv = DevToolsUtils.dumpv;
 
 	var StreamUtils = __webpack_require__(987);
 
 	var _require = __webpack_require__(988),
 	    Packet = _require.Packet,
@@ -44783,16 +44952,20 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 988 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	/**
 	 * Packets contain read / write functionality for the different packet types
 	 * supported by the debugging protocol, so that a transport can focus on
 	 * delivery and queue management without worrying too much about the specific
 	 * packet types.
 	 *
 	 * They are intended to be "one use only", so a new packet should be
 	 * instantiated for each incoming or outgoing packet.
@@ -45536,16 +45709,20 @@ return /******/ (function(modules) { // 
 	module.exports = WebSocketDebuggerTransport;
 
 /***/ },
 /* 991 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var promise = __webpack_require__(980);
 	var EventEmitter = __webpack_require__(985);
 
 	var _require = __webpack_require__(977),
 	    DebuggerClient = _require.DebuggerClient;
 
 	var targets = new WeakMap();
 	var promiseTargets = new WeakMap();
@@ -47211,16 +47388,20 @@ return /******/ (function(modules) { // 
 	var _Frame = __webpack_require__(1013);
 
 	var _Frame2 = _interopRequireDefault(_Frame);
 
 	var _Group2 = __webpack_require__(1015);
 
 	var _Group3 = _interopRequireDefault(_Group2);
 
+	var _WhyPaused = __webpack_require__(1119);
+
+	var _WhyPaused2 = _interopRequireDefault(_WhyPaused);
+
 	var _actions = __webpack_require__(244);
 
 	var _actions2 = _interopRequireDefault(_actions);
 
 	var _frame = __webpack_require__(1014);
 
 	var _clipboard = __webpack_require__(423);
 
@@ -47336,34 +47517,37 @@ return /******/ (function(modules) { // 
 	    if (frames.length <= NUM_FRAMES_SHOWN) {
 	      return null;
 	    }
 
 	    return _react.DOM.div({ className: "show-more", onClick: this.toggleFramesDisplay }, buttonMessage);
 	  }
 
 	  render() {
-	    var frames = this.props.frames;
+	    var _props4 = this.props,
+	        frames = _props4.frames,
+	        pause = _props4.pause;
 
 
 	    if (!frames) {
 	      return _react.DOM.div({ className: "pane frames" }, _react.DOM.div({ className: "pane-info empty" }, L10N.getStr("callStack.notPaused")));
 	    }
 
-	    return _react.DOM.div({ className: "pane frames" }, this.renderFrames(frames), this.renderToggleButton(frames));
+	    return _react.DOM.div({ className: "pane frames" }, this.renderFrames(frames), (0, _WhyPaused2.default)({ pause }), this.renderToggleButton(frames));
 	  }
 	}
 
 	Frames.propTypes = {
 	  frames: _react.PropTypes.array,
 	  frameworkGroupingOn: _react.PropTypes.bool.isRequired,
 	  toggleFrameworkGrouping: _react.PropTypes.func.isRequired,
 	  selectedFrame: _react.PropTypes.object,
 	  selectFrame: _react.PropTypes.func.isRequired,
-	  toggleBlackBox: _react.PropTypes.func
+	  toggleBlackBox: _react.PropTypes.func,
+	  pause: _react.PropTypes.object
 	};
 
 	Frames.displayName = "Frames";
 
 	function getSourceForFrame(sources, frame) {
 	  return (0, _selectors.getSourceInSources)(sources, frame.location.sourceId);
 	}
 
@@ -47383,17 +47567,18 @@ return /******/ (function(modules) { // 
 	  return processedFrames;
 	}
 
 	var getAndProcessFramesSelector = (0, _reselect.createSelector)(_selectors.getFrames, _selectors.getSources, getAndProcessFrames);
 
 	exports.default = (0, _reactRedux.connect)(state => ({
 	  frames: getAndProcessFramesSelector(state),
 	  frameworkGroupingOn: (0, _selectors.getFrameworkGroupingState)(state),
-	  selectedFrame: (0, _selectors.getSelectedFrame)(state)
+	  selectedFrame: (0, _selectors.getSelectedFrame)(state),
+	  pause: (0, _selectors.getPause)(state)
 	}), dispatch => (0, _redux.bindActionCreators)(_actions2.default, dispatch))(Frames);
 
 /***/ },
 /* 1013 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
@@ -47572,16 +47757,24 @@ return /******/ (function(modules) { // 
 	  );
 	}
 
 	function isExtJs(frame) {
 	  return (/\/ext-all[\.\-]/.test(getFrameUrl(frame))
 	  );
 	}
 
+	function isUnderscore(frame) {
+	  return getFrameUrl(frame).match(/underscore/i);
+	}
+
+	function isLodash(frame) {
+	  return getFrameUrl(frame).match(/lodash/i);
+	}
+
 	function getLibraryFromUrl(frame) {
 	  // @TODO each of these fns calls getFrameUrl, just call it once
 	  // (assuming there's not more complex logic to identify a lib)
 
 	  if (isBackbone(frame)) {
 	    return "Backbone";
 	  }
 
@@ -47607,16 +47800,24 @@ return /******/ (function(modules) { // 
 
 	  if (isPug(frame)) {
 	    return "Pug";
 	  }
 
 	  if (isExtJs(frame)) {
 	    return "ExtJS";
 	  }
+
+	  if (isUnderscore(frame)) {
+	    return "Underscore";
+	  }
+
+	  if (isLodash(frame)) {
+	    return "Lodash";
+	  }
 	}
 
 	var displayNameMap = {
 	  Backbone: {
 	    "extend/child": "Create Class",
 	    ".create": "Create Model"
 	  },
 	  jQuery: {
@@ -48255,17 +48456,17107 @@ return /******/ (function(modules) { // 
 	  var copyStackTraceItem = copyStackTraceElement(callbacks.copyStackTrace);
 
 	  menuOptions.push(copyStackTraceItem);
 
 	  (0, _devtoolsLaunchpad.showMenu)(event, menuOptions);
 	}
 
 /***/ },
-/* 1033 */,
+/* 1033 */
+/***/ function(module, exports, __webpack_require__) {
+
+	var __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(global, module) {/**
+	 * @license
+	 * Lodash <https://lodash.com/>
+	 * Copyright JS Foundation and other contributors <https://js.foundation/>
+	 * Released under MIT license <https://lodash.com/license>
+	 * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+	 * 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.4';
+
+	  /** 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.7976931348623157e+308,
+	      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*$/,
+	      reLeadingDot = /^\./,
+	      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)',
+	      rsOrdUpper = '\\d*(?:(?:1ST|2ND|3RD|(?![123])\\dTH)\\b)',
+	      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 = {
+	    '&': '&amp;',
+	    '<': '&lt;',
+	    '>': '&gt;',
+	    '"': '&quot;',
+	    "'": '&#39;'
+	  };
+
+	  /** Used to map HTML entities to characters. */
+	  var htmlUnescapes = {
+	    '&amp;': '&',
+	    '&lt;': '<',
+	    '&gt;': '>',
+	    '&quot;': '"',
+	    '&#39;': "'"
+	  };
+
+	  /** 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 {
+	      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;
+
+	  /*--------------------------------------------------------------------------*/
+
+	  /**
+	   * Adds the key-value `pair` to `map`.
+	   *
+	   * @private
+	   * @param {Object} map The map to modify.
+	   * @param {Array} pair The key-value pair to add.
+	   * @returns {Object} Returns `map`.
+	   */
+	  function addMapEntry(map, pair) {
+	    // Don't return `map.set` because it's not chainable in IE 11.
+	    map.set(pair[0], pair[1]);
+	    return map;
+	  }
+
+	  /**
+	   * Adds `value` to `set`.
+	   *
+	   * @private
+	   * @param {Object} set The set to modify.
+	   * @param {*} value The value to add.
+	   * @returns {Object} Returns `set`.
+	   */
+	  function addSetEntry(set, value) {
+	    // Don't return `set.add` because it's not chainable in IE 11.
+	    set.add(value);
+	    return set;
+	  }
+
+	  /**
+	   * 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;
+	  }
+
+	  /**
+	   * 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, baseClone, 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);
+
+	      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(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 = object[key],
+	          srcValue = 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 `map`.
+	     *
+	     * @private
+	     * @param {Object} map The map to clone.
+	     * @param {Function} cloneFunc The function to clone values.
+	     * @param {boolean} [isDeep] Specify a deep clone.
+	     * @returns {Object} Returns the cloned map.
+	     */
+	    function cloneMap(map, isDeep, cloneFunc) {
+	      var array = isDeep ? cloneFunc(mapToArray(map), CLONE_DEEP_FLAG) : mapToArray(map);
+	      return arrayReduce(array, addMapEntry, new map.constructor);
+	    }
+
+	    /**
+	     * 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 `set`.
+	     *
+	     * @private
+	     * @param {Object} set The set to clone.
+	     * @param {Function} cloneFunc The function to clone values.
+	     * @param {boolean} [isDeep] Specify a deep clone.
+	     * @returns {Object} Returns the cloned set.
+	     */
+	    function cloneSet(set, isDeep, cloneFunc) {
+	      var array = isDeep ? cloneFunc(setToArray(set), CLONE_DEEP_FLAG) : setToArray(set);
+	      return arrayReduce(array, addSetEntry, new set.constructor);
+	    }
+
+	    /**
+	     * 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;
+	    }
+
+	    /**