Bug 1386525 - devtools reps: update bundle to v0.12.0. r=bgrins draft
authorNicolas Chevobbe <nchevobbe@mozilla.com>
Tue, 08 Aug 2017 14:43:27 +0200
changeset 642584 91163a226eaada796b884b6a8e7a0b4887b65e1d
parent 642518 a921bfb8a2cf3db4d9edebe9b35799a3f9d035da
child 725048 a627c55448012f15d702e2ecb5ddb0af198853b7
push id72812
push userbmo:nchevobbe@mozilla.com
push dateTue, 08 Aug 2017 14:38:53 +0000
reviewersbgrins
bugs1386525
milestone57.0a1
Bug 1386525 - devtools reps: update bundle to v0.12.0. r=bgrins A test needed to be fixed since we changed some things in bucketing (proper ellipsis and bucket label fix). MozReview-Commit-ID: HhfJcKOGO2H
devtools/client/shared/components/reps/reps.css
devtools/client/shared/components/reps/reps.js
devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_object_inspector_entries.js
--- a/devtools/client/shared/components/reps/reps.css
+++ b/devtools/client/shared/components/reps/reps.css
@@ -58,16 +58,20 @@
 }
 
 .objectBox-textNode,
 .objectBox-string,
 .objectBox-symbol {
   color: var(--string-color);
 }
 
+.objectBox-string a, .objectBox-string a:visited {
+  color: currentColor;
+}
+
 .objectBox-function,
 .objectBox-stackTrace,
 .objectBox-profile {
   color: var(--object-color);
 }
 
 .objectBox-Location {
   font-style: italic;
@@ -246,16 +250,20 @@ html[dir="rtl"] .arrow svg,
 .arrow svg:-moz-locale-dir(rtl) {
   transform: rotate(90deg);
 }
 
 .arrow.expanded.expanded svg {
   transform: rotate(0deg);
 }
 
-.object-label {
+.object-label, .object-label * {
   color: var(--theme-highlight-blue);
 }
 
+.tree .node .unavailable {
+  color: var(--theme-content-color3);
+}
+
 .lessen {
   opacity: 0.6;
 }
 
--- a/devtools/client/shared/components/reps/reps.js
+++ b/devtools/client/shared/components/reps/reps.js
@@ -2,6864 +2,7089 @@
 	if(typeof exports === 'object' && typeof module === 'object')
 		module.exports = factory(require("devtools/client/shared/vendor/react"));
 	else if(typeof define === 'function' && define.amd)
 		define(["devtools/client/shared/vendor/react"], factory);
 	else {
 		var a = typeof exports === 'object' ? factory(require("devtools/client/shared/vendor/react")) : factory(root["devtools/client/shared/vendor/react"]);
 		for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
 	}
-})(this, function(__WEBPACK_EXTERNAL_MODULE_8__) {
+})(this, function(__WEBPACK_EXTERNAL_MODULE_0__) {
 return /******/ (function(modules) { // webpackBootstrap
 /******/ 	// The module cache
 /******/ 	var installedModules = {};
-
+/******/
 /******/ 	// The require function
 /******/ 	function __webpack_require__(moduleId) {
-
+/******/
 /******/ 		// Check if module is in cache
-/******/ 		if(installedModules[moduleId])
+/******/ 		if(installedModules[moduleId]) {
 /******/ 			return installedModules[moduleId].exports;
-
+/******/ 		}
 /******/ 		// Create a new module (and put it into the cache)
 /******/ 		var module = installedModules[moduleId] = {
-/******/ 			exports: {},
-/******/ 			id: moduleId,
-/******/ 			loaded: false
+/******/ 			i: moduleId,
+/******/ 			l: false,
+/******/ 			exports: {}
 /******/ 		};
-
+/******/
 /******/ 		// Execute the module function
 /******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
-
+/******/
 /******/ 		// Flag the module as loaded
-/******/ 		module.loaded = true;
-
+/******/ 		module.l = true;
+/******/
 /******/ 		// Return the exports of the module
 /******/ 		return module.exports;
 /******/ 	}
-
-
+/******/
+/******/
 /******/ 	// expose the modules object (__webpack_modules__)
 /******/ 	__webpack_require__.m = modules;
-
+/******/
 /******/ 	// expose the module cache
 /******/ 	__webpack_require__.c = installedModules;
-
+/******/
+/******/ 	// define getter function for harmony exports
+/******/ 	__webpack_require__.d = function(exports, name, getter) {
+/******/ 		if(!__webpack_require__.o(exports, name)) {
+/******/ 			Object.defineProperty(exports, name, {
+/******/ 				configurable: false,
+/******/ 				enumerable: true,
+/******/ 				get: getter
+/******/ 			});
+/******/ 		}
+/******/ 	};
+/******/
+/******/ 	// getDefaultExport function for compatibility with non-harmony modules
+/******/ 	__webpack_require__.n = function(module) {
+/******/ 		var getter = module && module.__esModule ?
+/******/ 			function getDefault() { return module['default']; } :
+/******/ 			function getModuleExports() { return module; };
+/******/ 		__webpack_require__.d(getter, 'a', getter);
+/******/ 		return getter;
+/******/ 	};
+/******/
+/******/ 	// Object.prototype.hasOwnProperty.call
+/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
+/******/
 /******/ 	// __webpack_public_path__
 /******/ 	__webpack_require__.p = "/assets/build";
-
+/******/
 /******/ 	// Load entry module and return exports
-/******/ 	return __webpack_require__(0);
+/******/ 	return __webpack_require__(__webpack_require__.s = 26);
 /******/ })
 /************************************************************************/
 /******/ ([
 /* 0 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	const { MODE } = __webpack_require__(1);
-	const { REPS, getRep } = __webpack_require__(2);
-	const ObjectInspector = __webpack_require__(45);
-
-	const {
-	  parseURLEncodedText,
-	  parseURLParams,
-	  maybeEscapePropertyName,
-	  getGripPreviewItems
-	} = __webpack_require__(7);
-
-	module.exports = {
-	  REPS,
-	  getRep,
-	  MODE,
-	  maybeEscapePropertyName,
-	  parseURLEncodedText,
-	  parseURLParams,
-	  getGripPreviewItems,
-	  ObjectInspector
-	};
-
-/***/ },
+/***/ (function(module, exports) {
+
+module.exports = __WEBPACK_EXTERNAL_MODULE_0__;
+
+/***/ }),
 /* 1 */
-/***/ function(module, exports) {
-
-	/* 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 = {
-	  MODE: {
-	    TINY: Symbol("TINY"),
-	    SHORT: Symbol("SHORT"),
-	    LONG: Symbol("LONG")
-	  }
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// Dependencies
+const React = __webpack_require__(0);
+const validProtocols = /^(http|https|ftp|data|javascript|resource|chrome):/i;
+const tokenSplitRegex = /(\s|\'|\"|\\)+/;
+/**
+ * Returns true if the given object is a grip (see RDP protocol)
+ */
+function isGrip(object) {
+  return object && object.actor;
+}
+
+function escapeNewLines(value) {
+  return value.replace(/\r/gm, "\\r").replace(/\n/gm, "\\n");
+}
+
+// Map from character code to the corresponding escape sequence.  \0
+// isn't here because it would require special treatment in some
+// situations.  \b, \f, and \v aren't here because they aren't very
+// common.  \' isn't here because there's no need, we only
+// double-quote strings.
+const escapeMap = {
+  // Tab.
+  9: "\\t",
+  // Newline.
+  0xa: "\\n",
+  // Carriage return.
+  0xd: "\\r",
+  // Quote.
+  0x22: "\\\"",
+  // Backslash.
+  0x5c: "\\\\"
+};
+
+// Regexp that matches any character we might possibly want to escape.
+// Note that we over-match here, because it's difficult to, say, match
+// an unpaired surrogate with a regexp.  The details are worked out by
+// the replacement function; see |escapeString|.
+const escapeRegexp = new RegExp("[" +
+// Quote and backslash.
+"\"\\\\" +
+// Controls.
+"\x00-\x1f" +
+// More controls.
+"\x7f-\x9f" +
+// BOM
+"\ufeff" +
+// Replacement characters and non-characters.
+"\ufffc-\uffff" +
+// Surrogates.
+"\ud800-\udfff" +
+// Mathematical invisibles.
+"\u2061-\u2064" +
+// Line and paragraph separators.
+"\u2028-\u2029" +
+// Private use area.
+"\ue000-\uf8ff" + "]", "g");
+
+/**
+ * Escape a string so that the result is viewable and valid JS.
+ * Control characters, other invisibles, invalid characters,
+ * backslash, and double quotes are escaped.  The resulting string is
+ * surrounded by double quotes.
+ *
+ * @param {String} str
+ *        the input
+ * @param {Boolean} escapeWhitespace
+ *        if true, TAB, CR, and NL characters will be escaped
+ * @return {String} the escaped string
+ */
+function escapeString(str, escapeWhitespace) {
+  return "\"" + str.replace(escapeRegexp, (match, offset) => {
+    let c = match.charCodeAt(0);
+    if (c in escapeMap) {
+      if (!escapeWhitespace && (c === 9 || c === 0xa || c === 0xd)) {
+        return match[0];
+      }
+      return escapeMap[c];
+    }
+    if (c >= 0xd800 && c <= 0xdfff) {
+      // Find the full code point containing the surrogate, with a
+      // special case for a trailing surrogate at the start of the
+      // string.
+      if (c >= 0xdc00 && offset > 0) {
+        --offset;
+      }
+      let codePoint = str.codePointAt(offset);
+      if (codePoint >= 0xd800 && codePoint <= 0xdfff) {
+        // Unpaired surrogate.
+        return "\\u" + codePoint.toString(16);
+      } else if (codePoint >= 0xf0000 && codePoint <= 0x10fffd) {
+        // Private use area.  Because we visit each pair of a such a
+        // character, return the empty string for one half and the
+        // real result for the other, to avoid duplication.
+        if (c <= 0xdbff) {
+          return "\\u{" + codePoint.toString(16) + "}";
+        }
+        return "";
+      }
+      // Other surrogate characters are passed through.
+      return match;
+    }
+    return "\\u" + ("0000" + c.toString(16)).substr(-4);
+  }) + "\"";
+}
+
+/**
+ * Escape a property name, if needed.  "Escaping" in this context
+ * means surrounding the property name with quotes.
+ *
+ * @param {String}
+ *        name the property name
+ * @return {String} either the input, or the input surrounded by
+ *                  quotes, properly quoted in JS syntax.
+ */
+function maybeEscapePropertyName(name) {
+  // Quote the property name if it needs quoting.  This particular
+  // test is an approximation; see
+  // https://mathiasbynens.be/notes/javascript-properties.  However,
+  // the full solution requires a fair amount of Unicode data, and so
+  // let's defer that until either it's important, or the \p regexp
+  // syntax lands, see
+  // https://github.com/tc39/proposal-regexp-unicode-property-escapes.
+  if (!/^\w+$/.test(name)) {
+    name = escapeString(name);
+  }
+  return name;
+}
+
+function cropMultipleLines(text, limit) {
+  return escapeNewLines(cropString(text, limit));
+}
+
+function rawCropString(text, limit, alternativeText) {
+  if (!alternativeText) {
+    alternativeText = "\u2026";
+  }
+
+  // Crop the string only if a limit is actually specified.
+  if (!limit || limit <= 0) {
+    return text;
+  }
+
+  // Set the limit at least to the length of the alternative text
+  // plus one character of the original text.
+  if (limit <= alternativeText.length) {
+    limit = alternativeText.length + 1;
+  }
+
+  let halfLimit = (limit - alternativeText.length) / 2;
+
+  if (text.length > limit) {
+    return text.substr(0, Math.ceil(halfLimit)) + alternativeText + text.substr(text.length - Math.floor(halfLimit));
+  }
+
+  return text;
+}
+
+function cropString(text, limit, alternativeText) {
+  return rawCropString(sanitizeString(text + ""), limit, alternativeText);
+}
+
+function sanitizeString(text) {
+  // Replace all non-printable characters, except of
+  // (horizontal) tab (HT: \x09) and newline (LF: \x0A, CR: \x0D),
+  // with unicode replacement character (u+fffd).
+  // eslint-disable-next-line no-control-regex
+  let re = new RegExp("[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]", "g");
+  return text.replace(re, "\ufffd");
+}
+
+function parseURLParams(url) {
+  url = new URL(url);
+  return parseURLEncodedText(url.searchParams);
+}
+
+function parseURLEncodedText(text) {
+  let params = [];
+
+  // In case the text is empty just return the empty parameters
+  if (text == "") {
+    return params;
+  }
+
+  let searchParams = new URLSearchParams(text);
+  let entries = [...searchParams.entries()];
+  return entries.map(entry => {
+    return {
+      name: entry[0],
+      value: entry[1]
+    };
+  });
+}
+
+function getFileName(url) {
+  let split = splitURLBase(url);
+  return split.name;
+}
+
+function splitURLBase(url) {
+  if (!isDataURL(url)) {
+    return splitURLTrue(url);
+  }
+  return {};
+}
+
+function getURLDisplayString(url) {
+  return cropString(url);
+}
+
+function isDataURL(url) {
+  return url && url.substr(0, 5) == "data:";
+}
+
+function splitURLTrue(url) {
+  const reSplitFile = /(.*?):\/{2,3}([^\/]*)(.*?)([^\/]*?)($|\?.*)/;
+  let m = reSplitFile.exec(url);
+
+  if (!m) {
+    return {
+      name: url,
+      path: url
+    };
+  } else if (m[4] == "" && m[5] == "") {
+    return {
+      protocol: m[1],
+      domain: m[2],
+      path: m[3],
+      name: m[3] != "/" ? m[3] : m[2]
+    };
+  }
+
+  return {
+    protocol: m[1],
+    domain: m[2],
+    path: m[2] + m[3],
+    name: m[4] + m[5]
+  };
+}
+
+/**
+ * Wrap the provided render() method of a rep in a try/catch block that will render a
+ * fallback rep if the render fails.
+ */
+function wrapRender(renderMethod) {
+  const wrappedFunction = function (props) {
+    try {
+      return renderMethod.call(this, props);
+    } catch (e) {
+      console.error(e);
+      return React.DOM.span({
+        className: "objectBox objectBox-failure",
+        title: "This object could not be rendered, " + "please file a bug on bugzilla.mozilla.org"
+      },
+      /* Labels have to be hardcoded for reps, see Bug 1317038. */
+      "Invalid object");
+    }
+  };
+  wrappedFunction.propTypes = renderMethod.propTypes;
+  return wrappedFunction;
+}
+
+/**
+ * Get preview items from a Grip.
+ *
+ * @param {Object} Grip from which we want the preview items
+ * @return {Array} Array of the preview items of the grip, or an empty array
+ *                 if the grip does not have preview items
+ */
+function getGripPreviewItems(grip) {
+  if (!grip) {
+    return [];
+  }
+
+  // Promise resolved value Grip
+  if (grip.promiseState && grip.promiseState.value) {
+    return [grip.promiseState.value];
+  }
+
+  // Array Grip
+  if (grip.preview && grip.preview.items) {
+    return grip.preview.items;
+  }
+
+  // Node Grip
+  if (grip.preview && grip.preview.childNodes) {
+    return grip.preview.childNodes;
+  }
+
+  // Set or Map Grip
+  if (grip.preview && grip.preview.entries) {
+    return grip.preview.entries.reduce((res, entry) => res.concat(entry), []);
+  }
+
+  // Event Grip
+  if (grip.preview && grip.preview.target) {
+    let keys = Object.keys(grip.preview.properties);
+    let values = Object.values(grip.preview.properties);
+    return [grip.preview.target, ...keys, ...values];
+  }
+
+  // RegEx Grip
+  if (grip.displayString) {
+    return [grip.displayString];
+  }
+
+  // Generic Grip
+  if (grip.preview && grip.preview.ownProperties) {
+    let propertiesValues = Object.values(grip.preview.ownProperties).map(property => property.value || property);
+
+    let propertyKeys = Object.keys(grip.preview.ownProperties);
+    propertiesValues = propertiesValues.concat(propertyKeys);
+
+    // ArrayBuffer Grip
+    if (grip.preview.safeGetterValues) {
+      propertiesValues = propertiesValues.concat(Object.values(grip.preview.safeGetterValues).map(property => property.getterValue || property));
+    }
+
+    return propertiesValues;
+  }
+
+  return [];
+}
+
+/**
+ * Get the type of an object.
+ *
+ * @param {Object} Grip from which we want the type.
+ * @param {boolean} noGrip true if the object is not a grip.
+ * @return {boolean}
+ */
+function getGripType(object, noGrip) {
+  let type = typeof object;
+  if (type == "object" && object instanceof String) {
+    type = "string";
+  } else if (object && type == "object" && object.type && noGrip !== true) {
+    type = object.type;
+  }
+
+  if (isGrip(object)) {
+    type = object.class;
+  }
+
+  return type;
+}
+
+/**
+ * Determines whether a grip is a string containing a URL.
+ *
+ * @param string grip
+ *        The grip, which may contain a URL.
+ * @return boolean
+ *         Whether the grip is a string containing a URL.
+ */
+function containsURL(grip) {
+  if (typeof grip !== "string") {
+    return false;
+  }
+
+  let tokens = grip.split(tokenSplitRegex);
+  return tokens.some(isURL);
+}
+
+/**
+ * Determines whether a string token is a valid URL.
+ *
+ * @param string token
+ *        The token.
+ * @return boolean
+ *         Whenther the token is a URL.
+ */
+function isURL(token) {
+  try {
+    if (!validProtocols.test(token)) {
+      return false;
+    }
+    new URL(token);
+    return true;
+  } catch (e) {
+    return false;
+  }
+}
+
+module.exports = {
+  isGrip,
+  isURL,
+  cropString,
+  containsURL,
+  rawCropString,
+  sanitizeString,
+  escapeString,
+  wrapRender,
+  cropMultipleLines,
+  parseURLParams,
+  parseURLEncodedText,
+  getFileName,
+  getURLDisplayString,
+  maybeEscapePropertyName,
+  getGripPreviewItems,
+  getGripType,
+  tokenSplitRegex
+};
+
+/***/ }),
 /* 2 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	__webpack_require__(3);
-	const { isGrip } = __webpack_require__(7);
-
-	// Load all existing rep templates
-	const Undefined = __webpack_require__(9);
-	const Null = __webpack_require__(10);
-	const StringRep = __webpack_require__(11);
-	const LongStringRep = __webpack_require__(12);
-	const Number = __webpack_require__(13);
-	const ArrayRep = __webpack_require__(14);
-	const Obj = __webpack_require__(15);
-	const SymbolRep = __webpack_require__(18);
-	const InfinityRep = __webpack_require__(19);
-	const NaNRep = __webpack_require__(20);
-	const Accessor = __webpack_require__(21);
-
-	// DOM types (grips)
-	const Attribute = __webpack_require__(22);
-	const DateTime = __webpack_require__(23);
-	const Document = __webpack_require__(24);
-	const Event = __webpack_require__(25);
-	const Func = __webpack_require__(26);
-	const PromiseRep = __webpack_require__(27);
-	const RegExp = __webpack_require__(28);
-	const StyleSheet = __webpack_require__(29);
-	const CommentNode = __webpack_require__(30);
-	const ElementNode = __webpack_require__(32);
-	const TextNode = __webpack_require__(37);
-	const ErrorRep = __webpack_require__(38);
-	const Window = __webpack_require__(39);
-	const ObjectWithText = __webpack_require__(40);
-	const ObjectWithURL = __webpack_require__(41);
-	const GripArray = __webpack_require__(42);
-	const GripMap = __webpack_require__(43);
-	const GripMapEntry = __webpack_require__(44);
-	const Grip = __webpack_require__(17);
-
-	// List of all registered template.
-	// XXX there should be a way for extensions to register a new
-	// or modify an existing rep.
-	let reps = [RegExp, StyleSheet, Event, DateTime, CommentNode, ElementNode, TextNode, Attribute, LongStringRep, Func, PromiseRep, ArrayRep, Document, Window, ObjectWithText, ObjectWithURL, ErrorRep, GripArray, GripMap, GripMapEntry, Grip, Undefined, Null, StringRep, Number, SymbolRep, InfinityRep, NaNRep, Accessor];
-
-	/**
-	 * Generic rep that is using for rendering native JS types or an object.
-	 * The right template used for rendering is picked automatically according
-	 * to the current value type. The value must be passed is as 'object'
-	 * property.
-	 */
-	const Rep = function (props) {
-	  let {
-	    object,
-	    defaultRep
-	  } = props;
-	  let rep = getRep(object, defaultRep, props.noGrip);
-	  return rep(props);
-	};
-
-	// Helpers
-
-	/**
-	 * Return a rep object that is responsible for rendering given
-	 * object.
-	 *
-	 * @param object {Object} Object to be rendered in the UI. This
-	 * can be generic JS object as well as a grip (handle to a remote
-	 * debuggee object).
-	 *
-	 * @param defaultObject {React.Component} The default template
-	 * that should be used to render given object if none is found.
-	 *
-	 * @param noGrip {Boolean} If true, will only check reps not made for remote objects.
-	 */
-	function getRep(object, defaultRep = Obj, noGrip = false) {
-	  let type = typeof object;
-	  if (type == "object" && object instanceof String) {
-	    type = "string";
-	  } else if (object && type == "object" && object.type && noGrip !== true) {
-	    type = object.type;
-	  }
-
-	  if (isGrip(object)) {
-	    type = object.class;
-	  }
-
-	  for (let i = 0; i < reps.length; i++) {
-	    let rep = reps[i];
-	    try {
-	      // supportsObject could return weight (not only true/false
-	      // but a number), which would allow to priorities templates and
-	      // support better extensibility.
-	      if (rep.supportsObject(object, type, noGrip)) {
-	        return rep.rep;
-	      }
-	    } catch (err) {
-	      console.error(err);
-	    }
-	  }
-
-	  return defaultRep.rep;
-	}
-
-	module.exports = {
-	  Rep,
-	  REPS: {
-	    Accessor,
-	    ArrayRep,
-	    Attribute,
-	    CommentNode,
-	    DateTime,
-	    Document,
-	    ElementNode,
-	    ErrorRep,
-	    Event,
-	    Func,
-	    Grip,
-	    GripArray,
-	    GripMap,
-	    GripMapEntry,
-	    InfinityRep,
-	    LongStringRep,
-	    NaNRep,
-	    Null,
-	    Number,
-	    Obj,
-	    ObjectWithText,
-	    ObjectWithURL,
-	    PromiseRep,
-	    RegExp,
-	    Rep,
-	    StringRep,
-	    StyleSheet,
-	    SymbolRep,
-	    TextNode,
-	    Undefined,
-	    Window
-	  },
-	  // Exporting for tests
-	  getRep
-	};
-
-/***/ },
+/***/ (function(module, exports) {
+
+/* 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 = {
+  MODE: {
+    TINY: Symbol("TINY"),
+    SHORT: Symbol("SHORT"),
+    LONG: Symbol("LONG")
+  }
+};
+
+/***/ }),
 /* 3 */
-/***/ function(module, exports) {
-
-	// removed by extract-text-webpack-plugin
-
-/***/ },
-/* 4 */,
-/* 5 */,
-/* 6 */,
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+__webpack_require__(27);
+
+// Load all existing rep templates
+const Undefined = __webpack_require__(28);
+const Null = __webpack_require__(29);
+const StringRep = __webpack_require__(16);
+const LongStringRep = __webpack_require__(30);
+const Number = __webpack_require__(31);
+const ArrayRep = __webpack_require__(17);
+const Obj = __webpack_require__(32);
+const SymbolRep = __webpack_require__(33);
+const InfinityRep = __webpack_require__(34);
+const NaNRep = __webpack_require__(35);
+const Accessor = __webpack_require__(36);
+
+// DOM types (grips)
+const Attribute = __webpack_require__(37);
+const DateTime = __webpack_require__(38);
+const Document = __webpack_require__(39);
+const Event = __webpack_require__(40);
+const Func = __webpack_require__(41);
+const PromiseRep = __webpack_require__(42);
+const RegExp = __webpack_require__(43);
+const StyleSheet = __webpack_require__(44);
+const CommentNode = __webpack_require__(45);
+const ElementNode = __webpack_require__(46);
+const TextNode = __webpack_require__(50);
+const ErrorRep = __webpack_require__(51);
+const Window = __webpack_require__(52);
+const ObjectWithText = __webpack_require__(53);
+const ObjectWithURL = __webpack_require__(54);
+const GripArray = __webpack_require__(19);
+const GripMap = __webpack_require__(55);
+const GripMapEntry = __webpack_require__(20);
+const Grip = __webpack_require__(9);
+
+// List of all registered template.
+// XXX there should be a way for extensions to register a new
+// or modify an existing rep.
+let reps = [RegExp, StyleSheet, Event, DateTime, CommentNode, ElementNode, TextNode, Attribute, LongStringRep, Func, PromiseRep, ArrayRep, Document, Window, ObjectWithText, ObjectWithURL, ErrorRep, GripArray, GripMap, GripMapEntry, Grip, Undefined, Null, StringRep, Number, SymbolRep, InfinityRep, NaNRep, Accessor];
+
+/**
+ * Generic rep that is using for rendering native JS types or an object.
+ * The right template used for rendering is picked automatically according
+ * to the current value type. The value must be passed is as 'object'
+ * property.
+ */
+const Rep = function (props) {
+  let {
+    object,
+    defaultRep
+  } = props;
+  let rep = getRep(object, defaultRep, props.noGrip);
+  return rep(props);
+};
+
+// Helpers
+
+/**
+ * Return a rep object that is responsible for rendering given
+ * object.
+ *
+ * @param object {Object} Object to be rendered in the UI. This
+ * can be generic JS object as well as a grip (handle to a remote
+ * debuggee object).
+ *
+ * @param defaultObject {React.Component} The default template
+ * that should be used to render given object if none is found.
+ *
+ * @param noGrip {Boolean} If true, will only check reps not made for remote objects.
+ */
+function getRep(object, defaultRep = Obj, noGrip = false) {
+  for (let i = 0; i < reps.length; i++) {
+    let rep = reps[i];
+    try {
+      // supportsObject could return weight (not only true/false
+      // but a number), which would allow to priorities templates and
+      // support better extensibility.
+      if (rep.supportsObject(object, noGrip)) {
+        return rep.rep;
+      }
+    } catch (err) {
+      console.error(err);
+    }
+  }
+
+  return defaultRep.rep;
+}
+
+module.exports = {
+  Rep,
+  REPS: {
+    Accessor,
+    ArrayRep,
+    Attribute,
+    CommentNode,
+    DateTime,
+    Document,
+    ElementNode,
+    ErrorRep,
+    Event,
+    Func,
+    Grip,
+    GripArray,
+    GripMap,
+    GripMapEntry,
+    InfinityRep,
+    LongStringRep,
+    NaNRep,
+    Null,
+    Number,
+    Obj,
+    ObjectWithText,
+    ObjectWithURL,
+    PromiseRep,
+    RegExp,
+    Rep,
+    StringRep,
+    StyleSheet,
+    SymbolRep,
+    TextNode,
+    Undefined,
+    Window
+  },
+  // Exporting for tests
+  getRep
+};
+
+/***/ }),
+/* 4 */
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// Dependencies
+const React = __webpack_require__(0);
+const {
+  maybeEscapePropertyName,
+  wrapRender
+} = __webpack_require__(1);
+const { MODE } = __webpack_require__(2);
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Property for Obj (local JS objects), Grip (remote JS objects)
+ * and GripMap (remote JS maps and weakmaps) reps.
+ * It's used to render object properties.
+ */
+PropRep.propTypes = {
+  // Property name.
+  name: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.object]).isRequired,
+  // Equal character rendered between property name and value.
+  equal: React.PropTypes.string,
+  // @TODO Change this to Object.values once it's supported in Node's version of V8
+  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
+  onDOMNodeMouseOver: React.PropTypes.func,
+  onDOMNodeMouseOut: React.PropTypes.func,
+  onInspectIconClick: React.PropTypes.func,
+  // Normally a PropRep will quote a property name that isn't valid
+  // when unquoted; but this flag can be used to suppress the
+  // quoting.
+  suppressQuotes: React.PropTypes.bool
+};
+
+/**
+ * Function that given a name, a delimiter and an object returns an array
+ * of React elements representing an object property (e.g. `name: value`)
+ *
+ * @param {Object} props
+ * @return {Array} Array of React elements.
+ */
+function PropRep(props) {
+  const Grip = __webpack_require__(9);
+  const { Rep } = __webpack_require__(3);
+
+  let {
+    name,
+    mode,
+    equal,
+    suppressQuotes
+  } = props;
+
+  let key;
+  // The key can be a simple string, for plain objects,
+  // or another object for maps and weakmaps.
+  if (typeof name === "string") {
+    if (!suppressQuotes) {
+      name = maybeEscapePropertyName(name);
+    }
+    key = span({ "className": "nodeName" }, name);
+  } else {
+    key = Rep(Object.assign({}, props, {
+      className: "nodeName",
+      object: name,
+      mode: mode || MODE.TINY,
+      defaultRep: Grip
+    }));
+  }
+
+  return [key, span({
+    "className": "objectEqual"
+  }, equal), Rep(Object.assign({}, props))];
+}
+
+// Exports from this module
+module.exports = wrapRender(PropRep);
+
+/***/ }),
+/* 5 */
+/***/ (function(module, exports) {
+
+/**
+ * Checks if `value` is classified as an `Array` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an array, else `false`.
+ * @example
+ *
+ * _.isArray([1, 2, 3]);
+ * // => true
+ *
+ * _.isArray(document.body.children);
+ * // => false
+ *
+ * _.isArray('abc');
+ * // => false
+ *
+ * _.isArray(_.noop);
+ * // => false
+ */
+var isArray = Array.isArray;
+
+module.exports = isArray;
+
+
+/***/ }),
+/* 6 */
+/***/ (function(module, exports, __webpack_require__) {
+
+var getNative = __webpack_require__(23);
+
+/* Built-in method references that are verified to be native. */
+var nativeCreate = getNative(Object, 'create');
+
+module.exports = nativeCreate;
+
+
+/***/ }),
 /* 7 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// Dependencies
-	const React = __webpack_require__(8);
-
-	/**
-	 * Returns true if the given object is a grip (see RDP protocol)
-	 */
-	function isGrip(object) {
-	  return object && object.actor;
-	}
-
-	function escapeNewLines(value) {
-	  return value.replace(/\r/gm, "\\r").replace(/\n/gm, "\\n");
-	}
-
-	// Map from character code to the corresponding escape sequence.  \0
-	// isn't here because it would require special treatment in some
-	// situations.  \b, \f, and \v aren't here because they aren't very
-	// common.  \' isn't here because there's no need, we only
-	// double-quote strings.
-	const escapeMap = {
-	  // Tab.
-	  9: "\\t",
-	  // Newline.
-	  0xa: "\\n",
-	  // Carriage return.
-	  0xd: "\\r",
-	  // Quote.
-	  0x22: "\\\"",
-	  // Backslash.
-	  0x5c: "\\\\"
-	};
-
-	// Regexp that matches any character we might possibly want to escape.
-	// Note that we over-match here, because it's difficult to, say, match
-	// an unpaired surrogate with a regexp.  The details are worked out by
-	// the replacement function; see |escapeString|.
-	const escapeRegexp = new RegExp("[" +
-	// Quote and backslash.
-	"\"\\\\" +
-	// Controls.
-	"\x00-\x1f" +
-	// More controls.
-	"\x7f-\x9f" +
-	// BOM
-	"\ufeff" +
-	// Replacement characters and non-characters.
-	"\ufffc-\uffff" +
-	// Surrogates.
-	"\ud800-\udfff" +
-	// Mathematical invisibles.
-	"\u2061-\u2064" +
-	// Line and paragraph separators.
-	"\u2028-\u2029" +
-	// Private use area.
-	"\ue000-\uf8ff" + "]", "g");
-
-	/**
-	 * Escape a string so that the result is viewable and valid JS.
-	 * Control characters, other invisibles, invalid characters,
-	 * backslash, and double quotes are escaped.  The resulting string is
-	 * surrounded by double quotes.
-	 *
-	 * @param {String} str
-	 *        the input
-	 * @param {Boolean} escapeWhitespace
-	 *        if true, TAB, CR, and NL characters will be escaped
-	 * @return {String} the escaped string
-	 */
-	function escapeString(str, escapeWhitespace) {
-	  return "\"" + str.replace(escapeRegexp, (match, offset) => {
-	    let c = match.charCodeAt(0);
-	    if (c in escapeMap) {
-	      if (!escapeWhitespace && (c === 9 || c === 0xa || c === 0xd)) {
-	        return match[0];
-	      }
-	      return escapeMap[c];
-	    }
-	    if (c >= 0xd800 && c <= 0xdfff) {
-	      // Find the full code point containing the surrogate, with a
-	      // special case for a trailing surrogate at the start of the
-	      // string.
-	      if (c >= 0xdc00 && offset > 0) {
-	        --offset;
-	      }
-	      let codePoint = str.codePointAt(offset);
-	      if (codePoint >= 0xd800 && codePoint <= 0xdfff) {
-	        // Unpaired surrogate.
-	        return "\\u" + codePoint.toString(16);
-	      } else if (codePoint >= 0xf0000 && codePoint <= 0x10fffd) {
-	        // Private use area.  Because we visit each pair of a such a
-	        // character, return the empty string for one half and the
-	        // real result for the other, to avoid duplication.
-	        if (c <= 0xdbff) {
-	          return "\\u{" + codePoint.toString(16) + "}";
-	        }
-	        return "";
-	      }
-	      // Other surrogate characters are passed through.
-	      return match;
-	    }
-	    return "\\u" + ("0000" + c.toString(16)).substr(-4);
-	  }) + "\"";
-	}
-
-	/**
-	 * Escape a property name, if needed.  "Escaping" in this context
-	 * means surrounding the property name with quotes.
-	 *
-	 * @param {String}
-	 *        name the property name
-	 * @return {String} either the input, or the input surrounded by
-	 *                  quotes, properly quoted in JS syntax.
-	 */
-	function maybeEscapePropertyName(name) {
-	  // Quote the property name if it needs quoting.  This particular
-	  // test is an approximation; see
-	  // https://mathiasbynens.be/notes/javascript-properties.  However,
-	  // the full solution requires a fair amount of Unicode data, and so
-	  // let's defer that until either it's important, or the \p regexp
-	  // syntax lands, see
-	  // https://github.com/tc39/proposal-regexp-unicode-property-escapes.
-	  if (!/^\w+$/.test(name)) {
-	    name = escapeString(name);
-	  }
-	  return name;
-	}
-
-	function cropMultipleLines(text, limit) {
-	  return escapeNewLines(cropString(text, limit));
-	}
-
-	function rawCropString(text, limit, alternativeText) {
-	  if (!alternativeText) {
-	    alternativeText = "\u2026";
-	  }
-
-	  // Crop the string only if a limit is actually specified.
-	  if (!limit || limit <= 0) {
-	    return text;
-	  }
-
-	  // Set the limit at least to the length of the alternative text
-	  // plus one character of the original text.
-	  if (limit <= alternativeText.length) {
-	    limit = alternativeText.length + 1;
-	  }
-
-	  let halfLimit = (limit - alternativeText.length) / 2;
-
-	  if (text.length > limit) {
-	    return text.substr(0, Math.ceil(halfLimit)) + alternativeText + text.substr(text.length - Math.floor(halfLimit));
-	  }
-
-	  return text;
-	}
-
-	function cropString(text, limit, alternativeText) {
-	  return rawCropString(sanitizeString(text + ""), limit, alternativeText);
-	}
-
-	function sanitizeString(text) {
-	  // Replace all non-printable characters, except of
-	  // (horizontal) tab (HT: \x09) and newline (LF: \x0A, CR: \x0D),
-	  // with unicode replacement character (u+fffd).
-	  // eslint-disable-next-line no-control-regex
-	  let re = new RegExp("[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]", "g");
-	  return text.replace(re, "\ufffd");
-	}
-
-	function parseURLParams(url) {
-	  url = new URL(url);
-	  return parseURLEncodedText(url.searchParams);
-	}
-
-	function parseURLEncodedText(text) {
-	  let params = [];
-
-	  // In case the text is empty just return the empty parameters
-	  if (text == "") {
-	    return params;
-	  }
-
-	  let searchParams = new URLSearchParams(text);
-	  let entries = [...searchParams.entries()];
-	  return entries.map(entry => {
-	    return {
-	      name: entry[0],
-	      value: entry[1]
-	    };
-	  });
-	}
-
-	function getFileName(url) {
-	  let split = splitURLBase(url);
-	  return split.name;
-	}
-
-	function splitURLBase(url) {
-	  if (!isDataURL(url)) {
-	    return splitURLTrue(url);
-	  }
-	  return {};
-	}
-
-	function getURLDisplayString(url) {
-	  return cropString(url);
-	}
-
-	function isDataURL(url) {
-	  return url && url.substr(0, 5) == "data:";
-	}
-
-	function splitURLTrue(url) {
-	  const reSplitFile = /(.*?):\/{2,3}([^\/]*)(.*?)([^\/]*?)($|\?.*)/;
-	  let m = reSplitFile.exec(url);
-
-	  if (!m) {
-	    return {
-	      name: url,
-	      path: url
-	    };
-	  } else if (m[4] == "" && m[5] == "") {
-	    return {
-	      protocol: m[1],
-	      domain: m[2],
-	      path: m[3],
-	      name: m[3] != "/" ? m[3] : m[2]
-	    };
-	  }
-
-	  return {
-	    protocol: m[1],
-	    domain: m[2],
-	    path: m[2] + m[3],
-	    name: m[4] + m[5]
-	  };
-	}
-
-	/**
-	 * Wrap the provided render() method of a rep in a try/catch block that will render a
-	 * fallback rep if the render fails.
-	 */
-	function wrapRender(renderMethod) {
-	  const wrappedFunction = function (props) {
-	    try {
-	      return renderMethod.call(this, props);
-	    } catch (e) {
-	      console.error(e);
-	      return React.DOM.span({
-	        className: "objectBox objectBox-failure",
-	        title: "This object could not be rendered, " + "please file a bug on bugzilla.mozilla.org"
-	      },
-	      /* Labels have to be hardcoded for reps, see Bug 1317038. */
-	      "Invalid object");
-	    }
-	  };
-	  wrappedFunction.propTypes = renderMethod.propTypes;
-	  return wrappedFunction;
-	}
-
-	/**
-	 * Get preview items from a Grip.
-	 *
-	 * @param {Object} Grip from which we want the preview items
-	 * @return {Array} Array of the preview items of the grip, or an empty array
-	 *                 if the grip does not have preview items
-	 */
-	function getGripPreviewItems(grip) {
-	  if (!grip) {
-	    return [];
-	  }
-
-	  // Promise resolved value Grip
-	  if (grip.promiseState && grip.promiseState.value) {
-	    return [grip.promiseState.value];
-	  }
-
-	  // Array Grip
-	  if (grip.preview && grip.preview.items) {
-	    return grip.preview.items;
-	  }
-
-	  // Node Grip
-	  if (grip.preview && grip.preview.childNodes) {
-	    return grip.preview.childNodes;
-	  }
-
-	  // Set or Map Grip
-	  if (grip.preview && grip.preview.entries) {
-	    return grip.preview.entries.reduce((res, entry) => res.concat(entry), []);
-	  }
-
-	  // Event Grip
-	  if (grip.preview && grip.preview.target) {
-	    let keys = Object.keys(grip.preview.properties);
-	    let values = Object.values(grip.preview.properties);
-	    return [grip.preview.target, ...keys, ...values];
-	  }
-
-	  // RegEx Grip
-	  if (grip.displayString) {
-	    return [grip.displayString];
-	  }
-
-	  // Generic Grip
-	  if (grip.preview && grip.preview.ownProperties) {
-	    let propertiesValues = Object.values(grip.preview.ownProperties).map(property => property.value || property);
-
-	    let propertyKeys = Object.keys(grip.preview.ownProperties);
-	    propertiesValues = propertiesValues.concat(propertyKeys);
-
-	    // ArrayBuffer Grip
-	    if (grip.preview.safeGetterValues) {
-	      propertiesValues = propertiesValues.concat(Object.values(grip.preview.safeGetterValues).map(property => property.getterValue || property));
-	    }
-
-	    return propertiesValues;
-	  }
-
-	  return [];
-	}
-
-	module.exports = {
-	  isGrip,
-	  cropString,
-	  rawCropString,
-	  sanitizeString,
-	  escapeString,
-	  wrapRender,
-	  cropMultipleLines,
-	  parseURLParams,
-	  parseURLEncodedText,
-	  getFileName,
-	  getURLDisplayString,
-	  maybeEscapePropertyName,
-	  getGripPreviewItems
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var eq = __webpack_require__(88);
+
+/**
+ * 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;
+}
+
+module.exports = assocIndexOf;
+
+
+/***/ }),
 /* 8 */
-/***/ function(module, exports) {
-
-	module.exports = __WEBPACK_EXTERNAL_MODULE_8__;
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var isKeyable = __webpack_require__(94);
+
+/**
+ * Gets the data for `map`.
+ *
+ * @private
+ * @param {Object} map The map to query.
+ * @param {string} key The reference key.
+ * @returns {*} Returns the map data.
+ */
+function getMapData(map, key) {
+  var data = map.__data__;
+  return isKeyable(key)
+    ? data[typeof key == 'string' ? 'string' : 'hash']
+    : data.map;
+}
+
+module.exports = getMapData;
+
+
+/***/ }),
 /* 9 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// Dependencies
-	const React = __webpack_require__(8);
-
-	const { wrapRender } = __webpack_require__(7);
-
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Renders undefined value
-	 */
-	const Undefined = function () {
-	  return span({ className: "objectBox objectBox-undefined" }, "undefined");
-	};
-
-	function supportsObject(object, type, noGrip = false) {
-	  if (noGrip === true) {
-	    return false;
-	  }
-
-	  return object && object.type && object.type == "undefined" || type == "undefined";
-	}
-
-	// Exports from this module
-
-	module.exports = {
-	  rep: wrapRender(Undefined),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// ReactJS
+const React = __webpack_require__(0);
+// Dependencies
+const {
+  isGrip,
+  wrapRender
+} = __webpack_require__(1);
+const PropRep = __webpack_require__(4);
+const { MODE } = __webpack_require__(2);
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Renders generic grip. Grip is client representation
+ * of remote JS object and is used as an input object
+ * for this rep component.
+ */
+GripRep.propTypes = {
+  object: React.PropTypes.object.isRequired,
+  // @TODO Change this to Object.values once it's supported in Node's version of V8
+  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
+  isInterestingProp: React.PropTypes.func,
+  title: React.PropTypes.string,
+  onDOMNodeMouseOver: React.PropTypes.func,
+  onDOMNodeMouseOut: React.PropTypes.func,
+  onInspectIconClick: React.PropTypes.func,
+  noGrip: React.PropTypes.bool
+};
+
+const DEFAULT_TITLE = "Object";
+
+function GripRep(props) {
+  let {
+    mode = MODE.SHORT,
+    object
+  } = props;
+
+  const config = {
+    "data-link-actor-id": object.actor,
+    className: "objectBox objectBox-object"
+  };
+
+  if (mode === MODE.TINY) {
+    let propertiesLength = getPropertiesLength(object);
+
+    const tinyModeItems = [];
+    if (getTitle(props, object) !== DEFAULT_TITLE) {
+      tinyModeItems.push(getTitleElement(props, object));
+    } else {
+      tinyModeItems.push(span({
+        className: "objectLeftBrace"
+      }, "{"), propertiesLength > 0 ? span({
+        key: "more",
+        className: "more-ellipsis",
+        title: "more…"
+      }, "…") : null, span({
+        className: "objectRightBrace"
+      }, "}"));
+    }
+
+    return span(config, ...tinyModeItems);
+  }
+
+  let propsArray = safePropIterator(props, object, maxLengthMap.get(mode));
+
+  return span(config, getTitleElement(props, object), span({
+    className: "objectLeftBrace"
+  }, " { "), ...propsArray, span({
+    className: "objectRightBrace"
+  }, " }"));
+}
+
+function getTitleElement(props, object) {
+  return span({
+    className: "objectTitle"
+  }, getTitle(props, object));
+}
+
+function getTitle(props, object) {
+  return props.title || object.class || DEFAULT_TITLE;
+}
+
+function getPropertiesLength(object) {
+  let propertiesLength = object.preview && object.preview.ownPropertiesLength ? object.preview.ownPropertiesLength : object.ownPropertyLength;
+
+  if (object.preview && object.preview.safeGetterValues) {
+    propertiesLength += Object.keys(object.preview.safeGetterValues).length;
+  }
+
+  if (object.preview && object.preview.ownSymbols) {
+    propertiesLength += object.preview.ownSymbolsLength;
+  }
+
+  return propertiesLength;
+}
+
+function safePropIterator(props, object, max) {
+  max = typeof max === "undefined" ? maxLengthMap.get(MODE.SHORT) : max;
+  try {
+    return propIterator(props, object, max);
+  } catch (err) {
+    console.error(err);
+  }
+  return [];
+}
+
+function propIterator(props, object, max) {
+  if (object.preview && Object.keys(object.preview).includes("wrappedValue")) {
+    const { Rep } = __webpack_require__(3);
+
+    return [Rep({
+      object: object.preview.wrappedValue,
+      mode: props.mode || MODE.TINY,
+      defaultRep: Grip
+    })];
+  }
+
+  // Property filter. Show only interesting properties to the user.
+  let isInterestingProp = props.isInterestingProp || ((type, value) => {
+    return type == "boolean" || type == "number" || type == "string" && value.length != 0;
+  });
+
+  let properties = object.preview ? object.preview.ownProperties : {};
+  let propertiesLength = getPropertiesLength(object);
+
+  if (object.preview && object.preview.safeGetterValues) {
+    properties = Object.assign({}, properties, object.preview.safeGetterValues);
+  }
+
+  let indexes = getPropIndexes(properties, max, isInterestingProp);
+  if (indexes.length < max && indexes.length < propertiesLength) {
+    // There are not enough props yet. Then add uninteresting props to display them.
+    indexes = indexes.concat(getPropIndexes(properties, max - indexes.length, (t, value, name) => {
+      return !isInterestingProp(t, value, name);
+    }));
+  }
+
+  // The server synthesizes some property names for a Proxy, like
+  // <target> and <handler>; we don't want to quote these because,
+  // as synthetic properties, they appear more natural when
+  // unquoted.
+  const suppressQuotes = object.class === "Proxy";
+  let propsArray = getProps(props, properties, indexes, suppressQuotes);
+
+  // Show symbols.
+  if (object.preview && object.preview.ownSymbols) {
+    const { ownSymbols } = object.preview;
+    const length = max - indexes.length;
+
+    const symbolsProps = ownSymbols.slice(0, length).map(symbolItem => {
+      return PropRep(Object.assign({}, props, {
+        mode: MODE.TINY,
+        name: symbolItem,
+        object: symbolItem.descriptor.value,
+        equal: ": ",
+        defaultRep: Grip,
+        title: null,
+        suppressQuotes
+      }));
+    });
+
+    propsArray.push(...symbolsProps);
+  }
+
+  if (Object.keys(properties).length > max || propertiesLength > max
+  // When the object has non-enumerable properties, we don't have them in the packet,
+  // but we might want to show there's something in the object.
+  || propertiesLength > propsArray.length) {
+    // There are some undisplayed props. Then display "more...".
+    propsArray.push(span({
+      key: "more",
+      className: "more-ellipsis",
+      title: "more…"
+    }, "…"));
+  }
+
+  return unfoldProps(propsArray);
+}
+
+function unfoldProps(items) {
+  return items.reduce((res, item, index) => {
+    if (Array.isArray(item)) {
+      res = res.concat(item);
+    } else {
+      res.push(item);
+    }
+
+    // Interleave commas between elements
+    if (index !== items.length - 1) {
+      res.push(", ");
+    }
+    return res;
+  }, []);
+}
+
+/**
+ * Get props ordered by index.
+ *
+ * @param {Object} componentProps Grip Component props.
+ * @param {Object} properties Properties of the object the Grip describes.
+ * @param {Array} indexes Indexes of properties.
+ * @param {Boolean} suppressQuotes true if we should suppress quotes
+ *                  on property names.
+ * @return {Array} Props.
+ */
+function getProps(componentProps, properties, indexes, suppressQuotes) {
+  // Make indexes ordered by ascending.
+  indexes.sort(function (a, b) {
+    return a - b;
+  });
+
+  const propertiesKeys = Object.keys(properties);
+  return indexes.map(i => {
+    let name = propertiesKeys[i];
+    let value = getPropValue(properties[name]);
+
+    return PropRep(Object.assign({}, componentProps, {
+      mode: MODE.TINY,
+      name,
+      object: value,
+      equal: ": ",
+      defaultRep: Grip,
+      title: null,
+      suppressQuotes
+    }));
+  });
+}
+
+/**
+ * Get the indexes of props in the object.
+ *
+ * @param {Object} properties Props object.
+ * @param {Number} max The maximum length of indexes array.
+ * @param {Function} filter Filter the props you want.
+ * @return {Array} Indexes of interesting props in the object.
+ */
+function getPropIndexes(properties, max, filter) {
+  let indexes = [];
+
+  try {
+    let i = 0;
+    for (let name in properties) {
+      if (indexes.length >= max) {
+        return indexes;
+      }
+
+      // Type is specified in grip's "class" field and for primitive
+      // values use typeof.
+      let value = getPropValue(properties[name]);
+      let type = value.class || typeof value;
+      type = type.toLowerCase();
+
+      if (filter(type, value, name)) {
+        indexes.push(i);
+      }
+      i++;
+    }
+  } catch (err) {
+    console.error(err);
+  }
+  return indexes;
+}
+
+/**
+ * Get the actual value of a property.
+ *
+ * @param {Object} property
+ * @return {Object} Value of the property.
+ */
+function getPropValue(property) {
+  let value = property;
+  if (typeof property === "object") {
+    let keys = Object.keys(property);
+    if (keys.includes("value")) {
+      value = property.value;
+    } else if (keys.includes("getterValue")) {
+      value = property.getterValue;
+    }
+  }
+  return value;
+}
+
+// Registration
+function supportsObject(object, noGrip = false) {
+  if (noGrip === true || !isGrip(object)) {
+    return false;
+  }
+
+  return object.preview ? typeof object.preview.ownProperties !== "undefined" : typeof object.ownPropertyLength !== "undefined";
+}
+
+const maxLengthMap = new Map();
+maxLengthMap.set(MODE.SHORT, 3);
+maxLengthMap.set(MODE.LONG, 10);
+
+// Grip is used in propIterator and has to be defined here.
+let Grip = {
+  rep: wrapRender(GripRep),
+  supportsObject,
+  maxLengthMap
+};
+
+// Exports from this module
+module.exports = Grip;
+
+/***/ }),
 /* 10 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// Dependencies
-	const React = __webpack_require__(8);
-
-	const { wrapRender } = __webpack_require__(7);
-
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Renders null value
-	 */
-	function Null(props) {
-	  return span({ className: "objectBox objectBox-null" }, "null");
-	}
-
-	function supportsObject(object, type, noGrip = false) {
-	  if (noGrip === true) {
-	    return false;
-	  }
-
-	  if (object && object.type && object.type == "null") {
-	    return true;
-	  }
-
-	  return object == null;
-	}
-
-	// Exports from this module
-
-	module.exports = {
-	  rep: wrapRender(Null),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+const React = __webpack_require__(0);
+const InlineSVG = __webpack_require__(47);
+
+const svg = {
+  "arrow": __webpack_require__(48),
+  "open-inspector": __webpack_require__(49)
+};
+
+Svg.propTypes = {
+  className: React.PropTypes.string
+};
+
+function Svg(name, props) {
+  if (!svg[name]) {
+    throw new Error("Unknown SVG: " + name);
+  }
+  let className = name;
+  if (props && props.className) {
+    className = `${name} ${props.className}`;
+  }
+  if (name === "subSettings") {
+    className = "";
+  }
+  props = Object.assign({}, props, { className, src: svg[name] });
+  return React.createElement(InlineSVG, props);
+}
+
+module.exports = Svg;
+
+/***/ }),
 /* 11 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// Dependencies
-	const React = __webpack_require__(8);
-
-	const {
-	  escapeString,
-	  rawCropString,
-	  sanitizeString,
-	  wrapRender
-	} = __webpack_require__(7);
-
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Renders a string. String value is enclosed within quotes.
-	 */
-	StringRep.propTypes = {
-	  useQuotes: React.PropTypes.bool,
-	  escapeWhitespace: React.PropTypes.bool,
-	  style: React.PropTypes.object,
-	  object: React.PropTypes.string.isRequired,
-	  member: React.PropTypes.any,
-	  cropLimit: React.PropTypes.number
-	};
-
-	function StringRep(props) {
-	  let {
-	    cropLimit,
-	    object: text,
-	    member,
-	    style,
-	    useQuotes = true,
-	    escapeWhitespace = true
-	  } = props;
-
-	  let config = { className: "objectBox objectBox-string" };
-	  if (style) {
-	    config.style = style;
-	  }
-
-	  if (useQuotes) {
-	    text = escapeString(text, escapeWhitespace);
-	  } else {
-	    text = sanitizeString(text);
-	  }
-
-	  if ((!member || !member.open) && cropLimit) {
-	    text = rawCropString(text, cropLimit);
-	  }
-
-	  return span(config, text);
-	}
-
-	function supportsObject(object, type) {
-	  return type == "string";
-	}
-
-	// Exports from this module
-
-	module.exports = {
-	  rep: wrapRender(StringRep),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var baseGetTag = __webpack_require__(12),
+    isObjectLike = __webpack_require__(15);
+
+/** `Object#toString` result references. */
+var symbolTag = '[object Symbol]';
+
+/**
+ * Checks if `value` is classified as a `Symbol` primitive or object.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
+ * @example
+ *
+ * _.isSymbol(Symbol.iterator);
+ * // => true
+ *
+ * _.isSymbol('abc');
+ * // => false
+ */
+function isSymbol(value) {
+  return typeof value == 'symbol' ||
+    (isObjectLike(value) && baseGetTag(value) == symbolTag);
+}
+
+module.exports = isSymbol;
+
+
+/***/ }),
 /* 12 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// Dependencies
-	const React = __webpack_require__(8);
-	const {
-	  escapeString,
-	  sanitizeString,
-	  isGrip,
-	  wrapRender
-	} = __webpack_require__(7);
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Renders a long string grip.
-	 */
-	LongStringRep.propTypes = {
-	  useQuotes: React.PropTypes.bool,
-	  escapeWhitespace: React.PropTypes.bool,
-	  style: React.PropTypes.object,
-	  cropLimit: React.PropTypes.number.isRequired,
-	  member: React.PropTypes.string,
-	  object: React.PropTypes.object.isRequired
-	};
-
-	function LongStringRep(props) {
-	  let {
-	    cropLimit,
-	    member,
-	    object,
-	    style,
-	    useQuotes = true,
-	    escapeWhitespace = true
-	  } = props;
-	  let { fullText, initial, length } = object;
-
-	  let config = {
-	    "data-link-actor-id": object.actor,
-	    className: "objectBox objectBox-string"
-	  };
-
-	  if (style) {
-	    config.style = style;
-	  }
-
-	  let string = member && member.open ? fullText || initial : initial.substring(0, cropLimit);
-
-	  if (string.length < length) {
-	    string += "\u2026";
-	  }
-	  let formattedString = useQuotes ? escapeString(string, escapeWhitespace) : sanitizeString(string);
-	  return span(config, formattedString);
-	}
-
-	function supportsObject(object, type, noGrip = false) {
-	  if (noGrip === true || !isGrip(object)) {
-	    return false;
-	  }
-	  return object.type === "longString";
-	}
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(LongStringRep),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var Symbol = __webpack_require__(13),
+    getRawTag = __webpack_require__(66),
+    objectToString = __webpack_require__(67);
+
+/** `Object#toString` result references. */
+var nullTag = '[object Null]',
+    undefinedTag = '[object Undefined]';
+
+/** Built-in value references. */
+var symToStringTag = Symbol ? Symbol.toStringTag : undefined;
+
+/**
+ * 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);
+}
+
+module.exports = baseGetTag;
+
+
+/***/ }),
 /* 13 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// Dependencies
-	const React = __webpack_require__(8);
-
-	const { wrapRender } = __webpack_require__(7);
-
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Renders a number
-	 */
-	Number.propTypes = {
-	  object: React.PropTypes.oneOfType([React.PropTypes.object, React.PropTypes.number, React.PropTypes.bool]).isRequired
-	};
-
-	function Number(props) {
-	  let value = props.object;
-
-	  return span({ className: "objectBox objectBox-number" }, stringify(value));
-	}
-
-	function stringify(object) {
-	  let isNegativeZero = Object.is(object, -0) || object.type && object.type == "-0";
-
-	  return isNegativeZero ? "-0" : String(object);
-	}
-
-	function supportsObject(object, type) {
-	  return ["boolean", "number", "-0"].includes(type);
-	}
-
-	// Exports from this module
-
-	module.exports = {
-	  rep: wrapRender(Number),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var root = __webpack_require__(14);
+
+/** Built-in value references. */
+var Symbol = root.Symbol;
+
+module.exports = Symbol;
+
+
+/***/ }),
 /* 14 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// Dependencies
-	const React = __webpack_require__(8);
-	const {
-	  wrapRender
-	} = __webpack_require__(7);
-	const { MODE } = __webpack_require__(1);
-
-	const ModePropType = React.PropTypes.oneOf(
-	// @TODO Change this to Object.values once it's supported in Node's version of V8
-	Object.keys(MODE).map(key => MODE[key]));
-
-	// Shortcuts
-	const DOM = React.DOM;
-
-	/**
-	 * Renders an array. The array is enclosed by left and right bracket
-	 * and the max number of rendered items depends on the current mode.
-	 */
-	ArrayRep.propTypes = {
-	  mode: ModePropType,
-	  object: React.PropTypes.array.isRequired
-	};
-
-	function ArrayRep(props) {
-	  let {
-	    object,
-	    mode = MODE.SHORT
-	  } = props;
-
-	  let items;
-	  let brackets;
-	  let needSpace = function (space) {
-	    return space ? { left: "[ ", right: " ]" } : { left: "[", right: "]" };
-	  };
-
-	  if (mode === MODE.TINY) {
-	    let isEmpty = object.length === 0;
-	    if (isEmpty) {
-	      items = [];
-	    } else {
-	      items = [DOM.span({
-	        className: "more-ellipsis",
-	        title: "more…"
-	      }, "…")];
-	    }
-	    brackets = needSpace(false);
-	  } else {
-	    items = arrayIterator(props, object, maxLengthMap.get(mode));
-	    brackets = needSpace(items.length > 0);
-	  }
-
-	  return DOM.span({
-	    className: "objectBox objectBox-array" }, DOM.span({
-	    className: "arrayLeftBracket"
-	  }, brackets.left), ...items, DOM.span({
-	    className: "arrayRightBracket"
-	  }, brackets.right), DOM.span({
-	    className: "arrayProperties",
-	    role: "group" }));
-	}
-
-	function arrayIterator(props, array, max) {
-	  let items = [];
-	  let delim;
-
-	  for (let i = 0; i < array.length && i < max; i++) {
-	    try {
-	      let value = array[i];
-
-	      delim = i == array.length - 1 ? "" : ", ";
-
-	      items.push(ItemRep({
-	        object: value,
-	        // Hardcode tiny mode to avoid recursive handling.
-	        mode: MODE.TINY,
-	        delim: delim
-	      }));
-	    } catch (exc) {
-	      items.push(ItemRep({
-	        object: exc,
-	        mode: MODE.TINY,
-	        delim: delim
-	      }));
-	    }
-	  }
-
-	  if (array.length > max) {
-	    items.push(DOM.span({
-	      className: "more-ellipsis",
-	      title: "more…"
-	    }, "…"));
-	  }
-
-	  return items;
-	}
-
-	/**
-	 * Renders array item. Individual values are separated by a comma.
-	 */
-	ItemRep.propTypes = {
-	  object: React.PropTypes.any.isRequired,
-	  delim: React.PropTypes.string.isRequired,
-	  mode: ModePropType
-	};
-
-	function ItemRep(props) {
-	  const { Rep } = __webpack_require__(2);
-
-	  let {
-	    object,
-	    delim,
-	    mode
-	  } = props;
-	  return DOM.span({}, Rep({ object: object, mode: mode }), delim);
-	}
-
-	function supportsObject(object, type) {
-	  return Array.isArray(object) || Object.prototype.toString.call(object) === "[object Arguments]";
-	}
-
-	const maxLengthMap = new Map();
-	maxLengthMap.set(MODE.SHORT, 3);
-	maxLengthMap.set(MODE.LONG, 10);
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(ArrayRep),
-	  supportsObject,
-	  maxLengthMap
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var freeGlobal = __webpack_require__(64);
+
+/** 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')();
+
+module.exports = root;
+
+
+/***/ }),
 /* 15 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// Dependencies
-	const React = __webpack_require__(8);
-	const {
-	  wrapRender
-	} = __webpack_require__(7);
-	const PropRep = __webpack_require__(16);
-	const { MODE } = __webpack_require__(1);
-	// Shortcuts
-	const { span } = React.DOM;
-
-	const DEFAULT_TITLE = "Object";
-
-	/**
-	 * Renders an object. An object is represented by a list of its
-	 * properties enclosed in curly brackets.
-	 */
-	ObjectRep.propTypes = {
-	  object: React.PropTypes.object.isRequired,
-	  // @TODO Change this to Object.values once it's supported in Node's version of V8
-	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
-	  title: React.PropTypes.string
-	};
-
-	function ObjectRep(props) {
-	  let object = props.object;
-	  let propsArray = safePropIterator(props, object);
-
-	  if (props.mode === MODE.TINY) {
-	    const tinyModeItems = [];
-	    if (getTitle(props, object) !== DEFAULT_TITLE) {
-	      tinyModeItems.push(getTitleElement(props, object));
-	    } else {
-	      tinyModeItems.push(span({
-	        className: "objectLeftBrace"
-	      }, "{"), propsArray.length > 0 ? span({
-	        key: "more",
-	        className: "more-ellipsis",
-	        title: "more…"
-	      }, "…") : null, span({
-	        className: "objectRightBrace"
-	      }, "}"));
-	    }
-
-	    return span({ className: "objectBox objectBox-object" }, ...tinyModeItems);
-	  }
-
-	  return span({ className: "objectBox objectBox-object" }, getTitleElement(props, object), span({
-	    className: "objectLeftBrace"
-	  }, " { "), ...propsArray, span({
-	    className: "objectRightBrace"
-	  }, " }"));
-	}
-
-	function getTitleElement(props, object) {
-	  return span({ className: "objectTitle" }, getTitle(props, object));
-	}
-
-	function getTitle(props, object) {
-	  return props.title || object.class || DEFAULT_TITLE;
-	}
-
-	function safePropIterator(props, object, max) {
-	  max = typeof max === "undefined" ? 3 : max;
-	  try {
-	    return propIterator(props, object, max);
-	  } catch (err) {
-	    console.error(err);
-	  }
-	  return [];
-	}
-
-	function propIterator(props, object, max) {
-	  let isInterestingProp = (type, value) => {
-	    // Do not pick objects, it could cause recursion.
-	    return type == "boolean" || type == "number" || type == "string" && value;
-	  };
-
-	  // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=945377
-	  if (Object.prototype.toString.call(object) === "[object Generator]") {
-	    object = Object.getPrototypeOf(object);
-	  }
-
-	  // Object members with non-empty values are preferred since it gives the
-	  // user a better overview of the object.
-	  let interestingObject = getFilteredObject(object, max, isInterestingProp);
-
-	  if (Object.keys(interestingObject).length < max) {
-	    // There are not enough props yet (or at least, not enough props to
-	    // be able to know whether we should print "more…" or not).
-	    // Let's display also empty members and functions.
-	    interestingObject = Object.assign({}, interestingObject, getFilteredObject(object, max - Object.keys(interestingObject).length, (type, value) => !isInterestingProp(type, value)));
-	  }
-
-	  let propsArray = getPropsArray(interestingObject);
-	  if (Object.keys(object).length > max) {
-	    propsArray.push(span({
-	      className: "more-ellipsis",
-	      title: "more…"
-	    }, "…"));
-	  }
-
-	  return unfoldProps(propsArray);
-	}
-
-	function unfoldProps(items) {
-	  return items.reduce((res, item, index) => {
-	    if (Array.isArray(item)) {
-	      res = res.concat(item);
-	    } else {
-	      res.push(item);
-	    }
-
-	    // Interleave commas between elements
-	    if (index !== items.length - 1) {
-	      res.push(", ");
-	    }
-	    return res;
-	  }, []);
-	}
-
-	/**
-	 * Get an array of components representing the properties of the object
-	 *
-	 * @param {Object} object
-	 * @return {Array} Array of PropRep.
-	 */
-	function getPropsArray(object) {
-	  let propsArray = [];
-
-	  if (!object) {
-	    return propsArray;
-	  }
-
-	  // Hardcode tiny mode to avoid recursive handling.
-	  let mode = MODE.TINY;
-	  const objectKeys = Object.keys(object);
-	  return objectKeys.map((name, i) => PropRep({
-	    mode,
-	    name,
-	    object: object[name],
-	    equal: ": "
-	  }));
-	}
-
-	/**
-	 * Get a copy of the object filtered by a given predicate.
-	 *
-	 * @param {Object} object.
-	 * @param {Number} max The maximum length of keys array.
-	 * @param {Function} filter Filter the props you want.
-	 * @return {Object} the filtered object.
-	 */
-	function getFilteredObject(object, max, filter) {
-	  let filteredObject = {};
-
-	  try {
-	    for (let name in object) {
-	      if (Object.keys(filteredObject).length >= max) {
-	        return filteredObject;
-	      }
-
-	      let value;
-	      try {
-	        value = object[name];
-	      } catch (exc) {
-	        continue;
-	      }
-
-	      let t = typeof value;
-	      if (filter(t, value)) {
-	        filteredObject[name] = value;
-	      }
-	    }
-	  } catch (err) {
-	    console.error(err);
-	  }
-	  return filteredObject;
-	}
-
-	function supportsObject(object, type) {
-	  return true;
-	}
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(ObjectRep),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports) {
+
+/**
+ * Checks if `value` is object-like. A value is object-like if it's not `null`
+ * and has a `typeof` result of "object".
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ * @example
+ *
+ * _.isObjectLike({});
+ * // => true
+ *
+ * _.isObjectLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isObjectLike(_.noop);
+ * // => false
+ *
+ * _.isObjectLike(null);
+ * // => false
+ */
+function isObjectLike(value) {
+  return value != null && typeof value == 'object';
+}
+
+module.exports = isObjectLike;
+
+
+/***/ }),
 /* 16 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// Dependencies
-	const React = __webpack_require__(8);
-	const {
-	  maybeEscapePropertyName,
-	  wrapRender
-	} = __webpack_require__(7);
-	const { MODE } = __webpack_require__(1);
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Property for Obj (local JS objects), Grip (remote JS objects)
-	 * and GripMap (remote JS maps and weakmaps) reps.
-	 * It's used to render object properties.
-	 */
-	PropRep.propTypes = {
-	  // Property name.
-	  name: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.object]).isRequired,
-	  // Equal character rendered between property name and value.
-	  equal: React.PropTypes.string,
-	  // @TODO Change this to Object.values once it's supported in Node's version of V8
-	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
-	  onDOMNodeMouseOver: React.PropTypes.func,
-	  onDOMNodeMouseOut: React.PropTypes.func,
-	  onInspectIconClick: React.PropTypes.func,
-	  // Normally a PropRep will quote a property name that isn't valid
-	  // when unquoted; but this flag can be used to suppress the
-	  // quoting.
-	  suppressQuotes: React.PropTypes.bool
-	};
-
-	/**
-	 * Function that given a name, a delimiter and an object returns an array
-	 * of React elements representing an object property (e.g. `name: value`)
-	 *
-	 * @param {Object} props
-	 * @return {Array} Array of React elements.
-	 */
-	function PropRep(props) {
-	  const Grip = __webpack_require__(17);
-	  const { Rep } = __webpack_require__(2);
-
-	  let {
-	    name,
-	    mode,
-	    equal,
-	    suppressQuotes
-	  } = props;
-
-	  let key;
-	  // The key can be a simple string, for plain objects,
-	  // or another object for maps and weakmaps.
-	  if (typeof name === "string") {
-	    if (!suppressQuotes) {
-	      name = maybeEscapePropertyName(name);
-	    }
-	    key = span({ "className": "nodeName" }, name);
-	  } else {
-	    key = Rep(Object.assign({}, props, {
-	      className: "nodeName",
-	      object: name,
-	      mode: mode || MODE.TINY,
-	      defaultRep: Grip
-	    }));
-	  }
-
-	  return [key, span({
-	    "className": "objectEqual"
-	  }, equal), Rep(Object.assign({}, props))];
-	}
-
-	// Exports from this module
-	module.exports = wrapRender(PropRep);
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// Dependencies
+const React = __webpack_require__(0);
+
+const {
+  containsURL,
+  isURL,
+  escapeString,
+  getGripType,
+  rawCropString,
+  sanitizeString,
+  wrapRender,
+  tokenSplitRegex
+} = __webpack_require__(1);
+
+// Shortcuts
+const { a, span } = React.DOM;
+
+/**
+ * Renders a string. String value is enclosed within quotes.
+ */
+StringRep.propTypes = {
+  useQuotes: React.PropTypes.bool,
+  escapeWhitespace: React.PropTypes.bool,
+  style: React.PropTypes.object,
+  object: React.PropTypes.string.isRequired,
+  member: React.PropTypes.any,
+  cropLimit: React.PropTypes.number,
+  openLink: React.PropTypes.func
+};
+
+function StringRep(props) {
+  let {
+    cropLimit,
+    object: text,
+    member,
+    style,
+    useQuotes = true,
+    escapeWhitespace = true,
+    openLink
+  } = props;
+
+  let config = { className: "objectBox objectBox-string" };
+  if (style) {
+    config.style = style;
+  }
+
+  if (useQuotes) {
+    text = escapeString(text, escapeWhitespace);
+  } else {
+    text = sanitizeString(text);
+  }
+
+  if ((!member || !member.open) && cropLimit) {
+    text = rawCropString(text, cropLimit);
+  }
+
+  if (!containsURL(text)) {
+    return span(config, text);
+  }
+
+  const items = [];
+
+  // As we walk through the tokens of the source string, we make sure to preserve
+  // the original whitespace that separated the tokens.
+  let tokens = text.split(tokenSplitRegex);
+  let textIndex = 0;
+  let tokenStart;
+  tokens.forEach((token, i) => {
+    tokenStart = text.indexOf(token, textIndex);
+    if (isURL(token)) {
+      items.push(text.slice(textIndex, tokenStart));
+      textIndex = tokenStart + token.length;
+
+      items.push(a({
+        className: "url",
+        title: token,
+        href: token,
+        draggable: false,
+        onClick: openLink ? () => openLink(token) : null
+      }, token));
+    }
+  });
+
+  // Clean up any non-URL text at the end of the source string.
+  items.push(text.slice(textIndex, text.length));
+  return span(config, ...items);
+}
+
+function supportsObject(object, noGrip = false) {
+  return getGripType(object, noGrip) == "string";
+}
+
+// Exports from this module
+
+module.exports = {
+  rep: wrapRender(StringRep),
+  supportsObject
+};
+
+/***/ }),
 /* 17 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// ReactJS
-	const React = __webpack_require__(8);
-	// Dependencies
-	const {
-	  isGrip,
-	  wrapRender
-	} = __webpack_require__(7);
-	const PropRep = __webpack_require__(16);
-	const { MODE } = __webpack_require__(1);
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Renders generic grip. Grip is client representation
-	 * of remote JS object and is used as an input object
-	 * for this rep component.
-	 */
-	GripRep.propTypes = {
-	  object: React.PropTypes.object.isRequired,
-	  // @TODO Change this to Object.values once it's supported in Node's version of V8
-	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
-	  isInterestingProp: React.PropTypes.func,
-	  title: React.PropTypes.string,
-	  onDOMNodeMouseOver: React.PropTypes.func,
-	  onDOMNodeMouseOut: React.PropTypes.func,
-	  onInspectIconClick: React.PropTypes.func,
-	  noGrip: React.PropTypes.bool
-	};
-
-	const DEFAULT_TITLE = "Object";
-
-	function GripRep(props) {
-	  let {
-	    mode = MODE.SHORT,
-	    object
-	  } = props;
-
-	  const config = {
-	    "data-link-actor-id": object.actor,
-	    className: "objectBox objectBox-object"
-	  };
-
-	  if (mode === MODE.TINY) {
-	    let propertiesLength = getPropertiesLength(object);
-
-	    const tinyModeItems = [];
-	    if (getTitle(props, object) !== DEFAULT_TITLE) {
-	      tinyModeItems.push(getTitleElement(props, object));
-	    } else {
-	      tinyModeItems.push(span({
-	        className: "objectLeftBrace"
-	      }, "{"), propertiesLength > 0 ? span({
-	        key: "more",
-	        className: "more-ellipsis",
-	        title: "more…"
-	      }, "…") : null, span({
-	        className: "objectRightBrace"
-	      }, "}"));
-	    }
-
-	    return span(config, ...tinyModeItems);
-	  }
-
-	  let propsArray = safePropIterator(props, object, maxLengthMap.get(mode));
-
-	  return span(config, getTitleElement(props, object), span({
-	    className: "objectLeftBrace"
-	  }, " { "), ...propsArray, span({
-	    className: "objectRightBrace"
-	  }, " }"));
-	}
-
-	function getTitleElement(props, object) {
-	  return span({
-	    className: "objectTitle"
-	  }, getTitle(props, object));
-	}
-
-	function getTitle(props, object) {
-	  return props.title || object.class || DEFAULT_TITLE;
-	}
-
-	function getPropertiesLength(object) {
-	  let propertiesLength = object.preview && object.preview.ownPropertiesLength ? object.preview.ownPropertiesLength : object.ownPropertyLength;
-
-	  if (object.preview && object.preview.safeGetterValues) {
-	    propertiesLength += Object.keys(object.preview.safeGetterValues).length;
-	  }
-
-	  if (object.preview && object.preview.ownSymbols) {
-	    propertiesLength += object.preview.ownSymbolsLength;
-	  }
-
-	  return propertiesLength;
-	}
-
-	function safePropIterator(props, object, max) {
-	  max = typeof max === "undefined" ? maxLengthMap.get(MODE.SHORT) : max;
-	  try {
-	    return propIterator(props, object, max);
-	  } catch (err) {
-	    console.error(err);
-	  }
-	  return [];
-	}
-
-	function propIterator(props, object, max) {
-	  if (object.preview && Object.keys(object.preview).includes("wrappedValue")) {
-	    const { Rep } = __webpack_require__(2);
-
-	    return [Rep({
-	      object: object.preview.wrappedValue,
-	      mode: props.mode || MODE.TINY,
-	      defaultRep: Grip
-	    })];
-	  }
-
-	  // Property filter. Show only interesting properties to the user.
-	  let isInterestingProp = props.isInterestingProp || ((type, value) => {
-	    return type == "boolean" || type == "number" || type == "string" && value.length != 0;
-	  });
-
-	  let properties = object.preview ? object.preview.ownProperties : {};
-	  let propertiesLength = getPropertiesLength(object);
-
-	  if (object.preview && object.preview.safeGetterValues) {
-	    properties = Object.assign({}, properties, object.preview.safeGetterValues);
-	  }
-
-	  let indexes = getPropIndexes(properties, max, isInterestingProp);
-	  if (indexes.length < max && indexes.length < propertiesLength) {
-	    // There are not enough props yet. Then add uninteresting props to display them.
-	    indexes = indexes.concat(getPropIndexes(properties, max - indexes.length, (t, value, name) => {
-	      return !isInterestingProp(t, value, name);
-	    }));
-	  }
-
-	  // The server synthesizes some property names for a Proxy, like
-	  // <target> and <handler>; we don't want to quote these because,
-	  // as synthetic properties, they appear more natural when
-	  // unquoted.
-	  const suppressQuotes = object.class === "Proxy";
-	  let propsArray = getProps(props, properties, indexes, suppressQuotes);
-
-	  // Show symbols.
-	  if (object.preview && object.preview.ownSymbols) {
-	    const { ownSymbols } = object.preview;
-	    const length = max - indexes.length;
-
-	    const symbolsProps = ownSymbols.slice(0, length).map(symbolItem => {
-	      return PropRep(Object.assign({}, props, {
-	        mode: MODE.TINY,
-	        name: symbolItem,
-	        object: symbolItem.descriptor.value,
-	        equal: ": ",
-	        defaultRep: Grip,
-	        title: null,
-	        suppressQuotes
-	      }));
-	    });
-
-	    propsArray.push(...symbolsProps);
-	  }
-
-	  if (Object.keys(properties).length > max || propertiesLength > max
-	  // When the object has non-enumerable properties, we don't have them in the packet,
-	  // but we might want to show there's something in the object.
-	  || propertiesLength > propsArray.length) {
-	    // There are some undisplayed props. Then display "more...".
-	    propsArray.push(span({
-	      key: "more",
-	      className: "more-ellipsis",
-	      title: "more…"
-	    }, "…"));
-	  }
-
-	  return unfoldProps(propsArray);
-	}
-
-	function unfoldProps(items) {
-	  return items.reduce((res, item, index) => {
-	    if (Array.isArray(item)) {
-	      res = res.concat(item);
-	    } else {
-	      res.push(item);
-	    }
-
-	    // Interleave commas between elements
-	    if (index !== items.length - 1) {
-	      res.push(", ");
-	    }
-	    return res;
-	  }, []);
-	}
-
-	/**
-	 * Get props ordered by index.
-	 *
-	 * @param {Object} componentProps Grip Component props.
-	 * @param {Object} properties Properties of the object the Grip describes.
-	 * @param {Array} indexes Indexes of properties.
-	 * @param {Boolean} suppressQuotes true if we should suppress quotes
-	 *                  on property names.
-	 * @return {Array} Props.
-	 */
-	function getProps(componentProps, properties, indexes, suppressQuotes) {
-	  // Make indexes ordered by ascending.
-	  indexes.sort(function (a, b) {
-	    return a - b;
-	  });
-
-	  const propertiesKeys = Object.keys(properties);
-	  return indexes.map(i => {
-	    let name = propertiesKeys[i];
-	    let value = getPropValue(properties[name]);
-
-	    return PropRep(Object.assign({}, componentProps, {
-	      mode: MODE.TINY,
-	      name,
-	      object: value,
-	      equal: ": ",
-	      defaultRep: Grip,
-	      title: null,
-	      suppressQuotes
-	    }));
-	  });
-	}
-
-	/**
-	 * Get the indexes of props in the object.
-	 *
-	 * @param {Object} properties Props object.
-	 * @param {Number} max The maximum length of indexes array.
-	 * @param {Function} filter Filter the props you want.
-	 * @return {Array} Indexes of interesting props in the object.
-	 */
-	function getPropIndexes(properties, max, filter) {
-	  let indexes = [];
-
-	  try {
-	    let i = 0;
-	    for (let name in properties) {
-	      if (indexes.length >= max) {
-	        return indexes;
-	      }
-
-	      // Type is specified in grip's "class" field and for primitive
-	      // values use typeof.
-	      let value = getPropValue(properties[name]);
-	      let type = value.class || typeof value;
-	      type = type.toLowerCase();
-
-	      if (filter(type, value, name)) {
-	        indexes.push(i);
-	      }
-	      i++;
-	    }
-	  } catch (err) {
-	    console.error(err);
-	  }
-	  return indexes;
-	}
-
-	/**
-	 * Get the actual value of a property.
-	 *
-	 * @param {Object} property
-	 * @return {Object} Value of the property.
-	 */
-	function getPropValue(property) {
-	  let value = property;
-	  if (typeof property === "object") {
-	    let keys = Object.keys(property);
-	    if (keys.includes("value")) {
-	      value = property.value;
-	    } else if (keys.includes("getterValue")) {
-	      value = property.getterValue;
-	    }
-	  }
-	  return value;
-	}
-
-	// Registration
-	function supportsObject(object, type, noGrip = false) {
-	  if (noGrip === true || !isGrip(object)) {
-	    return false;
-	  }
-
-	  return object.preview ? typeof object.preview.ownProperties !== "undefined" : typeof object.ownPropertyLength !== "undefined";
-	}
-
-	const maxLengthMap = new Map();
-	maxLengthMap.set(MODE.SHORT, 3);
-	maxLengthMap.set(MODE.LONG, 10);
-
-	// Grip is used in propIterator and has to be defined here.
-	let Grip = {
-	  rep: wrapRender(GripRep),
-	  supportsObject,
-	  maxLengthMap
-	};
-
-	// Exports from this module
-	module.exports = Grip;
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// Dependencies
+const React = __webpack_require__(0);
+const {
+  wrapRender
+} = __webpack_require__(1);
+const { MODE } = __webpack_require__(2);
+
+const ModePropType = React.PropTypes.oneOf(
+// @TODO Change this to Object.values once it's supported in Node's version of V8
+Object.keys(MODE).map(key => MODE[key]));
+
+// Shortcuts
+const DOM = React.DOM;
+
+/**
+ * Renders an array. The array is enclosed by left and right bracket
+ * and the max number of rendered items depends on the current mode.
+ */
+ArrayRep.propTypes = {
+  mode: ModePropType,
+  object: React.PropTypes.array.isRequired
+};
+
+function ArrayRep(props) {
+  let {
+    object,
+    mode = MODE.SHORT
+  } = props;
+
+  let items;
+  let brackets;
+  let needSpace = function (space) {
+    return space ? { left: "[ ", right: " ]" } : { left: "[", right: "]" };
+  };
+
+  if (mode === MODE.TINY) {
+    let isEmpty = object.length === 0;
+    if (isEmpty) {
+      items = [];
+    } else {
+      items = [DOM.span({
+        className: "more-ellipsis",
+        title: "more…"
+      }, "…")];
+    }
+    brackets = needSpace(false);
+  } else {
+    items = arrayIterator(props, object, maxLengthMap.get(mode));
+    brackets = needSpace(items.length > 0);
+  }
+
+  return DOM.span({
+    className: "objectBox objectBox-array" }, DOM.span({
+    className: "arrayLeftBracket"
+  }, brackets.left), ...items, DOM.span({
+    className: "arrayRightBracket"
+  }, brackets.right), DOM.span({
+    className: "arrayProperties",
+    role: "group" }));
+}
+
+function arrayIterator(props, array, max) {
+  let items = [];
+
+  for (let i = 0; i < array.length && i < max; i++) {
+    let config = {
+      mode: MODE.TINY,
+      delim: i == array.length - 1 ? "" : ", "
+    };
+    let item;
+
+    try {
+      item = ItemRep(Object.assign({}, props, config, {
+        object: array[i]
+      }));
+    } catch (exc) {
+      item = ItemRep(Object.assign({}, props, config, {
+        object: exc
+      }));
+    }
+    items.push(item);
+  }
+
+  if (array.length > max) {
+    items.push(DOM.span({
+      className: "more-ellipsis",
+      title: "more…"
+    }, "…"));
+  }
+
+  return items;
+}
+
+/**
+ * Renders array item. Individual values are separated by a comma.
+ */
+ItemRep.propTypes = {
+  object: React.PropTypes.any.isRequired,
+  delim: React.PropTypes.string.isRequired,
+  mode: ModePropType
+};
+
+function ItemRep(props) {
+  const { Rep } = __webpack_require__(3);
+
+  let {
+    object,
+    delim,
+    mode
+  } = props;
+  return DOM.span({}, Rep(Object.assign({}, props, {
+    object: object,
+    mode: mode
+  })), delim);
+}
+
+function supportsObject(object) {
+  return Array.isArray(object) || Object.prototype.toString.call(object) === "[object Arguments]";
+}
+
+const maxLengthMap = new Map();
+maxLengthMap.set(MODE.SHORT, 3);
+maxLengthMap.set(MODE.LONG, 10);
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(ArrayRep),
+  supportsObject,
+  maxLengthMap
+};
+
+/***/ }),
 /* 18 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// Dependencies
-	const React = __webpack_require__(8);
-
-	const { wrapRender } = __webpack_require__(7);
-
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Renders a symbol.
-	 */
-	SymbolRep.propTypes = {
-	  object: React.PropTypes.object.isRequired
-	};
-
-	function SymbolRep(props) {
-	  let {
-	    className = "objectBox objectBox-symbol",
-	    object
-	  } = props;
-	  let { name } = object;
-
-	  return span({ className }, `Symbol(${name || ""})`);
-	}
-
-	function supportsObject(object, type) {
-	  return type == "symbol";
-	}
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(SymbolRep),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports) {
+
+/* 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 = {
+  ELEMENT_NODE: 1,
+  ATTRIBUTE_NODE: 2,
+  TEXT_NODE: 3,
+  CDATA_SECTION_NODE: 4,
+  ENTITY_REFERENCE_NODE: 5,
+  ENTITY_NODE: 6,
+  PROCESSING_INSTRUCTION_NODE: 7,
+  COMMENT_NODE: 8,
+  DOCUMENT_NODE: 9,
+  DOCUMENT_TYPE_NODE: 10,
+  DOCUMENT_FRAGMENT_NODE: 11,
+  NOTATION_NODE: 12,
+
+  // DocumentPosition
+  DOCUMENT_POSITION_DISCONNECTED: 0x01,
+  DOCUMENT_POSITION_PRECEDING: 0x02,
+  DOCUMENT_POSITION_FOLLOWING: 0x04,
+  DOCUMENT_POSITION_CONTAINS: 0x08,
+  DOCUMENT_POSITION_CONTAINED_BY: 0x10,
+  DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: 0x20
+};
+
+/***/ }),
 /* 19 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// Dependencies
-	const React = __webpack_require__(8);
-
-	const { wrapRender } = __webpack_require__(7);
-
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Renders a Infinity object
-	 */
-	InfinityRep.propTypes = {
-	  object: React.PropTypes.object.isRequired
-	};
-
-	function InfinityRep(props) {
-	  const {
-	    object
-	  } = props;
-
-	  return span({ className: "objectBox objectBox-number" }, object.type);
-	}
-
-	function supportsObject(object, type) {
-	  return type == "Infinity" || type == "-Infinity";
-	}
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(InfinityRep),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// Dependencies
+const React = __webpack_require__(0);
+const {
+  getGripType,
+  isGrip,
+  wrapRender
+} = __webpack_require__(1);
+const { MODE } = __webpack_require__(2);
+
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Renders an array. The array is enclosed by left and right bracket
+ * and the max number of rendered items depends on the current mode.
+ */
+GripArray.propTypes = {
+  object: React.PropTypes.object.isRequired,
+  // @TODO Change this to Object.values once it's supported in Node's version of V8
+  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
+  provider: React.PropTypes.object,
+  onDOMNodeMouseOver: React.PropTypes.func,
+  onDOMNodeMouseOut: React.PropTypes.func,
+  onInspectIconClick: React.PropTypes.func
+};
+
+function GripArray(props) {
+  let {
+    object,
+    mode = MODE.SHORT
+  } = props;
+
+  let items;
+  let brackets;
+  let needSpace = function (space) {
+    return space ? { left: "[ ", right: " ]" } : { left: "[", right: "]" };
+  };
+
+  if (mode === MODE.TINY) {
+    let objectLength = getLength(object);
+    let isEmpty = objectLength === 0;
+    if (isEmpty) {
+      items = [];
+    } else {
+      items = [span({
+        className: "more-ellipsis",
+        title: "more…"
+      }, "…")];
+    }
+    brackets = needSpace(false);
+  } else {
+    let max = maxLengthMap.get(mode);
+    items = arrayIterator(props, object, max);
+    brackets = needSpace(items.length > 0);
+  }
+
+  let title = getTitle(props, object);
+
+  return span({
+    "data-link-actor-id": object.actor,
+    className: "objectBox objectBox-array" }, title, span({
+    className: "arrayLeftBracket"
+  }, brackets.left), ...interleaveCommas(items), span({
+    className: "arrayRightBracket"
+  }, brackets.right), span({
+    className: "arrayProperties",
+    role: "group" }));
+}
+
+function interleaveCommas(items) {
+  return items.reduce((res, item, index) => {
+    if (index !== items.length - 1) {
+      return res.concat(item, ", ");
+    }
+    return res.concat(item);
+  }, []);
+}
+
+function getLength(grip) {
+  if (!grip.preview) {
+    return 0;
+  }
+
+  return grip.preview.length || grip.preview.childNodesLength || 0;
+}
+
+function getTitle(props, object) {
+  if (props.mode === MODE.TINY) {
+    return "";
+  }
+
+  let title = props.title || object.class || "Array";
+  return span({
+    className: "objectTitle"
+  }, title + " ");
+}
+
+function getPreviewItems(grip) {
+  if (!grip.preview) {
+    return null;
+  }
+
+  return grip.preview.items || grip.preview.childNodes || [];
+}
+
+function arrayIterator(props, grip, max) {
+  let { Rep } = __webpack_require__(3);
+
+  let items = [];
+  const gripLength = getLength(grip);
+
+  if (!gripLength) {
+    return items;
+  }
+
+  const previewItems = getPreviewItems(grip);
+  let provider = props.provider;
+
+  let emptySlots = 0;
+  let foldedEmptySlots = 0;
+  items = previewItems.reduce((res, itemGrip) => {
+    if (res.length >= max) {
+      return res;
+    }
+
+    let object;
+    try {
+      if (!provider && itemGrip === null) {
+        emptySlots++;
+        return res;
+      }
+
+      object = provider ? provider.getValue(itemGrip) : itemGrip;
+    } catch (exc) {
+      object = exc;
+    }
+
+    if (emptySlots > 0) {
+      res.push(getEmptySlotsElement(emptySlots));
+      foldedEmptySlots = foldedEmptySlots + emptySlots - 1;
+      emptySlots = 0;
+    }
+
+    if (res.length < max) {
+      res.push(Rep(Object.assign({}, props, {
+        object,
+        mode: MODE.TINY,
+        // Do not propagate title to array items reps
+        title: undefined
+      })));
+    }
+
+    return res;
+  }, []);
+
+  // Handle trailing empty slots if there are some.
+  if (items.length < max && emptySlots > 0) {
+    items.push(getEmptySlotsElement(emptySlots));
+    foldedEmptySlots = foldedEmptySlots + emptySlots - 1;
+  }
+
+  const itemsShown = items.length + foldedEmptySlots;
+  if (gripLength > itemsShown) {
+    items.push(span({
+      className: "more-ellipsis",
+      title: "more…"
+    }, "…"));
+  }
+
+  return items;
+}
+
+function getEmptySlotsElement(number) {
+  // TODO: Use l10N - See https://github.com/devtools-html/reps/issues/141
+  return `<${number} empty slot${number > 1 ? "s" : ""}>`;
+}
+
+function supportsObject(grip, noGrip = false) {
+  if (noGrip === true || !isGrip(grip)) {
+    return false;
+  }
+
+  return grip.preview && (grip.preview.kind == "ArrayLike" || getGripType(grip, noGrip) === "DocumentFragment");
+}
+
+const maxLengthMap = new Map();
+maxLengthMap.set(MODE.SHORT, 3);
+maxLengthMap.set(MODE.LONG, 10);
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(GripArray),
+  supportsObject,
+  maxLengthMap
+};
+
+/***/ }),
 /* 20 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// Dependencies
-	const React = __webpack_require__(8);
-
-	const { wrapRender } = __webpack_require__(7);
-
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Renders a NaN object
-	 */
-	function NaNRep(props) {
-	  return span({ className: "objectBox objectBox-nan" }, "NaN");
-	}
-
-	function supportsObject(object, type) {
-	  return type == "NaN";
-	}
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(NaNRep),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// Dependencies
+const React = __webpack_require__(0);
+// Shortcuts
+const { span } = React.DOM;
+const {
+  wrapRender
+} = __webpack_require__(1);
+const PropRep = __webpack_require__(4);
+const { MODE } = __webpack_require__(2);
+/**
+ * Renders an map entry. A map entry is represented by its key, a column and its value.
+ */
+GripMapEntry.propTypes = {
+  object: React.PropTypes.object,
+  // @TODO Change this to Object.values once it's supported in Node's version of V8
+  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
+  onDOMNodeMouseOver: React.PropTypes.func,
+  onDOMNodeMouseOut: React.PropTypes.func,
+  onInspectIconClick: React.PropTypes.func
+};
+
+function GripMapEntry(props) {
+  const {
+    object
+  } = props;
+
+  const {
+    key,
+    value
+  } = object.preview;
+
+  return span({
+    className: "objectBox objectBox-map-entry"
+  }, ...PropRep(Object.assign({}, props, {
+    name: key,
+    object: value,
+    equal: " \u2192 ",
+    title: null,
+    suppressQuotes: false
+  })));
+}
+
+function supportsObject(grip, noGrip = false) {
+  if (noGrip === true) {
+    return false;
+  }
+  return grip && grip.type === "mapEntry" && grip.preview;
+}
+
+function createGripMapEntry(key, value) {
+  return {
+    type: "mapEntry",
+    preview: {
+      key,
+      value
+    }
+  };
+}
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(GripMapEntry),
+  createGripMapEntry,
+  supportsObject
+};
+
+/***/ }),
 /* 21 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// Dependencies
-	const React = __webpack_require__(8);
-	const {
-	  wrapRender
-	} = __webpack_require__(7);
-	const { MODE } = __webpack_require__(1);
-	// Shortcuts
-	const {
-	  span
-	} = React.DOM;
-	/**
-	 * Renders an object. An object is represented by a list of its
-	 * properties enclosed in curly brackets.
-	 */
-	Accessor.propTypes = {
-	  object: React.PropTypes.object.isRequired,
-	  mode: React.PropTypes.oneOf(Object.values(MODE))
-	};
-
-	function Accessor(props) {
-	  const {
-	    object
-	  } = props;
-
-	  const accessors = [];
-	  if (hasGetter(object)) {
-	    accessors.push("Getter");
-	  }
-	  if (hasSetter(object)) {
-	    accessors.push("Setter");
-	  }
-	  const title = accessors.join(" & ");
-
-	  return span({ className: "objectBox objectBox-accessor" }, span({
-	    className: "objectTitle"
-	  }, title));
-	}
-
-	function hasGetter(object) {
-	  return object && object.get && object.get.type !== "undefined";
-	}
-
-	function hasSetter(object) {
-	  return object && object.set && object.set.type !== "undefined";
-	}
-
-	function supportsObject(object, type, noGrip = false) {
-	  if (noGrip !== true && (hasGetter(object) || hasSetter(object))) {
-	    return true;
-	  }
-
-	  return false;
-	}
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(Accessor),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+const get = __webpack_require__(61);
+const has = __webpack_require__(101);
+const { maybeEscapePropertyName } = __webpack_require__(1);
+const ArrayRep = __webpack_require__(17);
+const GripArrayRep = __webpack_require__(19);
+const GripMapEntryRep = __webpack_require__(20);
+
+const NODE_TYPES = {
+  BUCKET: Symbol("[n…n]"),
+  DEFAULT_PROPERTIES: Symbol("[default properties]"),
+  ENTRIES: Symbol("<entries>"),
+  GET: Symbol("<get>"),
+  GRIP: Symbol("GRIP"),
+  MAP_ENTRY_KEY: Symbol("<key>"),
+  MAP_ENTRY_VALUE: Symbol("<value>"),
+  PROMISE_REASON: Symbol("<reason>"),
+  PROMISE_STATE: Symbol("<state>"),
+  PROMISE_VALUE: Symbol("<value>"),
+  SET: Symbol("<set>"),
+  PROTOTYPE: Symbol("__proto__")
+};
+
+let WINDOW_PROPERTIES = {};
+
+if (typeof window === "object") {
+  WINDOW_PROPERTIES = Object.getOwnPropertyNames(window);
+}
+
+const SAFE_PATH_PREFIX = "##-";
+
+function getType(item) {
+  return item.type;
+}
+
+function getValue(item) {
+  if (has(item, "contents.value")) {
+    return get(item, "contents.value");
+  }
+
+  if (has(item, "contents.getterValue")) {
+    return get(item, "contents.getterValue", undefined);
+  }
+
+  if (nodeHasAccessors(item)) {
+    return item.contents;
+  }
+
+  return undefined;
+}
+
+function nodeIsBucket(item) {
+  return getType(item) === NODE_TYPES.BUCKET;
+}
+
+function nodeIsEntries(item) {
+  return getType(item) === NODE_TYPES.ENTRIES;
+}
+
+function nodeIsMapEntry(item) {
+  return GripMapEntryRep.supportsObject(getValue(item));
+}
+
+function nodeHasChildren(item) {
+  return Array.isArray(item.contents) || nodeIsBucket(item);
+}
+
+function nodeIsObject(item) {
+  const value = getValue(item);
+  return value && value.type === "object";
+}
+
+function nodeIsArrayLike(item) {
+  const value = getValue(item);
+  return GripArrayRep.supportsObject(value) || ArrayRep.supportsObject(value);
+}
+
+function nodeIsFunction(item) {
+  const value = getValue(item);
+  return value && value.class === "Function";
+}
+
+function nodeIsOptimizedOut(item) {
+  const value = getValue(item);
+  return !nodeHasChildren(item) && value && value.optimizedOut;
+}
+
+function nodeIsMissingArguments(item) {
+  const value = getValue(item);
+  return !nodeHasChildren(item) && value && value.missingArguments;
+}
+
+function nodeHasProperties(item) {
+  return !nodeHasChildren(item) && nodeIsObject(item);
+}
+
+function nodeIsPrimitive(item) {
+  return !nodeHasChildren(item) && !nodeHasProperties(item) && !nodeIsEntries(item) && !nodeIsMapEntry(item) && !nodeHasAccessors(item);
+}
+
+function nodeIsDefaultProperties(item) {
+  return getType(item) === NODE_TYPES.DEFAULT_PROPERTIES;
+}
+
+function isDefaultWindowProperty(name) {
+  return WINDOW_PROPERTIES.includes(name);
+}
+
+function nodeIsPromise(item) {
+  const value = getValue(item);
+  if (!value) {
+    return false;
+  }
+
+  return value.class == "Promise";
+}
+
+function nodeIsPrototype(item) {
+  return getType(item) === NODE_TYPES.PROTOTYPE;
+}
+
+function nodeIsWindow(item) {
+  const value = getValue(item);
+  if (!value) {
+    return false;
+  }
+
+  return value.class == "Window";
+}
+
+function nodeIsGetter(item) {
+  return getType(item) === NODE_TYPES.GET;
+}
+
+function nodeIsSetter(item) {
+  return getType(item) === NODE_TYPES.SET;
+}
+
+function nodeHasAccessors(item) {
+  return !!getNodeGetter(item) || !!getNodeSetter(item);
+}
+
+function nodeSupportsBucketing(item) {
+  return nodeIsArrayLike(item) || nodeIsEntries(item);
+}
+
+function nodeHasEntries(item) {
+  const value = getValue(item);
+  if (!value) {
+    return false;
+  }
+
+  return value.class === "Map" || value.class === "Set" || value.class === "WeakMap" || value.class === "WeakSet";
+}
+
+function nodeHasAllEntriesInPreview(item) {
+  const { preview } = getValue(item) || {};
+  if (!preview) {
+    return false;
+  }
+
+  const {
+    entries,
+    items,
+    length,
+    size
+  } = preview;
+
+  return entries ? entries.length === size : items.length === length;
+}
+
+function makeNodesForPromiseProperties(item) {
+  const { promiseState: { reason, value, state } } = getValue(item);
+
+  const properties = [];
+
+  if (state) {
+    properties.push(createNode(item, "<state>", `${item.path}/${SAFE_PATH_PREFIX}state`, { value: state }, NODE_TYPES.PROMISE_STATE));
+  }
+
+  if (reason) {
+    properties.push(createNode(item, "<reason>", `${item.path}/${SAFE_PATH_PREFIX}reason`, { value: reason }, NODE_TYPES.PROMISE_REASON));
+  }
+
+  if (value) {
+    properties.push(createNode(item, "<value>", `${item.path}/${SAFE_PATH_PREFIX}value`, { value: value }, NODE_TYPES.PROMISE_VALUE));
+  }
+
+  return properties;
+}
+
+function makeNodesForEntries(item) {
+  const { path } = item;
+  const { preview } = getValue(item);
+  const nodeName = "<entries>";
+  const entriesPath = `${path}/${SAFE_PATH_PREFIX}entries`;
+
+  if (nodeHasAllEntriesInPreview(item)) {
+    let entriesNodes = [];
+    if (preview.entries) {
+      entriesNodes = preview.entries.map(([key, value], index) => {
+        return createNode(item, index, `${entriesPath}/${index}`, {
+          value: GripMapEntryRep.createGripMapEntry(key, value)
+        });
+      });
+    } else if (preview.items) {
+      entriesNodes = preview.items.map((value, index) => {
+        return createNode(item, index, `${entriesPath}/${index}`, { value });
+      });
+    }
+    return createNode(item, nodeName, entriesPath, entriesNodes, NODE_TYPES.ENTRIES);
+  }
+  return createNode(item, nodeName, entriesPath, null, NODE_TYPES.ENTRIES);
+}
+
+function makeNodesForMapEntry(item) {
+  const nodeValue = getValue(item);
+  if (!nodeValue || !nodeValue.preview) {
+    return [];
+  }
+
+  const { key, value } = nodeValue.preview;
+  const path = item.path;
+
+  return [createNode(item, "<key>", `${path}/##key`, { value: key }, NODE_TYPES.MAP_ENTRY_KEY), createNode(item, "<value>", `${path}/##value`, { value }, NODE_TYPES.MAP_ENTRY_VALUE)];
+}
+
+function getNodeGetter(item) {
+  return get(item, "contents.get", undefined);
+}
+
+function getNodeSetter(item) {
+  return get(item, "contents.set", undefined);
+}
+
+function makeNodesForAccessors(item) {
+  const accessors = [];
+
+  const getter = getNodeGetter(item);
+  if (getter && getter.type !== "undefined") {
+    accessors.push(createNode(item, "<get>", `${item.path}/${SAFE_PATH_PREFIX}get`, { value: getter }, NODE_TYPES.GET));
+  }
+
+  const setter = getNodeSetter(item);
+  if (setter && setter.type !== "undefined") {
+    accessors.push(createNode(item, "<set>", `${item.path}/${SAFE_PATH_PREFIX}set`, { value: setter }, NODE_TYPES.SET));
+  }
+
+  return accessors;
+}
+
+function sortProperties(properties) {
+  return properties.sort((a, b) => {
+    // Sort numbers in ascending order and sort strings lexicographically
+    const aInt = parseInt(a, 10);
+    const bInt = parseInt(b, 10);
+
+    if (isNaN(aInt) || isNaN(bInt)) {
+      return a > b ? 1 : -1;
+    }
+
+    return aInt - bInt;
+  });
+}
+
+function makeNumericalBuckets(propertiesNames, parent, ownProperties, startIndex = 0) {
+  const parentPath = parent.path;
+  const numProperties = propertiesNames.length;
+
+  // We want to have at most a hundred slices.
+  const bucketSize = 10 ** Math.max(2, Math.ceil(Math.log10(numProperties)) - 2);
+  const numBuckets = Math.ceil(numProperties / bucketSize);
+
+  let buckets = [];
+  for (let i = 1; i <= numBuckets; i++) {
+    const minKey = (i - 1) * bucketSize;
+    const maxKey = Math.min(i * bucketSize - 1, numProperties - 1);
+
+    if (maxKey === minKey) {
+      const name = propertiesNames[maxKey];
+      buckets.push(createNode(parent, name, `${parentPath}/${name}`, ownProperties[name]));
+    } else {
+      const minIndex = startIndex + minKey;
+      const maxIndex = startIndex + maxKey;
+      const bucketKey = `${SAFE_PATH_PREFIX}bucket_${minIndex}-${maxIndex}`;
+      const bucketName = `[${minIndex}…${maxIndex}]`;
+
+      const bucketRoot = createNode(parent, bucketName, `${parentPath}/${bucketKey}`, [], NODE_TYPES.BUCKET);
+
+      const bucketProperties = propertiesNames.slice(minKey, maxKey + 1);
+      let bucketNodes;
+      if (bucketProperties.length <= 100) {
+        bucketNodes = bucketProperties.map(name => createNode(bucketRoot, name, `${parentPath}/${bucketKey}/${name}`, ownProperties[name]));
+      } else {
+        bucketNodes = makeNumericalBuckets(bucketProperties, bucketRoot, ownProperties, minIndex);
+      }
+      setNodeChildren(bucketRoot, bucketNodes);
+      buckets.push(bucketRoot);
+    }
+  }
+  return buckets;
+}
+
+function makeDefaultPropsBucket(propertiesNames, parent, ownProperties) {
+  const parentPath = parent.path;
+
+  const userPropertiesNames = [];
+  const defaultProperties = [];
+
+  propertiesNames.forEach(name => {
+    if (isDefaultWindowProperty(name)) {
+      defaultProperties.push(name);
+    } else {
+      userPropertiesNames.push(name);
+    }
+  });
+
+  let nodes = makeNodesForOwnProps(userPropertiesNames, parent, ownProperties);
+
+  if (defaultProperties.length > 0) {
+    const defaultPropertiesNode = createNode(parent, "[default properties]", `${parentPath}/${SAFE_PATH_PREFIX}default`, null, NODE_TYPES.DEFAULT_PROPERTIES);
+
+    const defaultNodes = defaultProperties.map((name, index) => createNode(defaultPropertiesNode, maybeEscapePropertyName(name), `${parentPath}/${SAFE_PATH_PREFIX}bucket${index}/${name}`, ownProperties[name]));
+    nodes.push(setNodeChildren(defaultPropertiesNode, defaultNodes));
+  }
+  return nodes;
+}
+
+function makeNodesForOwnProps(propertiesNames, parent, ownProperties) {
+  const parentPath = parent.path;
+  return propertiesNames.map(name => createNode(parent, maybeEscapePropertyName(name), `${parentPath}/${name}`, ownProperties[name]));
+}
+
+function makeNodesForProperties(objProps, parent) {
+  const {
+    ownProperties = {},
+    ownSymbols,
+    prototype,
+    safeGetterValues
+  } = objProps;
+
+  const parentPath = parent.path;
+  const parentValue = getValue(parent);
+
+  let allProperties = Object.assign({}, ownProperties, safeGetterValues);
+
+  // Ignore properties that are neither non-concrete nor getters/setters.
+  const propertiesNames = sortProperties(Object.keys(allProperties)).filter(name => allProperties[name].hasOwnProperty("value") || allProperties[name].hasOwnProperty("getterValue") || allProperties[name].hasOwnProperty("get") || allProperties[name].hasOwnProperty("set"));
+
+  const numProperties = propertiesNames.length;
+
+  let nodes = [];
+  if (nodeSupportsBucketing(parent) && numProperties > 100) {
+    nodes = makeNumericalBuckets(propertiesNames, parent, allProperties);
+  } else if (parentValue && parentValue.class == "Window") {
+    nodes = makeDefaultPropsBucket(propertiesNames, parent, allProperties);
+  } else {
+    nodes = makeNodesForOwnProps(propertiesNames, parent, allProperties);
+  }
+
+  if (Array.isArray(ownSymbols)) {
+    ownSymbols.forEach((ownSymbol, index) => {
+      nodes.push(createNode(parent, ownSymbol.name, `${parentPath}/${SAFE_PATH_PREFIX}symbol-${index}`, ownSymbol.descriptor));
+    }, this);
+  }
+
+  if (nodeIsPromise(parent)) {
+    nodes.push(...makeNodesForPromiseProperties(parent));
+  }
+
+  if (nodeHasEntries(parent)) {
+    nodes.push(makeNodesForEntries(parent));
+  }
+
+  // Add the prototype if it exists and is not null
+  if (prototype && prototype.type !== "null") {
+    nodes.push(createNode(parent, "__proto__", `${parentPath}/__proto__`, { value: prototype }, NODE_TYPES.PROTOTYPE));
+  }
+
+  return nodes;
+}
+
+function createNode(parent, name, path, contents, type = NODE_TYPES.GRIP) {
+  if (contents === undefined) {
+    return null;
+  }
+
+  // The path is important to uniquely identify the item in the entire
+  // tree. This helps debugging & optimizes React's rendering of large
+  // lists. The path will be separated by property name,
+  // i.e. `{ foo: { bar: { baz: 5 }}}` will have a path of `foo/bar/baz`
+  // for the inner object.
+  return {
+    parent,
+    name,
+    path,
+    contents,
+    type
+  };
+}
+
+function setNodeChildren(node, children) {
+  node.contents = children;
+  return node;
+}
+
+function getChildren(options) {
+  const {
+    actors = {},
+    getObjectEntries,
+    getObjectProperties,
+    item
+  } = options;
+  // Nodes can either have children already, or be an object with
+  // properties that we need to go and fetch.
+  if (nodeHasAccessors(item)) {
+    return makeNodesForAccessors(item);
+  }
+
+  if (nodeIsMapEntry(item)) {
+    return makeNodesForMapEntry(item);
+  }
+
+  if (nodeHasChildren(item)) {
+    return item.contents;
+  }
+
+  if (!nodeHasProperties(item) && !nodeIsEntries(item)) {
+    return [];
+  }
+
+  // Because we are dynamically creating the tree as the user
+  // expands it (not precalculated tree structure), we cache child
+  // arrays. This not only helps performance, but is necessary
+  // because the expanded state depends on instances of nodes
+  // being the same across renders. If we didn't do this, each
+  // node would be a new instance every render.
+  const key = item.path;
+  if (actors && actors[key]) {
+    return actors[key];
+  }
+
+  if (nodeIsBucket(item)) {
+    return item.contents.children;
+  }
+
+  let loadedProps;
+  if (nodeIsEntries(item)) {
+    // If `item` is an <entries> node, we need to get the entries
+    // matching the parent node actor.
+    const parent = getParent(item);
+    loadedProps = getObjectEntries(get(getValue(parent), "actor", undefined));
+  } else {
+    loadedProps = getObjectProperties(get(getValue(item), "actor", undefined));
+  }
+
+  const {
+    ownProperties,
+    ownSymbols,
+    safeGetterValues,
+    prototype
+  } = loadedProps || {};
+
+  if (!ownProperties && !ownSymbols && !safeGetterValues && !prototype) {
+    return [];
+  }
+
+  let children = makeNodesForProperties(loadedProps, item);
+  actors[key] = children;
+  return children;
+}
+
+function getParent(item) {
+  return item.parent;
+}
+
+module.exports = {
+  createNode,
+  getChildren,
+  getParent,
+  getValue,
+  makeNodesForEntries,
+  makeNodesForPromiseProperties,
+  makeNodesForProperties,
+  nodeHasAccessors,
+  nodeHasAllEntriesInPreview,
+  nodeHasChildren,
+  nodeHasEntries,
+  nodeHasProperties,
+  nodeIsDefaultProperties,
+  nodeIsEntries,
+  nodeIsFunction,
+  nodeIsGetter,
+  nodeIsMapEntry,
+  nodeIsMissingArguments,
+  nodeIsObject,
+  nodeIsOptimizedOut,
+  nodeIsPrimitive,
+  nodeIsPromise,
+  nodeIsPrototype,
+  nodeIsSetter,
+  nodeIsWindow,
+  nodeSupportsBucketing,
+  setNodeChildren,
+  sortProperties,
+  NODE_TYPES,
+  // Export for testing purpose.
+  SAFE_PATH_PREFIX
+};
+
+/***/ }),
 /* 22 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// ReactJS
-	const React = __webpack_require__(8);
-
-	// Reps
-	const {
-	  isGrip,
-	  wrapRender
-	} = __webpack_require__(7);
-	const { rep: StringRep } = __webpack_require__(11);
-
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Renders DOM attribute
-	 */
-	Attribute.propTypes = {
-	  object: React.PropTypes.object.isRequired
-	};
-
-	function Attribute(props) {
-	  let {
-	    object
-	  } = props;
-	  let value = object.preview.value;
-
-	  return span({
-	    "data-link-actor-id": object.actor,
-	    className: "objectLink-Attr"
-	  }, span({ className: "attrTitle" }, getTitle(object)), span({ className: "attrEqual" }, "="), StringRep({ object: value }));
-	}
-
-	function getTitle(grip) {
-	  return grip.preview.nodeName;
-	}
-
-	// Registration
-	function supportsObject(grip, type, noGrip = false) {
-	  if (noGrip === true || !isGrip(grip)) {
-	    return false;
-	  }
-
-	  return type == "Attr" && grip.preview;
-	}
-
-	module.exports = {
-	  rep: wrapRender(Attribute),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var isArray = __webpack_require__(5),
+    isKey = __webpack_require__(63),
+    stringToPath = __webpack_require__(68),
+    toString = __webpack_require__(98);
+
+/**
+ * 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));
+}
+
+module.exports = castPath;
+
+
+/***/ }),
 /* 23 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// ReactJS
-	const React = __webpack_require__(8);
-
-	// Reps
-	const {
-	  isGrip,
-	  wrapRender
-	} = __webpack_require__(7);
-
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Used to render JS built-in Date() object.
-	 */
-	DateTime.propTypes = {
-	  object: React.PropTypes.object.isRequired
-	};
-
-	function DateTime(props) {
-	  let grip = props.object;
-	  let date;
-	  try {
-	    date = span({
-	      "data-link-actor-id": grip.actor,
-	      className: "objectBox"
-	    }, getTitle(grip), span({ className: "Date" }, new Date(grip.preview.timestamp).toISOString()));
-	  } catch (e) {
-	    date = span({ className: "objectBox" }, "Invalid Date");
-	  }
-
-	  return date;
-	}
-
-	function getTitle(grip) {
-	  return span({
-	    className: "objectTitle"
-	  }, grip.class + " ");
-	}
-
-	// Registration
-	function supportsObject(grip, type, noGrip = false) {
-	  if (noGrip === true || !isGrip(grip)) {
-	    return false;
-	  }
-
-	  return type == "Date" && grip.preview;
-	}
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(DateTime),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var baseIsNative = __webpack_require__(75),
+    getValue = __webpack_require__(80);
+
+/**
+ * Gets the native function at `key` of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {string} key The key of the method to get.
+ * @returns {*} Returns the function if it's native, else `undefined`.
+ */
+function getNative(object, key) {
+  var value = getValue(object, key);
+  return baseIsNative(value) ? value : undefined;
+}
+
+module.exports = getNative;
+
+
+/***/ }),
 /* 24 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// ReactJS
-	const React = __webpack_require__(8);
-
-	// Reps
-	const {
-	  isGrip,
-	  getURLDisplayString,
-	  wrapRender
-	} = __webpack_require__(7);
-
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Renders DOM document object.
-	 */
-	Document.propTypes = {
-	  object: React.PropTypes.object.isRequired
-	};
-
-	function Document(props) {
-	  let grip = props.object;
-
-	  return span({
-	    "data-link-actor-id": grip.actor,
-	    className: "objectBox objectBox-object"
-	  }, getTitle(grip), span({ className: "objectPropValue" }, getLocation(grip)));
-	}
-
-	function getLocation(grip) {
-	  let location = grip.preview.location;
-	  return location ? getURLDisplayString(location) : "";
-	}
-
-	function getTitle(grip) {
-	  return span({
-	    className: "objectTitle"
-	  }, grip.class + " ");
-	}
-
-	// Registration
-	function supportsObject(object, type, noGrip = false) {
-	  if (noGrip === true || !isGrip(object)) {
-	    return false;
-	  }
-
-	  return object.preview && type == "HTMLDocument";
-	}
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(Document),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports) {
+
+/**
+ * Checks if `value` is the
+ * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
+ * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(_.noop);
+ * // => true
+ *
+ * _.isObject(null);
+ * // => false
+ */
+function isObject(value) {
+  var type = typeof value;
+  return value != null && (type == 'object' || type == 'function');
+}
+
+module.exports = isObject;
+
+
+/***/ }),
 /* 25 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// ReactJS
-	const React = __webpack_require__(8);
-
-	// Reps
-	const {
-	  isGrip,
-	  wrapRender
-	} = __webpack_require__(7);
-
-	const { MODE } = __webpack_require__(1);
-	const { rep } = __webpack_require__(17);
-
-	/**
-	 * Renders DOM event objects.
-	 */
-	Event.propTypes = {
-	  object: React.PropTypes.object.isRequired,
-	  // @TODO Change this to Object.values once it's supported in Node's version of V8
-	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
-	  onDOMNodeMouseOver: React.PropTypes.func,
-	  onDOMNodeMouseOut: React.PropTypes.func,
-	  onInspectIconClick: React.PropTypes.func
-	};
-
-	function Event(props) {
-	  // Use `Object.assign` to keep `props` without changes because:
-	  // 1. JSON.stringify/JSON.parse is slow.
-	  // 2. Immutable.js is planned for the future.
-	  let gripProps = Object.assign({}, props, {
-	    title: getTitle(props)
-	  });
-	  gripProps.object = Object.assign({}, props.object);
-	  gripProps.object.preview = Object.assign({}, props.object.preview);
-
-	  gripProps.object.preview.ownProperties = {};
-	  if (gripProps.object.preview.target) {
-	    Object.assign(gripProps.object.preview.ownProperties, {
-	      target: gripProps.object.preview.target
-	    });
-	  }
-	  Object.assign(gripProps.object.preview.ownProperties, gripProps.object.preview.properties);
-
-	  delete gripProps.object.preview.properties;
-	  gripProps.object.ownPropertyLength = Object.keys(gripProps.object.preview.ownProperties).length;
-
-	  switch (gripProps.object.class) {
-	    case "MouseEvent":
-	      gripProps.isInterestingProp = (type, value, name) => {
-	        return ["target", "clientX", "clientY", "layerX", "layerY"].includes(name);
-	      };
-	      break;
-	    case "KeyboardEvent":
-	      gripProps.isInterestingProp = (type, value, name) => {
-	        return ["target", "key", "charCode", "keyCode"].includes(name);
-	      };
-	      break;
-	    case "MessageEvent":
-	      gripProps.isInterestingProp = (type, value, name) => {
-	        return ["target", "isTrusted", "data"].includes(name);
-	      };
-	      break;
-	    default:
-	      gripProps.isInterestingProp = (type, value, name) => {
-	        // We want to show the properties in the order they are declared.
-	        return Object.keys(gripProps.object.preview.ownProperties).includes(name);
-	      };
-	  }
-
-	  return rep(gripProps);
-	}
-
-	function getTitle(props) {
-	  let preview = props.object.preview;
-	  let title = preview.type;
-
-	  if (preview.eventKind == "key" && preview.modifiers && preview.modifiers.length) {
-	    title = `${title} ${preview.modifiers.join("-")}`;
-	  }
-	  return title;
-	}
-
-	// Registration
-	function supportsObject(grip, type, noGrip = false) {
-	  if (noGrip === true || !isGrip(grip)) {
-	    return false;
-	  }
-
-	  return grip.preview && grip.preview.kind == "DOMEvent";
-	}
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(Event),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var isSymbol = __webpack_require__(11);
+
+/** Used as references for various `Number` constants. */
+var INFINITY = 1 / 0;
+
+/**
+ * Converts `value` to a string key if it's not a string or symbol.
+ *
+ * @private
+ * @param {*} value The value to inspect.
+ * @returns {string|symbol} Returns the key.
+ */
+function toKey(value) {
+  if (typeof value == 'string' || isSymbol(value)) {
+    return value;
+  }
+  var result = (value + '');
+  return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
+}
+
+module.exports = toKey;
+
+
+/***/ }),
 /* 26 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// ReactJS
-	const React = __webpack_require__(8);
-
-	// Reps
-	const {
-	  isGrip,
-	  cropString,
-	  wrapRender
-	} = __webpack_require__(7);
-
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * This component represents a template for Function objects.
-	 */
-	FunctionRep.propTypes = {
-	  object: React.PropTypes.object.isRequired,
-	  parameterNames: React.PropTypes.array
-	};
-
-	function FunctionRep(props) {
-	  let grip = props.object;
-
-	  return span({
-	    "data-link-actor-id": grip.actor,
-	    className: "objectBox objectBox-function",
-	    // Set dir="ltr" to prevent function parentheses from
-	    // appearing in the wrong direction
-	    dir: "ltr"
-	  }, getTitle(props, grip), summarizeFunction(grip), "(", ...renderParams(props), ")");
-	}
-
-	function getTitle(props, grip) {
-	  let title = "function ";
-	  if (grip.isGenerator) {
-	    title = "function* ";
-	  }
-	  if (grip.isAsync) {
-	    title = "async " + title;
-	  }
-
-	  return span({
-	    className: "objectTitle"
-	  }, title);
-	}
-
-	function summarizeFunction(grip) {
-	  let name = grip.userDisplayName || grip.displayName || grip.name || "";
-	  return cropString(name, 100);
-	}
-
-	function renderParams(props) {
-	  const {
-	    parameterNames = []
-	  } = props;
-
-	  return parameterNames.filter(param => param).reduce((res, param, index, arr) => {
-	    res.push(span({ className: "param" }, param));
-	    if (index < arr.length - 1) {
-	      res.push(span({ className: "delimiter" }, ", "));
-	    }
-	    return res;
-	  }, []);
-	}
-
-	// Registration
-	function supportsObject(grip, type, noGrip = false) {
-	  if (noGrip === true || !isGrip(grip)) {
-	    return type == "function";
-	  }
-
-	  return type == "Function";
-	}
-
-	// Exports from this module
-
-	module.exports = {
-	  rep: wrapRender(FunctionRep),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+const { MODE } = __webpack_require__(2);
+const { REPS, getRep } = __webpack_require__(3);
+const ObjectInspector = __webpack_require__(56);
+const ObjectInspectorUtils = __webpack_require__(21);
+
+const {
+  parseURLEncodedText,
+  parseURLParams,
+  maybeEscapePropertyName,
+  getGripPreviewItems
+} = __webpack_require__(1);
+
+module.exports = {
+  REPS,
+  getRep,
+  MODE,
+  maybeEscapePropertyName,
+  parseURLEncodedText,
+  parseURLParams,
+  getGripPreviewItems,
+  ObjectInspector,
+  ObjectInspectorUtils
+};
+
+/***/ }),
 /* 27 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// ReactJS
-	const React = __webpack_require__(8);
-	// Dependencies
-	const {
-	  isGrip,
-	  wrapRender
-	} = __webpack_require__(7);
-
-	const PropRep = __webpack_require__(16);
-	const { MODE } = __webpack_require__(1);
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Renders a DOM Promise object.
-	 */
-	PromiseRep.propTypes = {
-	  object: React.PropTypes.object.isRequired,
-	  // @TODO Change this to Object.values once it's supported in Node's version of V8
-	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
-	  onDOMNodeMouseOver: React.PropTypes.func,
-	  onDOMNodeMouseOut: React.PropTypes.func,
-	  onInspectIconClick: React.PropTypes.func
-	};
-
-	function PromiseRep(props) {
-	  const object = props.object;
-	  const { promiseState } = object;
-
-	  const config = {
-	    "data-link-actor-id": object.actor,
-	    className: "objectBox objectBox-object"
-	  };
-
-	  if (props.mode === MODE.TINY) {
-	    let { Rep } = __webpack_require__(2);
-
-	    return span(config, getTitle(object), span({
-	      className: "objectLeftBrace"
-	    }, " { "), Rep({ object: promiseState.state }), span({
-	      className: "objectRightBrace"
-	    }, " }"));
-	  }
-
-	  const propsArray = getProps(props, promiseState);
-	  return span(config, getTitle(object), span({
-	    className: "objectLeftBrace"
-	  }, " { "), ...propsArray, span({
-	    className: "objectRightBrace"
-	  }, " }"));
-	}
-
-	function getTitle(object) {
-	  return span({
-	    className: "objectTitle"
-	  }, object.class);
-	}
-
-	function getProps(props, promiseState) {
-	  const keys = ["state"];
-	  if (Object.keys(promiseState).includes("value")) {
-	    keys.push("value");
-	  }
-
-	  return keys.reduce((res, key, i) => {
-	    let object = promiseState[key];
-	    res = res.concat(PropRep(Object.assign({}, props, {
-	      mode: MODE.TINY,
-	      name: `<${key}>`,
-	      object,
-	      equal: ": ",
-	      suppressQuotes: true
-	    })));
-
-	    // Interleave commas between elements
-	    if (i !== keys.length - 1) {
-	      res.push(", ");
-	    }
-
-	    return res;
-	  }, []);
-	}
-
-	// Registration
-	function supportsObject(object, type, noGrip = false) {
-	  if (noGrip === true || !isGrip(object)) {
-	    return false;
-	  }
-	  return type === "Promise";
-	}
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(PromiseRep),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports) {
+
+// removed by extract-text-webpack-plugin
+
+/***/ }),
 /* 28 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// ReactJS
-	const React = __webpack_require__(8);
-
-	// Reps
-	const {
-	  isGrip,
-	  wrapRender
-	} = __webpack_require__(7);
-
-	/**
-	 * Renders a grip object with regular expression.
-	 */
-	RegExp.propTypes = {
-	  object: React.PropTypes.object.isRequired
-	};
-
-	function RegExp(props) {
-	  let { object } = props;
-
-	  return React.DOM.span({
-	    "data-link-actor-id": object.actor,
-	    className: "objectBox objectBox-regexp regexpSource"
-	  }, getSource(object));
-	}
-
-	function getSource(grip) {
-	  return grip.displayString;
-	}
-
-	// Registration
-	function supportsObject(object, type, noGrip = false) {
-	  if (noGrip === true || !isGrip(object)) {
-	    return false;
-	  }
-
-	  return type == "RegExp";
-	}
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(RegExp),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// Dependencies
+const React = __webpack_require__(0);
+
+const {
+  getGripType,
+  wrapRender
+} = __webpack_require__(1);
+
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Renders undefined value
+ */
+const Undefined = function () {
+  return span({ className: "objectBox objectBox-undefined" }, "undefined");
+};
+
+function supportsObject(object, noGrip = false) {
+  if (noGrip === true) {
+    return false;
+  }
+
+  return object && object.type && object.type == "undefined" || getGripType(object, noGrip) == "undefined";
+}
+
+// Exports from this module
+
+module.exports = {
+  rep: wrapRender(Undefined),
+  supportsObject
+};
+
+/***/ }),
 /* 29 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// ReactJS
-	const React = __webpack_require__(8);
-
-	// Reps
-	const {
-	  isGrip,
-	  getURLDisplayString,
-	  wrapRender
-	} = __webpack_require__(7);
-
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Renders a grip representing CSSStyleSheet
-	 */
-	StyleSheet.propTypes = {
-	  object: React.PropTypes.object.isRequired
-	};
-
-	function StyleSheet(props) {
-	  let grip = props.object;
-
-	  return span({
-	    "data-link-actor-id": grip.actor,
-	    className: "objectBox objectBox-object"
-	  }, getTitle(grip), span({ className: "objectPropValue" }, getLocation(grip)));
-	}
-
-	function getTitle(grip) {
-	  let title = "StyleSheet ";
-	  return span({ className: "objectBoxTitle" }, title);
-	}
-
-	function getLocation(grip) {
-	  // Embedded stylesheets don't have URL and so, no preview.
-	  let url = grip.preview ? grip.preview.url : "";
-	  return url ? getURLDisplayString(url) : "";
-	}
-
-	// Registration
-	function supportsObject(object, type, noGrip = false) {
-	  if (noGrip === true || !isGrip(object)) {
-	    return false;
-	  }
-
-	  return type == "CSSStyleSheet";
-	}
-
-	// Exports from this module
-
-	module.exports = {
-	  rep: wrapRender(StyleSheet),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// Dependencies
+const React = __webpack_require__(0);
+
+const { wrapRender } = __webpack_require__(1);
+
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Renders null value
+ */
+function Null(props) {
+  return span({ className: "objectBox objectBox-null" }, "null");
+}
+
+function supportsObject(object, noGrip = false) {
+  if (noGrip === true) {
+    return false;
+  }
+
+  if (object && object.type && object.type == "null") {
+    return true;
+  }
+
+  return object == null;
+}
+
+// Exports from this module
+
+module.exports = {
+  rep: wrapRender(Null),
+  supportsObject
+};
+
+/***/ }),
 /* 30 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// Dependencies
-	const React = __webpack_require__(8);
-	const {
-	  isGrip,
-	  cropString,
-	  cropMultipleLines,
-	  wrapRender
-	} = __webpack_require__(7);
-	const { MODE } = __webpack_require__(1);
-	const nodeConstants = __webpack_require__(31);
-
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Renders DOM comment node.
-	 */
-	CommentNode.propTypes = {
-	  object: React.PropTypes.object.isRequired,
-	  // @TODO Change this to Object.values once it's supported in Node's version of V8
-	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key]))
-	};
-
-	function CommentNode(props) {
-	  let {
-	    object,
-	    mode = MODE.SHORT
-	  } = props;
-
-	  let { textContent } = object.preview;
-	  if (mode === MODE.TINY) {
-	    textContent = cropMultipleLines(textContent, 30);
-	  } else if (mode === MODE.SHORT) {
-	    textContent = cropString(textContent, 50);
-	  }
-
-	  return span({
-	    className: "objectBox theme-comment",
-	    "data-link-actor-id": object.actor
-	  }, `<!-- ${textContent} -->`);
-	}
-
-	// Registration
-	function supportsObject(object, type, noGrip = false) {
-	  if (noGrip === true || !isGrip(object)) {
-	    return false;
-	  }
-	  return object.preview && object.preview.nodeType === nodeConstants.COMMENT_NODE;
-	}
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(CommentNode),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// Dependencies
+const React = __webpack_require__(0);
+const {
+  escapeString,
+  sanitizeString,
+  isGrip,
+  wrapRender
+} = __webpack_require__(1);
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Renders a long string grip.
+ */
+LongStringRep.propTypes = {
+  useQuotes: React.PropTypes.bool,
+  escapeWhitespace: React.PropTypes.bool,
+  style: React.PropTypes.object,
+  cropLimit: React.PropTypes.number.isRequired,
+  member: React.PropTypes.string,
+  object: React.PropTypes.object.isRequired
+};
+
+function LongStringRep(props) {
+  let {
+    cropLimit,
+    member,
+    object,
+    style,
+    useQuotes = true,
+    escapeWhitespace = true
+  } = props;
+  let { fullText, initial, length } = object;
+
+  let config = {
+    "data-link-actor-id": object.actor,
+    className: "objectBox objectBox-string"
+  };
+
+  if (style) {
+    config.style = style;
+  }
+
+  let string = member && member.open ? fullText || initial : initial.substring(0, cropLimit);
+
+  if (string.length < length) {
+    string += "\u2026";
+  }
+  let formattedString = useQuotes ? escapeString(string, escapeWhitespace) : sanitizeString(string);
+  return span(config, formattedString);
+}
+
+function supportsObject(object, noGrip = false) {
+  if (noGrip === true || !isGrip(object)) {
+    return false;
+  }
+  return object.type === "longString";
+}
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(LongStringRep),
+  supportsObject
+};
+
+/***/ }),
 /* 31 */
-/***/ function(module, exports) {
-
-	/* 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 = {
-	  ELEMENT_NODE: 1,
-	  ATTRIBUTE_NODE: 2,
-	  TEXT_NODE: 3,
-	  CDATA_SECTION_NODE: 4,
-	  ENTITY_REFERENCE_NODE: 5,
-	  ENTITY_NODE: 6,
-	  PROCESSING_INSTRUCTION_NODE: 7,
-	  COMMENT_NODE: 8,
-	  DOCUMENT_NODE: 9,
-	  DOCUMENT_TYPE_NODE: 10,
-	  DOCUMENT_FRAGMENT_NODE: 11,
-	  NOTATION_NODE: 12,
-
-	  // DocumentPosition
-	  DOCUMENT_POSITION_DISCONNECTED: 0x01,
-	  DOCUMENT_POSITION_PRECEDING: 0x02,
-	  DOCUMENT_POSITION_FOLLOWING: 0x04,
-	  DOCUMENT_POSITION_CONTAINS: 0x08,
-	  DOCUMENT_POSITION_CONTAINED_BY: 0x10,
-	  DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: 0x20
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// Dependencies
+const React = __webpack_require__(0);
+
+const {
+  getGripType,
+  wrapRender
+} = __webpack_require__(1);
+
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Renders a number
+ */
+Number.propTypes = {
+  object: React.PropTypes.oneOfType([React.PropTypes.object, React.PropTypes.number, React.PropTypes.bool]).isRequired
+};
+
+function Number(props) {
+  let value = props.object;
+
+  return span({ className: "objectBox objectBox-number" }, stringify(value));
+}
+
+function stringify(object) {
+  let isNegativeZero = Object.is(object, -0) || object.type && object.type == "-0";
+
+  return isNegativeZero ? "-0" : String(object);
+}
+
+function supportsObject(object, noGrip = false) {
+  return ["boolean", "number", "-0"].includes(getGripType(object, noGrip));
+}
+
+// Exports from this module
+
+module.exports = {
+  rep: wrapRender(Number),
+  supportsObject
+};
+
+/***/ }),
 /* 32 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// ReactJS
-	const React = __webpack_require__(8);
-
-	// Utils
-	const {
-	  isGrip,
-	  wrapRender
-	} = __webpack_require__(7);
-	const { MODE } = __webpack_require__(1);
-	const nodeConstants = __webpack_require__(31);
-	const Svg = __webpack_require__(33);
-
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Renders DOM element node.
-	 */
-	ElementNode.propTypes = {
-	  object: React.PropTypes.object.isRequired,
-	  // @TODO Change this to Object.values once it's supported in Node's version of V8
-	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
-	  onDOMNodeMouseOver: React.PropTypes.func,
-	  onDOMNodeMouseOut: React.PropTypes.func,
-	  onInspectIconClick: React.PropTypes.func
-	};
-
-	function ElementNode(props) {
-	  let {
-	    object,
-	    mode,
-	    onDOMNodeMouseOver,
-	    onDOMNodeMouseOut,
-	    onInspectIconClick
-	  } = props;
-	  let elements = getElements(object, mode);
-
-	  let isInTree = object.preview && object.preview.isConnected === true;
-
-	  let baseConfig = {
-	    "data-link-actor-id": object.actor,
-	    className: "objectBox objectBox-node"
-	  };
-	  let inspectIcon;
-	  if (isInTree) {
-	    if (onDOMNodeMouseOver) {
-	      Object.assign(baseConfig, {
-	        onMouseOver: _ => onDOMNodeMouseOver(object)
-	      });
-	    }
-
-	    if (onDOMNodeMouseOut) {
-	      Object.assign(baseConfig, {
-	        onMouseOut: onDOMNodeMouseOut
-	      });
-	    }
-
-	    if (onInspectIconClick) {
-	      inspectIcon = Svg("open-inspector", {
-	        element: "a",
-	        draggable: false,
-	        // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands
-	        title: "Click to select the node in the inspector",
-	        onClick: e => onInspectIconClick(object, e)
-	      });
-	    }
-	  }
-
-	  return span(baseConfig, ...elements, inspectIcon);
-	}
-
-	function getElements(grip, mode) {
-	  let { attributes, nodeName } = grip.preview;
-	  const nodeNameElement = span({
-	    className: "tag-name theme-fg-color3"
-	  }, nodeName);
-
-	  if (mode === MODE.TINY) {
-	    let elements = [nodeNameElement];
-	    if (attributes.id) {
-	      elements.push(span({ className: "attr-name theme-fg-color2" }, `#${attributes.id}`));
-	    }
-	    if (attributes.class) {
-	      elements.push(span({ className: "attr-name theme-fg-color2" }, attributes.class.replace(/(^\s+)|(\s+$)/g, "").split(" ").map(cls => `.${cls}`).join("")));
-	    }
-	    return elements;
-	  }
-	  let attributeKeys = Object.keys(attributes);
-	  if (attributeKeys.includes("class")) {
-	    attributeKeys.splice(attributeKeys.indexOf("class"), 1);
-	    attributeKeys.unshift("class");
-	  }
-	  if (attributeKeys.includes("id")) {
-	    attributeKeys.splice(attributeKeys.indexOf("id"), 1);
-	    attributeKeys.unshift("id");
-	  }
-	  const attributeElements = attributeKeys.reduce((arr, name, i, keys) => {
-	    let value = attributes[name];
-	    let attribute = span({}, span({ className: "attr-name theme-fg-color2" }, `${name}`), `="`, span({ className: "attr-value theme-fg-color6" }, `${value}`), `"`);
-
-	    return arr.concat([" ", attribute]);
-	  }, []);
-
-	  return ["<", nodeNameElement, ...attributeElements, ">"];
-	}
-
-	// Registration
-	function supportsObject(object, type, noGrip = false) {
-	  if (noGrip === true || !isGrip(object)) {
-	    return false;
-	  }
-	  return object.preview && object.preview.nodeType === nodeConstants.ELEMENT_NODE;
-	}
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(ElementNode),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// Dependencies
+const React = __webpack_require__(0);
+const {
+  wrapRender
+} = __webpack_require__(1);
+const PropRep = __webpack_require__(4);
+const { MODE } = __webpack_require__(2);
+// Shortcuts
+const { span } = React.DOM;
+
+const DEFAULT_TITLE = "Object";
+
+/**
+ * Renders an object. An object is represented by a list of its
+ * properties enclosed in curly brackets.
+ */
+ObjectRep.propTypes = {
+  object: React.PropTypes.object.isRequired,
+  // @TODO Change this to Object.values once it's supported in Node's version of V8
+  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
+  title: React.PropTypes.string
+};
+
+function ObjectRep(props) {
+  let object = props.object;
+  let propsArray = safePropIterator(props, object);
+
+  if (props.mode === MODE.TINY) {
+    const tinyModeItems = [];
+    if (getTitle(props, object) !== DEFAULT_TITLE) {
+      tinyModeItems.push(getTitleElement(props, object));
+    } else {
+      tinyModeItems.push(span({
+        className: "objectLeftBrace"
+      }, "{"), propsArray.length > 0 ? span({
+        key: "more",
+        className: "more-ellipsis",
+        title: "more…"
+      }, "…") : null, span({
+        className: "objectRightBrace"
+      }, "}"));
+    }
+
+    return span({ className: "objectBox objectBox-object" }, ...tinyModeItems);
+  }
+
+  return span({ className: "objectBox objectBox-object" }, getTitleElement(props, object), span({
+    className: "objectLeftBrace"
+  }, " { "), ...propsArray, span({
+    className: "objectRightBrace"
+  }, " }"));
+}
+
+function getTitleElement(props, object) {
+  return span({ className: "objectTitle" }, getTitle(props, object));
+}
+
+function getTitle(props, object) {
+  return props.title || object.class || DEFAULT_TITLE;
+}
+
+function safePropIterator(props, object, max) {
+  max = typeof max === "undefined" ? 3 : max;
+  try {
+    return propIterator(props, object, max);
+  } catch (err) {
+    console.error(err);
+  }
+  return [];
+}
+
+function propIterator(props, object, max) {
+  let isInterestingProp = (type, value) => {
+    // Do not pick objects, it could cause recursion.
+    return type == "boolean" || type == "number" || type == "string" && value;
+  };
+
+  // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=945377
+  if (Object.prototype.toString.call(object) === "[object Generator]") {
+    object = Object.getPrototypeOf(object);
+  }
+
+  // Object members with non-empty values are preferred since it gives the
+  // user a better overview of the object.
+  let interestingObject = getFilteredObject(object, max, isInterestingProp);
+
+  if (Object.keys(interestingObject).length < max) {
+    // There are not enough props yet (or at least, not enough props to
+    // be able to know whether we should print "more…" or not).
+    // Let's display also empty members and functions.
+    interestingObject = Object.assign({}, interestingObject, getFilteredObject(object, max - Object.keys(interestingObject).length, (type, value) => !isInterestingProp(type, value)));
+  }
+
+  let propsArray = getPropsArray(interestingObject, props);
+  if (Object.keys(object).length > max) {
+    propsArray.push(span({
+      className: "more-ellipsis",
+      title: "more…"
+    }, "…"));
+  }
+
+  return unfoldProps(propsArray);
+}
+
+function unfoldProps(items) {
+  return items.reduce((res, item, index) => {
+    if (Array.isArray(item)) {
+      res = res.concat(item);
+    } else {
+      res.push(item);
+    }
+
+    // Interleave commas between elements
+    if (index !== items.length - 1) {
+      res.push(", ");
+    }
+    return res;
+  }, []);
+}
+
+/**
+ * Get an array of components representing the properties of the object
+ *
+ * @param {Object} object
+ * @param {Object} props
+ * @return {Array} Array of PropRep.
+ */
+function getPropsArray(object, props) {
+  let propsArray = [];
+
+  if (!object) {
+    return propsArray;
+  }
+
+  // Hardcode tiny mode to avoid recursive handling.
+  let mode = MODE.TINY;
+  const objectKeys = Object.keys(object);
+  return objectKeys.map((name, i) => PropRep(Object.assign({}, props, {
+    mode,
+    name,
+    object: object[name],
+    equal: ": "
+  })));
+}
+
+/**
+ * Get a copy of the object filtered by a given predicate.
+ *
+ * @param {Object} object.
+ * @param {Number} max The maximum length of keys array.
+ * @param {Function} filter Filter the props you want.
+ * @return {Object} the filtered object.
+ */
+function getFilteredObject(object, max, filter) {
+  let filteredObject = {};
+
+  try {
+    for (let name in object) {
+      if (Object.keys(filteredObject).length >= max) {
+        return filteredObject;
+      }
+
+      let value;
+      try {
+        value = object[name];
+      } catch (exc) {
+        continue;
+      }
+
+      let t = typeof value;
+      if (filter(t, value)) {
+        filteredObject[name] = value;
+      }
+    }
+  } catch (err) {
+    console.error(err);
+  }
+  return filteredObject;
+}
+
+function supportsObject(object) {
+  return true;
+}
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(ObjectRep),
+  supportsObject
+};
+
+/***/ }),
 /* 33 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	const React = __webpack_require__(8);
-	const InlineSVG = __webpack_require__(34);
-
-	const svg = {
-	  "arrow": __webpack_require__(35),
-	  "open-inspector": __webpack_require__(36)
-	};
-
-	Svg.propTypes = {
-	  className: React.PropTypes.string
-	};
-
-	function Svg(name, props) {
-	  if (!svg[name]) {
-	    throw new Error("Unknown SVG: " + name);
-	  }
-	  let className = name;
-	  if (props && props.className) {
-	    className = `${name} ${props.className}`;
-	  }
-	  if (name === "subSettings") {
-	    className = "";
-	  }
-	  props = Object.assign({}, props, { className, src: svg[name] });
-	  return React.createElement(InlineSVG, props);
-	}
-
-	module.exports = Svg;
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// Dependencies
+const React = __webpack_require__(0);
+
+const {
+  getGripType,
+  wrapRender
+} = __webpack_require__(1);
+
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Renders a symbol.
+ */
+SymbolRep.propTypes = {
+  object: React.PropTypes.object.isRequired
+};
+
+function SymbolRep(props) {
+  let {
+    className = "objectBox objectBox-symbol",
+    object
+  } = props;
+  let { name } = object;
+
+  return span({ className }, `Symbol(${name || ""})`);
+}
+
+function supportsObject(object, noGrip = false) {
+  return getGripType(object, noGrip) == "symbol";
+}
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(SymbolRep),
+  supportsObject
+};
+
+/***/ }),
 /* 34 */
-/***/ function(module, exports, __webpack_require__) {
-
-	'use strict';
-
-	Object.defineProperty(exports, '__esModule', {
-	    value: true
-	});
-
-	var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-	var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
-
-	var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
-
-	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-	function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
-
-	function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
-
-	function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-
-	var _react = __webpack_require__(8);
-
-	var _react2 = _interopRequireDefault(_react);
-
-	var DOMParser = typeof window !== 'undefined' && window.DOMParser;
-	var process = process || {};
-	process.env = process.env || {};
-	var parserAvailable = typeof DOMParser !== 'undefined' && DOMParser.prototype != null && DOMParser.prototype.parseFromString != null;
-
-	function isParsable(src) {
-	    // kinda naive but meh, ain't gonna use full-blown parser for this
-	    return parserAvailable && typeof src === 'string' && src.trim().substr(0, 4) === '<svg';
-	}
-
-	// parse SVG string using `DOMParser`
-	function parseFromSVGString(src) {
-	    var parser = new DOMParser();
-	    return parser.parseFromString(src, "image/svg+xml");
-	}
-
-	// Transform DOM prop/attr names applicable to `<svg>` element but react-limited
-	function switchSVGAttrToReactProp(propName) {
-	    switch (propName) {
-	        case 'class':
-	            return 'className';
-	        default:
-	            return propName;
-	    }
-	}
-
-	var InlineSVG = (function (_React$Component) {
-	    _inherits(InlineSVG, _React$Component);
-
-	    _createClass(InlineSVG, null, [{
-	        key: 'defaultProps',
-	        value: {
-	            element: 'i',
-	            raw: false,
-	            src: ''
-	        },
-	        enumerable: true
-	    }, {
-	        key: 'propTypes',
-	        value: {
-	            src: _react2['default'].PropTypes.string.isRequired,
-	            element: _react2['default'].PropTypes.string,
-	            raw: _react2['default'].PropTypes.bool
-	        },
-	        enumerable: true
-	    }]);
-
-	    function InlineSVG(props) {
-	        _classCallCheck(this, InlineSVG);
-
-	        _get(Object.getPrototypeOf(InlineSVG.prototype), 'constructor', this).call(this, props);
-	        this._extractSVGProps = this._extractSVGProps.bind(this);
-	    }
-
-	    // Serialize `Attr` objects in `NamedNodeMap`
-
-	    _createClass(InlineSVG, [{
-	        key: '_serializeAttrs',
-	        value: function _serializeAttrs(map) {
-	            var ret = {};
-	            var prop = undefined;
-	            for (var i = 0; i < map.length; i++) {
-	                prop = switchSVGAttrToReactProp(map[i].name);
-	                ret[prop] = map[i].value;
-	            }
-	            return ret;
-	        }
-
-	        // get <svg /> element props
-	    }, {
-	        key: '_extractSVGProps',
-	        value: function _extractSVGProps(src) {
-	            var map = parseFromSVGString(src).documentElement.attributes;
-	            return map.length > 0 ? this._serializeAttrs(map) : null;
-	        }
-
-	        // get content inside <svg> element.
-	    }, {
-	        key: '_stripSVG',
-	        value: function _stripSVG(src) {
-	            return parseFromSVGString(src).documentElement.innerHTML;
-	        }
-	    }, {
-	        key: 'componentWillReceiveProps',
-	        value: function componentWillReceiveProps(_ref) {
-	            var children = _ref.children;
-
-	            if ("production" !== process.env.NODE_ENV && children != null) {
-	                console.info('<InlineSVG />: `children` prop will be ignored.');
-	            }
-	        }
-	    }, {
-	        key: 'render',
-	        value: function render() {
-	            var Element = undefined,
-	                __html = undefined,
-	                svgProps = undefined;
-	            var _props = this.props;
-	            var element = _props.element;
-	            var raw = _props.raw;
-	            var src = _props.src;
-
-	            var otherProps = _objectWithoutProperties(_props, ['element', 'raw', 'src']);
-
-	            if (raw === true && isParsable(src)) {
-	                Element = 'svg';
-	                svgProps = this._extractSVGProps(src);
-	                __html = this._stripSVG(src);
-	            }
-	            __html = __html || src;
-	            Element = Element || element;
-	            svgProps = svgProps || {};
-
-	            return _react2['default'].createElement(Element, _extends({}, svgProps, otherProps, { src: null, children: null,
-	                dangerouslySetInnerHTML: { __html: __html } }));
-	        }
-	    }]);
-
-	    return InlineSVG;
-	})(_react2['default'].Component);
-
-	exports['default'] = InlineSVG;
-	module.exports = exports['default'];
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// Dependencies
+const React = __webpack_require__(0);
+
+const {
+  getGripType,
+  wrapRender
+} = __webpack_require__(1);
+
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Renders a Infinity object
+ */
+InfinityRep.propTypes = {
+  object: React.PropTypes.object.isRequired
+};
+
+function InfinityRep(props) {
+  const {
+    object
+  } = props;
+
+  return span({ className: "objectBox objectBox-number" }, object.type);
+}
+
+function supportsObject(object, noGrip = false) {
+  const type = getGripType(object, noGrip);
+  return type == "Infinity" || type == "-Infinity";
+}
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(InfinityRep),
+  supportsObject
+};
+
+/***/ }),
 /* 35 */
-/***/ function(module, exports) {
-
-	module.exports = "<!-- 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/. --><svg viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M8 13.4c-.5 0-.9-.2-1.2-.6L.4 5.2C0 4.7-.1 4.3.2 3.7S1 3 1.6 3h12.8c.6 0 1.2.1 1.4.7.3.6.2 1.1-.2 1.6l-6.4 7.6c-.3.4-.7.5-1.2.5z\"></path></svg>"
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// Dependencies
+const React = __webpack_require__(0);
+
+const {
+  getGripType,
+  wrapRender
+} = __webpack_require__(1);
+
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Renders a NaN object
+ */
+function NaNRep(props) {
+  return span({ className: "objectBox objectBox-nan" }, "NaN");
+}
+
+function supportsObject(object, noGrip = false) {
+  return getGripType(object, noGrip) == "NaN";
+}
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(NaNRep),
+  supportsObject
+};
+
+/***/ }),
 /* 36 */
-/***/ function(module, exports) {
-
-	module.exports = "<!-- 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/. --><svg viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M8,3L12,3L12,7L14,7L14,8L12,8L12,12L8,12L8,14L7,14L7,12L3,12L3,8L1,8L1,7L3,7L3,3L7,3L7,1L8,1L8,3ZM10,10L10,5L5,5L5,10L10,10Z\"></path></svg>"
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// Dependencies
+const React = __webpack_require__(0);
+const {
+  wrapRender
+} = __webpack_require__(1);
+const { MODE } = __webpack_require__(2);
+// Shortcuts
+const {
+  span
+} = React.DOM;
+/**
+ * Renders an object. An object is represented by a list of its
+ * properties enclosed in curly brackets.
+ */
+Accessor.propTypes = {
+  object: React.PropTypes.object.isRequired,
+  mode: React.PropTypes.oneOf(Object.values(MODE))
+};
+
+function Accessor(props) {
+  const {
+    object
+  } = props;
+
+  const accessors = [];
+  if (hasGetter(object)) {
+    accessors.push("Getter");
+  }
+  if (hasSetter(object)) {
+    accessors.push("Setter");
+  }
+  const title = accessors.join(" & ");
+
+  return span({ className: "objectBox objectBox-accessor" }, span({
+    className: "objectTitle"
+  }, title));
+}
+
+function hasGetter(object) {
+  return object && object.get && object.get.type !== "undefined";
+}
+
+function hasSetter(object) {
+  return object && object.set && object.set.type !== "undefined";
+}
+
+function supportsObject(object, noGrip = false) {
+  if (noGrip !== true && (hasGetter(object) || hasSetter(object))) {
+    return true;
+  }
+
+  return false;
+}
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(Accessor),
+  supportsObject
+};
+
+/***/ }),
 /* 37 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// ReactJS
-	const React = __webpack_require__(8);
-
-	// Reps
-	const {
-	  isGrip,
-	  cropString,
-	  wrapRender
-	} = __webpack_require__(7);
-	const { MODE } = __webpack_require__(1);
-	const Svg = __webpack_require__(33);
-
-	// Shortcuts
-	const DOM = React.DOM;
-
-	/**
-	 * Renders DOM #text node.
-	 */
-	TextNode.propTypes = {
-	  object: React.PropTypes.object.isRequired,
-	  // @TODO Change this to Object.values once it's supported in Node's version of V8
-	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
-	  onDOMNodeMouseOver: React.PropTypes.func,
-	  onDOMNodeMouseOut: React.PropTypes.func,
-	  onInspectIconClick: React.PropTypes.func
-	};
-
-	function TextNode(props) {
-	  let {
-	    object: grip,
-	    mode = MODE.SHORT,
-	    onDOMNodeMouseOver,
-	    onDOMNodeMouseOut,
-	    onInspectIconClick
-	  } = props;
-
-	  let baseConfig = {
-	    "data-link-actor-id": grip.actor,
-	    className: "objectBox objectBox-textNode"
-	  };
-	  let inspectIcon;
-	  let isInTree = grip.preview && grip.preview.isConnected === true;
-
-	  if (isInTree) {
-	    if (onDOMNodeMouseOver) {
-	      Object.assign(baseConfig, {
-	        onMouseOver: _ => onDOMNodeMouseOver(grip)
-	      });
-	    }
-
-	    if (onDOMNodeMouseOut) {
-	      Object.assign(baseConfig, {
-	        onMouseOut: onDOMNodeMouseOut
-	      });
-	    }
-
-	    if (onInspectIconClick) {
-	      inspectIcon = Svg("open-inspector", {
-	        element: "a",
-	        draggable: false,
-	        // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands
-	        title: "Click to select the node in the inspector",
-	        onClick: e => onInspectIconClick(grip, e)
-	      });
-	    }
-	  }
-
-	  if (mode === MODE.TINY) {
-	    return DOM.span(baseConfig, getTitle(grip), inspectIcon);
-	  }
-
-	  return DOM.span(baseConfig, getTitle(grip), DOM.span({ className: "nodeValue" }, " ", `"${getTextContent(grip)}"`), inspectIcon);
-	}
-
-	function getTextContent(grip) {
-	  return cropString(grip.preview.textContent);
-	}
-
-	function getTitle(grip) {
-	  const title = "#text";
-	  return DOM.span({}, title);
-	}
-
-	// Registration
-	function supportsObject(grip, type, noGrip = false) {
-	  if (noGrip === true || !isGrip(grip)) {
-	    return false;
-	  }
-
-	  return grip.preview && grip.class == "Text";
-	}
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(TextNode),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// ReactJS
+const React = __webpack_require__(0);
+
+// Reps
+const {
+  getGripType,
+  isGrip,
+  wrapRender
+} = __webpack_require__(1);
+const { rep: StringRep } = __webpack_require__(16);
+
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Renders DOM attribute
+ */
+Attribute.propTypes = {
+  object: React.PropTypes.object.isRequired
+};
+
+function Attribute(props) {
+  let {
+    object
+  } = props;
+  let value = object.preview.value;
+
+  return span({
+    "data-link-actor-id": object.actor,
+    className: "objectLink-Attr"
+  }, span({ className: "attrTitle" }, getTitle(object)), span({ className: "attrEqual" }, "="), StringRep({ object: value }));
+}
+
+function getTitle(grip) {
+  return grip.preview.nodeName;
+}
+
+// Registration
+function supportsObject(grip, noGrip = false) {
+  if (noGrip === true || !isGrip(grip)) {
+    return false;
+  }
+
+  return getGripType(grip, noGrip) == "Attr" && grip.preview;
+}
+
+module.exports = {
+  rep: wrapRender(Attribute),
+  supportsObject
+};
+
+/***/ }),
 /* 38 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// ReactJS
-	const React = __webpack_require__(8);
-	// Utils
-	const {
-	  isGrip,
-	  wrapRender
-	} = __webpack_require__(7);
-	const { MODE } = __webpack_require__(1);
-
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Renders Error objects.
-	 */
-	ErrorRep.propTypes = {
-	  object: React.PropTypes.object.isRequired,
-	  // @TODO Change this to Object.values once it's supported in Node's version of V8
-	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key]))
-	};
-
-	function ErrorRep(props) {
-	  let object = props.object;
-	  let preview = object.preview;
-	  let name = preview && preview.name ? preview.name : "Error";
-
-	  let content = props.mode === MODE.TINY ? name : `${name}: ${preview.message}`;
-
-	  if (preview.stack && props.mode !== MODE.TINY) {
-	    /*
-	      * Since Reps are used in the JSON Viewer, we can't localize
-	      * the "Stack trace" label (defined in debugger.properties as
-	      * "variablesViewErrorStacktrace" property), until Bug 1317038 lands.
-	      */
-	    content = `${content}\nStack trace:\n${preview.stack}`;
-	  }
-
-	  return span({
-	    "data-link-actor-id": object.actor,
-	    className: "objectBox-stackTrace"
-	  }, content);
-	}
-
-	// Registration
-	function supportsObject(object, type, noGrip = false) {
-	  if (noGrip === true || !isGrip(object)) {
-	    return false;
-	  }
-	  return object.preview && type === "Error";
-	}
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(ErrorRep),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// ReactJS
+const React = __webpack_require__(0);
+
+// Reps
+const {
+  getGripType,
+  isGrip,
+  wrapRender
+} = __webpack_require__(1);
+
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Used to render JS built-in Date() object.
+ */
+DateTime.propTypes = {
+  object: React.PropTypes.object.isRequired
+};
+
+function DateTime(props) {
+  let grip = props.object;
+  let date;
+  try {
+    date = span({
+      "data-link-actor-id": grip.actor,
+      className: "objectBox"
+    }, getTitle(grip), span({ className: "Date" }, new Date(grip.preview.timestamp).toISOString()));
+  } catch (e) {
+    date = span({ className: "objectBox" }, "Invalid Date");
+  }
+
+  return date;
+}
+
+function getTitle(grip) {
+  return span({
+    className: "objectTitle"
+  }, grip.class + " ");
+}
+
+// Registration
+function supportsObject(grip, noGrip = false) {
+  if (noGrip === true || !isGrip(grip)) {
+    return false;
+  }
+
+  return getGripType(grip, noGrip) == "Date" && grip.preview;
+}
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(DateTime),
+  supportsObject
+};
+
+/***/ }),
 /* 39 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// ReactJS
-	const React = __webpack_require__(8);
-
-	// Reps
-	const {
-	  isGrip,
-	  getURLDisplayString,
-	  wrapRender
-	} = __webpack_require__(7);
-
-	const { MODE } = __webpack_require__(1);
-
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Renders a grip representing a window.
-	 */
-	WindowRep.propTypes = {
-	  // @TODO Change this to Object.values once it's supported in Node's version of V8
-	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
-	  object: React.PropTypes.object.isRequired
-	};
-
-	function WindowRep(props) {
-	  let {
-	    mode,
-	    object
-	  } = props;
-
-	  const config = {
-	    "data-link-actor-id": object.actor,
-	    className: "objectBox objectBox-Window"
-	  };
-
-	  if (mode === MODE.TINY) {
-	    return span(config, getTitle(object));
-	  }
-
-	  return span(config, getTitle(object), " ", span({ className: "objectPropValue" }, getLocation(object)));
-	}
-
-	function getTitle(object) {
-	  let title = object.displayClass || object.class || "Window";
-	  return span({ className: "objectBoxTitle" }, title);
-	}
-
-	function getLocation(object) {
-	  return getURLDisplayString(object.preview.url);
-	}
-
-	// Registration
-	function supportsObject(object, type, noGrip = false) {
-	  if (noGrip === true || !isGrip(object)) {
-	    return false;
-	  }
-
-	  return object.preview && type == "Window";
-	}
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(WindowRep),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// ReactJS
+const React = __webpack_require__(0);
+
+// Reps
+const {
+  getGripType,
+  isGrip,
+  getURLDisplayString,
+  wrapRender
+} = __webpack_require__(1);
+
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Renders DOM document object.
+ */
+Document.propTypes = {
+  object: React.PropTypes.object.isRequired
+};
+
+function Document(props) {
+  let grip = props.object;
+
+  return span({
+    "data-link-actor-id": grip.actor,
+    className: "objectBox objectBox-object"
+  }, getTitle(grip), span({ className: "objectPropValue" }, getLocation(grip)));
+}
+
+function getLocation(grip) {
+  let location = grip.preview.location;
+  return location ? getURLDisplayString(location) : "";
+}
+
+function getTitle(grip) {
+  return span({
+    className: "objectTitle"
+  }, grip.class + " ");
+}
+
+// Registration
+function supportsObject(object, noGrip = false) {
+  if (noGrip === true || !isGrip(object)) {
+    return false;
+  }
+
+  return object.preview && getGripType(object, noGrip) == "HTMLDocument";
+}
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(Document),
+  supportsObject
+};
+
+/***/ }),
 /* 40 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// ReactJS
-	const React = __webpack_require__(8);
-
-	// Reps
-	const {
-	  isGrip,
-	  wrapRender
-	} = __webpack_require__(7);
-
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Renders a grip object with textual data.
-	 */
-	ObjectWithText.propTypes = {
-	  object: React.PropTypes.object.isRequired
-	};
-
-	function ObjectWithText(props) {
-	  let grip = props.object;
-	  return span({
-	    "data-link-actor-id": grip.actor,
-	    className: "objectBox objectBox-" + getType(grip)
-	  }, span({ className: "objectPropValue" }, getDescription(grip)));
-	}
-
-	function getType(grip) {
-	  return grip.class;
-	}
-
-	function getDescription(grip) {
-	  return "\"" + grip.preview.text + "\"";
-	}
-
-	// Registration
-	function supportsObject(grip, type, noGrip = false) {
-	  if (noGrip === true || !isGrip(grip)) {
-	    return false;
-	  }
-
-	  return grip.preview && grip.preview.kind == "ObjectWithText";
-	}
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(ObjectWithText),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// ReactJS
+const React = __webpack_require__(0);
+
+// Reps
+const {
+  isGrip,
+  wrapRender
+} = __webpack_require__(1);
+
+const { MODE } = __webpack_require__(2);
+const { rep } = __webpack_require__(9);
+
+/**
+ * Renders DOM event objects.
+ */
+Event.propTypes = {
+  object: React.PropTypes.object.isRequired,
+  // @TODO Change this to Object.values once it's supported in Node's version of V8
+  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
+  onDOMNodeMouseOver: React.PropTypes.func,
+  onDOMNodeMouseOut: React.PropTypes.func,
+  onInspectIconClick: React.PropTypes.func
+};
+
+function Event(props) {
+  // Use `Object.assign` to keep `props` without changes because:
+  // 1. JSON.stringify/JSON.parse is slow.
+  // 2. Immutable.js is planned for the future.
+  let gripProps = Object.assign({}, props, {
+    title: getTitle(props)
+  });
+  gripProps.object = Object.assign({}, props.object);
+  gripProps.object.preview = Object.assign({}, props.object.preview);
+
+  gripProps.object.preview.ownProperties = {};
+  if (gripProps.object.preview.target) {
+    Object.assign(gripProps.object.preview.ownProperties, {
+      target: gripProps.object.preview.target
+    });
+  }
+  Object.assign(gripProps.object.preview.ownProperties, gripProps.object.preview.properties);
+
+  delete gripProps.object.preview.properties;
+  gripProps.object.ownPropertyLength = Object.keys(gripProps.object.preview.ownProperties).length;
+
+  switch (gripProps.object.class) {
+    case "MouseEvent":
+      gripProps.isInterestingProp = (type, value, name) => {
+        return ["target", "clientX", "clientY", "layerX", "layerY"].includes(name);
+      };
+      break;
+    case "KeyboardEvent":
+      gripProps.isInterestingProp = (type, value, name) => {
+        return ["target", "key", "charCode", "keyCode"].includes(name);
+      };
+      break;
+    case "MessageEvent":
+      gripProps.isInterestingProp = (type, value, name) => {
+        return ["target", "isTrusted", "data"].includes(name);
+      };
+      break;
+    default:
+      gripProps.isInterestingProp = (type, value, name) => {
+        // We want to show the properties in the order they are declared.
+        return Object.keys(gripProps.object.preview.ownProperties).includes(name);
+      };
+  }
+
+  return rep(gripProps);
+}
+
+function getTitle(props) {
+  let preview = props.object.preview;
+  let title = preview.type;
+
+  if (preview.eventKind == "key" && preview.modifiers && preview.modifiers.length) {
+    title = `${title} ${preview.modifiers.join("-")}`;
+  }
+  return title;
+}
+
+// Registration
+function supportsObject(grip, noGrip = false) {
+  if (noGrip === true || !isGrip(grip)) {
+    return false;
+  }
+
+  return grip.preview && grip.preview.kind == "DOMEvent";
+}
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(Event),
+  supportsObject
+};
+
+/***/ }),
 /* 41 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// ReactJS
-	const React = __webpack_require__(8);
-
-	// Reps
-	const {
-	  isGrip,
-	  getURLDisplayString,
-	  wrapRender
-	} = __webpack_require__(7);
-
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Renders a grip object with URL data.
-	 */
-	ObjectWithURL.propTypes = {
-	  object: React.PropTypes.object.isRequired
-	};
-
-	function ObjectWithURL(props) {
-	  let grip = props.object;
-	  return span({
-	    "data-link-actor-id": grip.actor,
-	    className: "objectBox objectBox-" + getType(grip)
-	  }, getTitle(grip), span({ className: "objectPropValue" }, getDescription(grip)));
-	}
-
-	function getTitle(grip) {
-	  return span({ className: "objectTitle" }, getType(grip) + " ");
-	}
-
-	function getType(grip) {
-	  return grip.class;
-	}
-
-	function getDescription(grip) {
-	  return getURLDisplayString(grip.preview.url);
-	}
-
-	// Registration
-	function supportsObject(grip, type, noGrip = false) {
-	  if (noGrip === true || !isGrip(grip)) {
-	    return false;
-	  }
-
-	  return grip.preview && grip.preview.kind == "ObjectWithURL";
-	}
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(ObjectWithURL),
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// ReactJS
+const React = __webpack_require__(0);
+
+// Reps
+const {
+  getGripType,
+  isGrip,
+  cropString,
+  wrapRender
+} = __webpack_require__(1);
+
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * This component represents a template for Function objects.
+ */
+FunctionRep.propTypes = {
+  object: React.PropTypes.object.isRequired,
+  parameterNames: React.PropTypes.array
+};
+
+function FunctionRep(props) {
+  let grip = props.object;
+
+  return span({
+    "data-link-actor-id": grip.actor,
+    className: "objectBox objectBox-function",
+    // Set dir="ltr" to prevent function parentheses from
+    // appearing in the wrong direction
+    dir: "ltr"
+  }, getTitle(props, grip), getFunctionName(grip, props), "(", ...renderParams(props), ")");
+}
+
+function getTitle(props, grip) {
+  const {
+    simplified
+  } = props;
+
+  if (simplified === true && !grip.isGenerator && !grip.isAsync) {
+    return null;
+  }
+
+  let title = simplified === true ? "" : "function ";
+
+  if (grip.isGenerator) {
+    title = simplified === true ? "* " : "function* ";
+  }
+
+  if (grip.isAsync) {
+    title = "async" + " " + title;
+  }
+
+  return span({
+    className: "objectTitle"
+  }, title);
+}
+
+function getFunctionName(grip, props) {
+  let name = grip.userDisplayName || grip.displayName || grip.name || props.functionName || "";
+  return cropString(name, 100);
+}
+
+function renderParams(props) {
+  const {
+    parameterNames = []
+  } = props;
+
+  return parameterNames.filter(param => param).reduce((res, param, index, arr) => {
+    res.push(span({ className: "param" }, param));
+    if (index < arr.length - 1) {
+      res.push(span({ className: "delimiter" }, ", "));
+    }
+    return res;
+  }, []);
+}
+
+// Registration
+function supportsObject(grip, noGrip = false) {
+  const type = getGripType(grip, noGrip);
+  if (noGrip === true || !isGrip(grip)) {
+    return type == "function";
+  }
+
+  return type == "Function";
+}
+
+// Exports from this module
+
+module.exports = {
+  rep: wrapRender(FunctionRep),
+  supportsObject
+};
+
+/***/ }),
 /* 42 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// Dependencies
-	const React = __webpack_require__(8);
-	const {
-	  isGrip,
-	  wrapRender
-	} = __webpack_require__(7);
-	const { MODE } = __webpack_require__(1);
-
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Renders an array. The array is enclosed by left and right bracket
-	 * and the max number of rendered items depends on the current mode.
-	 */
-	GripArray.propTypes = {
-	  object: React.PropTypes.object.isRequired,
-	  // @TODO Change this to Object.values once it's supported in Node's version of V8
-	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
-	  provider: React.PropTypes.object,
-	  onDOMNodeMouseOver: React.PropTypes.func,
-	  onDOMNodeMouseOut: React.PropTypes.func,
-	  onInspectIconClick: React.PropTypes.func
-	};
-
-	function GripArray(props) {
-	  let {
-	    object,
-	    mode = MODE.SHORT
-	  } = props;
-
-	  let items;
-	  let brackets;
-	  let needSpace = function (space) {
-	    return space ? { left: "[ ", right: " ]" } : { left: "[", right: "]" };
-	  };
-
-	  if (mode === MODE.TINY) {
-	    let objectLength = getLength(object);
-	    let isEmpty = objectLength === 0;
-	    if (isEmpty) {
-	      items = [];
-	    } else {
-	      items = [span({
-	        className: "more-ellipsis",
-	        title: "more…"
-	      }, "…")];
-	    }
-	    brackets = needSpace(false);
-	  } else {
-	    let max = maxLengthMap.get(mode);
-	    items = arrayIterator(props, object, max);
-	    brackets = needSpace(items.length > 0);
-	  }
-
-	  let title = getTitle(props, object);
-
-	  return span({
-	    "data-link-actor-id": object.actor,
-	    className: "objectBox objectBox-array" }, title, span({
-	    className: "arrayLeftBracket"
-	  }, brackets.left), ...interleaveCommas(items), span({
-	    className: "arrayRightBracket"
-	  }, brackets.right), span({
-	    className: "arrayProperties",
-	    role: "group" }));
-	}
-
-	function interleaveCommas(items) {
-	  return items.reduce((res, item, index) => {
-	    if (index !== items.length - 1) {
-	      return res.concat(item, ", ");
-	    }
-	    return res.concat(item);
-	  }, []);
-	}
-
-	function getLength(grip) {
-	  if (!grip.preview) {
-	    return 0;
-	  }
-
-	  return grip.preview.length || grip.preview.childNodesLength || 0;
-	}
-
-	function getTitle(props, object) {
-	  if (props.mode === MODE.TINY) {
-	    return "";
-	  }
-
-	  let title = props.title || object.class || "Array";
-	  return span({
-	    className: "objectTitle"
-	  }, title + " ");
-	}
-
-	function getPreviewItems(grip) {
-	  if (!grip.preview) {
-	    return null;
-	  }
-
-	  return grip.preview.items || grip.preview.childNodes || [];
-	}
-
-	function arrayIterator(props, grip, max) {
-	  let { Rep } = __webpack_require__(2);
-
-	  let items = [];
-	  const gripLength = getLength(grip);
-
-	  if (!gripLength) {
-	    return items;
-	  }
-
-	  const previewItems = getPreviewItems(grip);
-	  let provider = props.provider;
-
-	  let emptySlots = 0;
-	  let foldedEmptySlots = 0;
-	  items = previewItems.reduce((res, itemGrip) => {
-	    if (res.length >= max) {
-	      return res;
-	    }
-
-	    let object;
-	    try {
-	      if (!provider && itemGrip === null) {
-	        emptySlots++;
-	        return res;
-	      }
-
-	      object = provider ? provider.getValue(itemGrip) : itemGrip;
-	    } catch (exc) {
-	      object = exc;
-	    }
-
-	    if (emptySlots > 0) {
-	      res.push(getEmptySlotsElement(emptySlots));
-	      foldedEmptySlots = foldedEmptySlots + emptySlots - 1;
-	      emptySlots = 0;
-	    }
-
-	    if (res.length < max) {
-	      res.push(Rep(Object.assign({}, props, {
-	        object,
-	        mode: MODE.TINY,
-	        // Do not propagate title to array items reps
-	        title: undefined
-	      })));
-	    }
-
-	    return res;
-	  }, []);
-
-	  // Handle trailing empty slots if there are some.
-	  if (items.length < max && emptySlots > 0) {
-	    items.push(getEmptySlotsElement(emptySlots));
-	    foldedEmptySlots = foldedEmptySlots + emptySlots - 1;
-	  }
-
-	  const itemsShown = items.length + foldedEmptySlots;
-	  if (gripLength > itemsShown) {
-	    items.push(span({
-	      className: "more-ellipsis",
-	      title: "more…"
-	    }, "…"));
-	  }
-
-	  return items;
-	}
-
-	function getEmptySlotsElement(number) {
-	  // TODO: Use l10N - See https://github.com/devtools-html/reps/issues/141
-	  return `<${number} empty slot${number > 1 ? "s" : ""}>`;
-	}
-
-	function supportsObject(grip, type, noGrip = false) {
-	  if (noGrip === true || !isGrip(grip)) {
-	    return false;
-	  }
-
-	  return grip.preview && (grip.preview.kind == "ArrayLike" || type === "DocumentFragment");
-	}
-
-	const maxLengthMap = new Map();
-	maxLengthMap.set(MODE.SHORT, 3);
-	maxLengthMap.set(MODE.LONG, 10);
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(GripArray),
-	  supportsObject,
-	  maxLengthMap
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// ReactJS
+const React = __webpack_require__(0);
+// Dependencies
+const {
+  getGripType,
+  isGrip,
+  wrapRender
+} = __webpack_require__(1);
+
+const PropRep = __webpack_require__(4);
+const { MODE } = __webpack_require__(2);
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Renders a DOM Promise object.
+ */
+PromiseRep.propTypes = {
+  object: React.PropTypes.object.isRequired,
+  // @TODO Change this to Object.values once it's supported in Node's version of V8
+  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
+  onDOMNodeMouseOver: React.PropTypes.func,
+  onDOMNodeMouseOut: React.PropTypes.func,
+  onInspectIconClick: React.PropTypes.func
+};
+
+function PromiseRep(props) {
+  const object = props.object;
+  const { promiseState } = object;
+
+  const config = {
+    "data-link-actor-id": object.actor,
+    className: "objectBox objectBox-object"
+  };
+
+  if (props.mode === MODE.TINY) {
+    let { Rep } = __webpack_require__(3);
+
+    return span(config, getTitle(object), span({
+      className: "objectLeftBrace"
+    }, " { "), Rep({ object: promiseState.state }), span({
+      className: "objectRightBrace"
+    }, " }"));
+  }
+
+  const propsArray = getProps(props, promiseState);
+  return span(config, getTitle(object), span({
+    className: "objectLeftBrace"
+  }, " { "), ...propsArray, span({
+    className: "objectRightBrace"
+  }, " }"));
+}
+
+function getTitle(object) {
+  return span({
+    className: "objectTitle"
+  }, object.class);
+}
+
+function getProps(props, promiseState) {
+  const keys = ["state"];
+  if (Object.keys(promiseState).includes("value")) {
+    keys.push("value");
+  }
+
+  return keys.reduce((res, key, i) => {
+    let object = promiseState[key];
+    res = res.concat(PropRep(Object.assign({}, props, {
+      mode: MODE.TINY,
+      name: `<${key}>`,
+      object,
+      equal: ": ",
+      suppressQuotes: true
+    })));
+
+    // Interleave commas between elements
+    if (i !== keys.length - 1) {
+      res.push(", ");
+    }
+
+    return res;
+  }, []);
+}
+
+// Registration
+function supportsObject(object, noGrip = false) {
+  if (noGrip === true || !isGrip(object)) {
+    return false;
+  }
+  return getGripType(object, noGrip) == "Promise";
+}
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(PromiseRep),
+  supportsObject
+};
+
+/***/ }),
 /* 43 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// Dependencies
-	const React = __webpack_require__(8);
-	const {
-	  isGrip,
-	  wrapRender
-	} = __webpack_require__(7);
-	const PropRep = __webpack_require__(16);
-	const { MODE } = __webpack_require__(1);
-	// Shortcuts
-	const { span } = React.DOM;
-
-	/**
-	 * Renders an map. A map is represented by a list of its
-	 * entries enclosed in curly brackets.
-	 */
-	GripMap.propTypes = {
-	  object: React.PropTypes.object,
-	  // @TODO Change this to Object.values once it's supported in Node's version of V8
-	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
-	  isInterestingEntry: React.PropTypes.func,
-	  onDOMNodeMouseOver: React.PropTypes.func,
-	  onDOMNodeMouseOut: React.PropTypes.func,
-	  onInspectIconClick: React.PropTypes.func,
-	  title: React.PropTypes.string
-	};
-
-	function GripMap(props) {
-	  let {
-	    mode,
-	    object
-	  } = props;
-
-	  const config = {
-	    "data-link-actor-id": object.actor,
-	    className: "objectBox objectBox-object"
-	  };
-
-	  if (mode === MODE.TINY) {
-	    return span(config, getTitle(props, object));
-	  }
-
-	  let propsArray = safeEntriesIterator(props, object, maxLengthMap.get(mode));
-
-	  return span(config, getTitle(props, object), span({
-	    className: "objectLeftBrace"
-	  }, " { "), ...propsArray, span({
-	    className: "objectRightBrace"
-	  }, " }"));
-	}
-
-	function getTitle(props, object) {
-	  let title = props.title || (object && object.class ? object.class : "Map");
-	  return span({
-	    className: "objectTitle"
-	  }, title);
-	}
-
-	function safeEntriesIterator(props, object, max) {
-	  max = typeof max === "undefined" ? 3 : max;
-	  try {
-	    return entriesIterator(props, object, max);
-	  } catch (err) {
-	    console.error(err);
-	  }
-	  return [];
-	}
-
-	function entriesIterator(props, object, max) {
-	  // Entry filter. Show only interesting entries to the user.
-	  let isInterestingEntry = props.isInterestingEntry || ((type, value) => {
-	    return type == "boolean" || type == "number" || type == "string" && value.length != 0;
-	  });
-
-	  let mapEntries = object.preview && object.preview.entries ? object.preview.entries : [];
-
-	  let indexes = getEntriesIndexes(mapEntries, max, isInterestingEntry);
-	  if (indexes.length < max && indexes.length < mapEntries.length) {
-	    // There are not enough entries yet, so we add uninteresting entries.
-	    indexes = indexes.concat(getEntriesIndexes(mapEntries, max - indexes.length, (t, value, name) => {
-	      return !isInterestingEntry(t, value, name);
-	    }));
-	  }
-
-	  let entries = getEntries(props, mapEntries, indexes);
-	  if (entries.length < object.preview.size) {
-	    // There are some undisplayed entries. Then display "…".
-	    entries.push(span({
-	      key: "more",
-	      className: "more-ellipsis",
-	      title: "more…"
-	    }, "…"));
-	  }
-
-	  return unfoldEntries(entries);
-	}
-
-	function unfoldEntries(items) {
-	  return items.reduce((res, item, index) => {
-	    if (Array.isArray(item)) {
-	      res = res.concat(item);
-	    } else {
-	      res.push(item);
-	    }
-
-	    // Interleave commas between elements
-	    if (index !== items.length - 1) {
-	      res.push(", ");
-	    }
-	    return res;
-	  }, []);
-	}
-
-	/**
-	 * Get entries ordered by index.
-	 *
-	 * @param {Object} props Component props.
-	 * @param {Array} entries Entries array.
-	 * @param {Array} indexes Indexes of entries.
-	 * @return {Array} Array of PropRep.
-	 */
-	function getEntries(props, entries, indexes) {
-	  let {
-	    onDOMNodeMouseOver,
-	    onDOMNodeMouseOut,
-	    onInspectIconClick
-	  } = props;
-
-	  // Make indexes ordered by ascending.
-	  indexes.sort(function (a, b) {
-	    return a - b;
-	  });
-
-	  return indexes.map((index, i) => {
-	    let [key, entryValue] = entries[index];
-	    let value = entryValue.value !== undefined ? entryValue.value : entryValue;
-
-	    return PropRep({
-	      name: key,
-	      equal: " \u2192 ",
-	      object: value,
-	      mode: MODE.TINY,
-	      onDOMNodeMouseOver,
-	      onDOMNodeMouseOut,
-	      onInspectIconClick
-	    });
-	  });
-	}
-
-	/**
-	 * Get the indexes of entries in the map.
-	 *
-	 * @param {Array} entries Entries array.
-	 * @param {Number} max The maximum length of indexes array.
-	 * @param {Function} filter Filter the entry you want.
-	 * @return {Array} Indexes of filtered entries in the map.
-	 */
-	function getEntriesIndexes(entries, max, filter) {
-	  return entries.reduce((indexes, [key, entry], i) => {
-	    if (indexes.length < max) {
-	      let value = entry && entry.value !== undefined ? entry.value : entry;
-	      // Type is specified in grip's "class" field and for primitive
-	      // values use typeof.
-	      let type = (value && value.class ? value.class : typeof value).toLowerCase();
-
-	      if (filter(type, value, key)) {
-	        indexes.push(i);
-	      }
-	    }
-
-	    return indexes;
-	  }, []);
-	}
-
-	function supportsObject(grip, type, noGrip = false) {
-	  if (noGrip === true || !isGrip(grip)) {
-	    return false;
-	  }
-	  return grip.preview && grip.preview.kind == "MapLike";
-	}
-
-	const maxLengthMap = new Map();
-	maxLengthMap.set(MODE.SHORT, 3);
-	maxLengthMap.set(MODE.LONG, 10);
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(GripMap),
-	  supportsObject,
-	  maxLengthMap
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// ReactJS
+const React = __webpack_require__(0);
+
+// Reps
+const {
+  getGripType,
+  isGrip,
+  wrapRender
+} = __webpack_require__(1);
+
+/**
+ * Renders a grip object with regular expression.
+ */
+RegExp.propTypes = {
+  object: React.PropTypes.object.isRequired
+};
+
+function RegExp(props) {
+  let { object } = props;
+
+  return React.DOM.span({
+    "data-link-actor-id": object.actor,
+    className: "objectBox objectBox-regexp regexpSource"
+  }, getSource(object));
+}
+
+function getSource(grip) {
+  return grip.displayString;
+}
+
+// Registration
+function supportsObject(object, noGrip = false) {
+  if (noGrip === true || !isGrip(object)) {
+    return false;
+  }
+
+  return getGripType(object, noGrip) == "RegExp";
+}
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(RegExp),
+  supportsObject
+};
+
+/***/ }),
 /* 44 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	// Dependencies
-	const React = __webpack_require__(8);
-	// Shortcuts
-	const { span } = React.DOM;
-	const {
-	  wrapRender
-	} = __webpack_require__(7);
-	const PropRep = __webpack_require__(16);
-	const { MODE } = __webpack_require__(1);
-	/**
-	 * Renders an map entry. A map entry is represented by its key, a column and its value.
-	 */
-	GripMapEntry.propTypes = {
-	  object: React.PropTypes.object,
-	  // @TODO Change this to Object.values once it's supported in Node's version of V8
-	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
-	  onDOMNodeMouseOver: React.PropTypes.func,
-	  onDOMNodeMouseOut: React.PropTypes.func,
-	  onInspectIconClick: React.PropTypes.func
-	};
-
-	function GripMapEntry(props) {
-	  const {
-	    object
-	  } = props;
-
-	  const {
-	    key,
-	    value
-	  } = object.preview;
-
-	  return span({
-	    className: "objectBox objectBox-map-entry"
-	  }, ...PropRep(Object.assign({}, props, {
-	    name: key,
-	    object: value,
-	    equal: " \u2192 ",
-	    title: null,
-	    suppressQuotes: false
-	  })));
-	}
-
-	function supportsObject(grip, type, noGrip = false) {
-	  if (noGrip === true) {
-	    return false;
-	  }
-	  return grip && grip.type === "mapEntry" && grip.preview;
-	}
-
-	function createGripMapEntry(key, value) {
-	  return {
-	    type: "mapEntry",
-	    preview: {
-	      key,
-	      value
-	    }
-	  };
-	}
-
-	// Exports from this module
-	module.exports = {
-	  rep: wrapRender(GripMapEntry),
-	  createGripMapEntry,
-	  supportsObject
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// ReactJS
+const React = __webpack_require__(0);
+
+// Reps
+const {
+  getGripType,
+  isGrip,
+  getURLDisplayString,
+  wrapRender
+} = __webpack_require__(1);
+
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Renders a grip representing CSSStyleSheet
+ */
+StyleSheet.propTypes = {
+  object: React.PropTypes.object.isRequired
+};
+
+function StyleSheet(props) {
+  let grip = props.object;
+
+  return span({
+    "data-link-actor-id": grip.actor,
+    className: "objectBox objectBox-object"
+  }, getTitle(grip), span({ className: "objectPropValue" }, getLocation(grip)));
+}
+
+function getTitle(grip) {
+  let title = "StyleSheet ";
+  return span({ className: "objectBoxTitle" }, title);
+}
+
+function getLocation(grip) {
+  // Embedded stylesheets don't have URL and so, no preview.
+  let url = grip.preview ? grip.preview.url : "";
+  return url ? getURLDisplayString(url) : "";
+}
+
+// Registration
+function supportsObject(object, noGrip = false) {
+  if (noGrip === true || !isGrip(object)) {
+    return false;
+  }
+
+  return getGripType(object, noGrip) == "CSSStyleSheet";
+}
+
+// Exports from this module
+
+module.exports = {
+  rep: wrapRender(StyleSheet),
+  supportsObject
+};
+
+/***/ }),
 /* 45 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	const {
-	  Component,
-	  createFactory,
-	  DOM: dom,
-	  PropTypes
-	} = __webpack_require__(8);
-
-	const Tree = createFactory(__webpack_require__(46).Tree);
-	__webpack_require__(48);
-
-	const classnames = __webpack_require__(50);
-	const Svg = __webpack_require__(33);
-	const {
-	  REPS: {
-	    Rep,
-	    Grip
-	  }
-	} = __webpack_require__(2);
-	const {
-	  MODE
-	} = __webpack_require__(1);
-
-	const {
-	  getChildren,
-	  getParent,
-	  getValue,
-	  nodeHasAccessors,
-	  nodeHasAllEntriesInPreview,
-	  nodeHasProperties,
-	  nodeIsDefaultProperties,
-	  nodeIsEntries,
-	  nodeIsMapEntry,
-	  nodeIsMissingArguments,
-	  nodeIsOptimizedOut,
-	  nodeIsPrimitive,
-	  nodeIsPrototype
-	} = __webpack_require__(51);
-
-	// This implements a component that renders an interactive inspector
-	// for looking at JavaScript objects. It expects descriptions of
-	// objects from the protocol, and will dynamically fetch child
-	// properties as objects are expanded.
-	//
-	// If you want to inspect a single object, pass the name and the
-	// protocol descriptor of it:
-	//
-	//  ObjectInspector({
-	//    name: "foo",
-	//    desc: { writable: true, ..., { value: { actor: "1", ... }}},
-	//    ...
-	//  })
-	//
-	// If you want multiple top-level objects (like scopes), you can pass
-	// an array of manually constructed nodes as `roots`:
-	//
-	//  ObjectInspector({
-	//    roots: [{ name: ... }, ...],
-	//    ...
-	//  });
-
-	// There are 3 types of nodes: a simple node with a children array, an
-	// object that has properties that should be children when they are
-	// fetched, and a primitive value that should be displayed with no
-	// children.
-
-	class ObjectInspector extends Component {
-	  constructor() {
-	    super();
-
-	    this.actors = {};
-	    this.state = {
-	      expandedKeys: new Set(),
-	      focusedItem: null
-	    };
-
-	    const self = this;
-
-	    self.getChildren = this.getChildren.bind(this);
-	    self.renderTreeItem = this.renderTreeItem.bind(this);
-	    self.setExpanded = this.setExpanded.bind(this);
-	    self.focusItem = this.focusItem.bind(this);
-	    self.getRoots = this.getRoots.bind(this);
-	  }
-
-	  getChildren(item) {
-	    const {
-	      getObjectEntries,
-	      getObjectProperties
-	    } = this.props;
-	    const { actors } = this;
-
-	    return getChildren({
-	      getObjectEntries,
-	      getObjectProperties,
-	      actors,
-	      item
-	    });
-	  }
-
-	  getRoots() {
-	    return this.props.roots;
-	  }
-
-	  getKey(item) {
-	    return item.path;
-	  }
-
-	  setExpanded(item, expand) {
-	    const { expandedKeys } = this.state;
-	    const key = this.getKey(item);
-
-	    if (expand === true) {
-	      expandedKeys.add(key);
-	    } else {
-	      expandedKeys.delete(key);
-	    }
-
-	    this.setState({ expandedKeys });
-
-	    if (expand === true) {
-	      const {
-	        getObjectProperties,
-	        getObjectEntries,
-	        loadObjectProperties,
-	        loadObjectEntries
-	      } = this.props;
-
-	      const value = getValue(item);
-	      const parent = getParent(item);
-	      const parentValue = getValue(parent);
-	      const parentActor = parentValue ? parentValue.actor : null;
-
-	      if (nodeHasProperties(item) && value && !getObjectProperties(value.actor)) {
-	        loadObjectProperties(value);
-	      }
-
-	      if (nodeIsEntries(item) && !nodeHasAllEntriesInPreview(parent) && parentActor && !getObjectEntries(parentActor)) {
-	        loadObjectEntries(parentValue);
-	      }
-	    }
-	  }
-
-	  focusItem(item) {
-	    if (!this.props.disabledFocus && this.state.focusedItem !== item) {
-	      this.setState({
-	        focusedItem: item
-	      });
-
-	      if (this.props.onFocus) {
-	        this.props.onFocus(item);
-	      }
-	    }
-	  }
-
-	  renderTreeItem(item, depth, focused, arrow, expanded) {
-	    let objectValue;
-	    let label = item.name;
-	    let itemValue = getValue(item);
-
-	    const isPrimitive = nodeIsPrimitive(item);
-
-	    const unavailable = isPrimitive && itemValue && itemValue.hasOwnProperty && itemValue.hasOwnProperty("unavailable");
-
-	    if (nodeIsOptimizedOut(item)) {
-	      objectValue = dom.span({ className: "unavailable" }, "(optimized away)");
-	    } else if (nodeIsMissingArguments(item) || unavailable) {
-	      objectValue = dom.span({ className: "unavailable" }, "(unavailable)");
-	    } else if (nodeHasProperties(item) || nodeHasAccessors(item) || nodeIsMapEntry(item) || isPrimitive) {
-	      let repsProp = Object.assign({}, this.props);
-	      if (depth > 0) {
-	        repsProp.mode = this.props.mode === MODE.LONG ? MODE.SHORT : MODE.TINY;
-	      }
-
-	      objectValue = this.renderGrip(item, repsProp);
-	    }
-
-	    const hasLabel = label !== null && typeof label !== "undefined";
-	    const hasValue = typeof objectValue !== "undefined";
-
-	    const SINGLE_INDENT_WIDTH = 15;
-	    const indentWidth = (depth + (isPrimitive ? 1 : 0)) * SINGLE_INDENT_WIDTH;
-
-	    const {
-	      onDoubleClick,
-	      onLabelClick
-	    } = this.props;
-
-	    return dom.div({
-	      className: classnames("node object-node", {
-	        focused,
-	        lessen: !expanded && (nodeIsDefaultProperties(item) || nodeIsPrototype(item))
-	      }),
-	      style: {
-	        marginLeft: indentWidth
-	      },
-	      onClick: isPrimitive === false ? e => {
-	        e.stopPropagation();
-	        this.setExpanded(item, !expanded);
-	      } : null,
-	      onDoubleClick: onDoubleClick ? e => {
-	        e.stopPropagation();
-	        onDoubleClick(item, {
-	          depth,
-	          focused,
-	          expanded
-	        });
-	      } : null
-	    }, isPrimitive === false ? Svg("arrow", {
-	      className: classnames({
-	        expanded: expanded
-	      })
-	    }) : null, hasLabel ? dom.span({
-	      className: "object-label",
-	      onClick: onLabelClick ? event => {
-	        event.stopPropagation();
-	        onLabelClick(item, {
-	          depth,
-	          focused,
-	          expanded,
-	          setExpanded: this.setExpanded
-	        });
-	      } : null
-	    }, label) : null, hasLabel && hasValue ? dom.span({ className: "object-delimiter" }, " : ") : null, hasValue ? objectValue : null);
-	  }
-
-	  renderGrip(item, props) {
-	    const object = getValue(item);
-	    return Rep(Object.assign({}, props, {
-	      object,
-	      mode: props.mode || MODE.TINY,
-	      defaultRep: Grip
-	    }));
-	  }
-
-	  render() {
-	    const {
-	      autoExpandDepth = 1,
-	      autoExpandAll = true,
-	      disabledFocus,
-	      itemHeight = 20,
-	      disableWrap = false
-	    } = this.props;
-
-	    const {
-	      expandedKeys,
-	      focusedItem
-	    } = this.state;
-
-	    let roots = this.getRoots();
-	    if (roots.length === 1 && nodeIsPrimitive(roots[0])) {
-	      return this.renderGrip(roots[0], this.props);
-	    }
-
-	    return Tree({
-	      className: disableWrap ? "nowrap" : "",
-	      autoExpandAll,
-	      autoExpandDepth,
-	      disabledFocus,
-	      itemHeight,
-
-	      isExpanded: item => expandedKeys.has(this.getKey(item)),
-	      focused: focusedItem,
-
-	      getRoots: this.getRoots,
-	      getParent,
-	      getChildren: this.getChildren,
-	      getKey: this.getKey,
-
-	      onExpand: item => this.setExpanded(item, true),
-	      onCollapse: item => this.setExpanded(item, false),
-	      onFocus: this.focusItem,
-
-	      renderItem: this.renderTreeItem
-	    });
-	  }
-	}
-
-	ObjectInspector.displayName = "ObjectInspector";
-
-	ObjectInspector.propTypes = {
-	  autoExpandAll: PropTypes.bool,
-	  autoExpandDepth: PropTypes.number,
-	  disabledFocus: PropTypes.bool,
-	  disableWrap: PropTypes.bool,
-	  roots: PropTypes.array,
-	  getObjectProperties: PropTypes.func.isRequired,
-	  loadObjectProperties: PropTypes.func.isRequired,
-	  itemHeight: PropTypes.number,
-	  mode: PropTypes.oneOf(Object.values(MODE)),
-	  onFocus: PropTypes.func,
-	  onDoubleClick: PropTypes.func,
-	  onLabelClick: PropTypes.func
-	};
-
-	module.exports = ObjectInspector;
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// Dependencies
+const React = __webpack_require__(0);
+const {
+  isGrip,
+  cropString,
+  cropMultipleLines,
+  wrapRender
+} = __webpack_require__(1);
+const { MODE } = __webpack_require__(2);
+const nodeConstants = __webpack_require__(18);
+
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Renders DOM comment node.
+ */
+CommentNode.propTypes = {
+  object: React.PropTypes.object.isRequired,
+  // @TODO Change this to Object.values once it's supported in Node's version of V8
+  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key]))
+};
+
+function CommentNode(props) {
+  let {
+    object,
+    mode = MODE.SHORT
+  } = props;
+
+  let { textContent } = object.preview;
+  if (mode === MODE.TINY) {
+    textContent = cropMultipleLines(textContent, 30);
+  } else if (mode === MODE.SHORT) {
+    textContent = cropString(textContent, 50);
+  }
+
+  return span({
+    className: "objectBox theme-comment",
+    "data-link-actor-id": object.actor
+  }, `<!-- ${textContent} -->`);
+}
+
+// Registration
+function supportsObject(object, noGrip = false) {
+  if (noGrip === true || !isGrip(object)) {
+    return false;
+  }
+  return object.preview && object.preview.nodeType === nodeConstants.COMMENT_NODE;
+}
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(CommentNode),
+  supportsObject
+};
+
+/***/ }),
 /* 46 */
-/***/ function(module, exports, __webpack_require__) {
-
-	const Tree = __webpack_require__(47);
-
-	module.exports = {
-	  Tree
-	};
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// ReactJS
+const React = __webpack_require__(0);
+
+// Utils
+const {
+  isGrip,
+  wrapRender
+} = __webpack_require__(1);
+const { MODE } = __webpack_require__(2);
+const nodeConstants = __webpack_require__(18);
+const Svg = __webpack_require__(10);
+
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Renders DOM element node.
+ */
+ElementNode.propTypes = {
+  object: React.PropTypes.object.isRequired,
+  // @TODO Change this to Object.values once it's supported in Node's version of V8
+  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
+  onDOMNodeMouseOver: React.PropTypes.func,
+  onDOMNodeMouseOut: React.PropTypes.func,
+  onInspectIconClick: React.PropTypes.func
+};
+
+function ElementNode(props) {
+  let {
+    object,
+    mode,
+    onDOMNodeMouseOver,
+    onDOMNodeMouseOut,
+    onInspectIconClick
+  } = props;
+  let elements = getElements(object, mode);
+
+  let isInTree = object.preview && object.preview.isConnected === true;
+
+  let baseConfig = {
+    "data-link-actor-id": object.actor,
+    className: "objectBox objectBox-node"
+  };
+  let inspectIcon;
+  if (isInTree) {
+    if (onDOMNodeMouseOver) {
+      Object.assign(baseConfig, {
+        onMouseOver: _ => onDOMNodeMouseOver(object)
+      });
+    }
+
+    if (onDOMNodeMouseOut) {
+      Object.assign(baseConfig, {
+        onMouseOut: onDOMNodeMouseOut
+      });
+    }
+
+    if (onInspectIconClick) {
+      inspectIcon = Svg("open-inspector", {
+        element: "a",
+        draggable: false,
+        // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands
+        title: "Click to select the node in the inspector",
+        onClick: e => onInspectIconClick(object, e)
+      });
+    }
+  }
+
+  return span(baseConfig, ...elements, inspectIcon);
+}
+
+function getElements(grip, mode) {
+  let { attributes, nodeName } = grip.preview;
+  const nodeNameElement = span({
+    className: "tag-name theme-fg-color3"
+  }, nodeName);
+
+  if (mode === MODE.TINY) {
+    let elements = [nodeNameElement];
+    if (attributes.id) {
+      elements.push(span({ className: "attr-name theme-fg-color2" }, `#${attributes.id}`));
+    }
+    if (attributes.class) {
+      elements.push(span({ className: "attr-name theme-fg-color2" }, attributes.class.replace(/(^\s+)|(\s+$)/g, "").split(" ").map(cls => `.${cls}`).join("")));
+    }
+    return elements;
+  }
+  let attributeKeys = Object.keys(attributes);
+  if (attributeKeys.includes("class")) {
+    attributeKeys.splice(attributeKeys.indexOf("class"), 1);
+    attributeKeys.unshift("class");
+  }
+  if (attributeKeys.includes("id")) {
+    attributeKeys.splice(attributeKeys.indexOf("id"), 1);
+    attributeKeys.unshift("id");
+  }
+  const attributeElements = attributeKeys.reduce((arr, name, i, keys) => {
+    let value = attributes[name];
+    let attribute = span({}, span({ className: "attr-name theme-fg-color2" }, `${name}`), `="`, span({ className: "attr-value theme-fg-color6" }, `${value}`), `"`);
+
+    return arr.concat([" ", attribute]);
+  }, []);
+
+  return ["<", nodeNameElement, ...attributeElements, ">"];
+}
+
+// Registration
+function supportsObject(object, noGrip = false) {
+  if (noGrip === true || !isGrip(object)) {
+    return false;
+  }
+  return object.preview && object.preview.nodeType === nodeConstants.ELEMENT_NODE;
+}
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(ElementNode),
+  supportsObject
+};
+
+/***/ }),
 /* 47 */
-/***/ function(module, exports, __webpack_require__) {
-
-	const { DOM: dom, createClass, createFactory, PropTypes } = __webpack_require__(8);
-
-	const AUTO_EXPAND_DEPTH = 0; // depth
-
-	/**
-	 * An arrow that displays whether its node is expanded (â–¼) or collapsed
-	 * (â–¶). When its node has no children, it is hidden.
-	 */
-	const ArrowExpander = createFactory(createClass({
-	  displayName: "ArrowExpander",
-
-	  shouldComponentUpdate(nextProps, nextState) {
-	    return this.props.item !== nextProps.item || this.props.visible !== nextProps.visible || this.props.expanded !== nextProps.expanded;
-	  },
-
-	  render() {
-	    const attrs = {
-	      className: "arrow theme-twisty",
-	      onClick: this.props.expanded ? () => this.props.onCollapse(this.props.item) : e => this.props.onExpand(this.props.item, e.altKey)
-	    };
-
-	    if (this.props.expanded) {
-	      attrs.className += " open";
-	    }
-
-	    if (!this.props.visible) {
-	      attrs.style = Object.assign({}, this.props.style || {}, {
-	        visibility: "hidden"
-	      });
-	    }
-
-	    return dom.div(attrs, this.props.children);
-	  }
-	}));
-
-	const TreeNode = createFactory(createClass({
-	  displayName: "TreeNode",
-
-	  componentDidMount() {
-	    if (this.props.focused) {
-	      this.refs.button.focus();
-	    }
-	  },
-
-	  componentDidUpdate() {
-	    if (this.props.focused) {
-	      this.refs.button.focus();
-	    }
-	  },
-
-	  shouldComponentUpdate(nextProps) {
-	    return this.props.item !== nextProps.item || this.props.focused !== nextProps.focused || this.props.expanded !== nextProps.expanded;
-	  },
-
-	  render() {
-	    const arrow = ArrowExpander({
-	      item: this.props.item,
-	      expanded: this.props.expanded,
-	      visible: this.props.hasChildren,
-	      onExpand: this.props.onExpand,
-	      onCollapse: this.props.onCollapse
-	    });
-
-	    let isOddRow = this.props.index % 2;
-	    return dom.div({
-	      className: `tree-node div ${isOddRow ? "tree-node-odd" : ""}`,
-	      onFocus: this.props.onFocus,
-	      onClick: this.props.onFocus,
-	      onBlur: this.props.onBlur,
-	      style: {
-	        padding: 0,
-	        margin: 0
-	      }
-	    }, this.props.renderItem(this.props.item, this.props.depth, this.props.focused, arrow, this.props.expanded),
-
-	    // XXX: OSX won't focus/blur regular elements even if you set tabindex
-	    // unless there is an input/button child.
-	    dom.button(this._buttonAttrs));
-	  },
-
-	  _buttonAttrs: {
-	    ref: "button",
-	    style: {
-	      opacity: 0,
-	      width: "0 !important",
-	      height: "0 !important",
-	      padding: "0 !important",
-	      outline: "none",
-	      MozAppearance: "none",
-	      // XXX: Despite resetting all of the above properties (and margin), the
-	      // button still ends up with ~79px width, so we set a large negative
-	      // margin to completely hide it.
-	      MozMarginStart: "-1000px !important"
-	    }
-	  }
-	}));
-
-	/**
-	 * Create a function that calls the given function `fn` only once per animation
-	 * frame.
-	 *
-	 * @param {Function} fn
-	 * @returns {Function}
-	 */
-	function oncePerAnimationFrame(fn) {
-	  let animationId = null;
-	  let argsToPass = null;
-	  return function (...args) {
-	    argsToPass = args;
-	    if (animationId !== null) {
-	      return;
-	    }
-
-	    animationId = requestAnimationFrame(() => {
-	      fn.call(this, ...argsToPass);
-	      animationId = null;
-	      argsToPass = null;
-	    });
-	  };
-	}
-
-	const NUMBER_OF_OFFSCREEN_ITEMS = 1;
-
-	/**
-	 * A generic tree component. See propTypes for the public API.
-	 *
-	 * @see `devtools/client/memory/components/test/mochitest/head.js` for usage
-	 * @see `devtools/client/memory/components/heap.js` for usage
-	 */
-	const Tree = module.exports = createClass({
-	  displayName: "Tree",
-
-	  propTypes: {
-	    // Required props
-
-	    // A function to get an item's parent, or null if it is a root.
-	    getParent: PropTypes.func.isRequired,
-	    // A function to get an item's children.
-	    getChildren: PropTypes.func.isRequired,
-	    // A function which takes an item and ArrowExpander and returns a
-	    // component.
-	    renderItem: PropTypes.func.isRequired,
-	    // A function which returns the roots of the tree (forest).
-	    getRoots: PropTypes.func.isRequired,
-	    // A function to get a unique key for the given item.
-	    getKey: PropTypes.func.isRequired,
-	    // A function to get whether an item is expanded or not. If an item is not
-	    // expanded, then it must be collapsed.
-	    isExpanded: PropTypes.func.isRequired,
-	    // The height of an item in the tree including margin and padding, in
-	    // pixels.
-	    itemHeight: PropTypes.number.isRequired,
-
-	    // Optional props
-
-	    // The currently focused item, if any such item exists.
-	    focused: PropTypes.any,
-	    // Handle when a new item is focused.
-	    onFocus: PropTypes.func,
-	    // The depth to which we should automatically expand new items.
-	    autoExpandDepth: PropTypes.number,
-	    // Should auto expand all new items or just the new items under the first
-	    // root item.
-	    autoExpandAll: PropTypes.bool,
-	    // Optional event handlers for when items are expanded or collapsed.
-	    onExpand: PropTypes.func,
-	    onCollapse: PropTypes.func
-	  },
-
-	  getDefaultProps() {
-	    return {
-	      autoExpandDepth: AUTO_EXPAND_DEPTH,
-	      autoExpandAll: true
-	    };
-	  },
-
-	  getInitialState() {
-	    return {
-	      scroll: 0,
-	      height: window.innerHeight,
-	      seen: new Set()
-	    };
-	  },
-
-	  componentDidMount() {
-	    window.addEventListener("resize", this._updateHeight);
-	    this._autoExpand(this.props);
-	    this._updateHeight();
-	  },
-
-	  componentWillUnmount() {
-	    window.removeEventListener("resize", this._updateHeight);
-	  },
-
-	  componentWillReceiveProps(nextProps) {
-	    this._autoExpand(nextProps);
-	    this._updateHeight();
-	  },
-
-	  _autoExpand(props) {
-	    if (!props.autoExpandDepth) {
-	      return;
-	    }
-
-	    // Automatically expand the first autoExpandDepth levels for new items. Do
-	    // not use the usual DFS infrastructure because we don't want to ignore
-	    // collapsed nodes.
-	    const autoExpand = (item, currentDepth) => {
-	      if (currentDepth >= props.autoExpandDepth || this.state.seen.has(item)) {
-	        return;
-	      }
-
-	      props.onExpand(item);
-	      this.state.seen.add(item);
-
-	      const children = props.getChildren(item);
-	      const length = children.length;
-	      for (let i = 0; i < length; i++) {
-	        autoExpand(children[i], currentDepth + 1);
-	      }
-	    };
-
-	    const roots = props.getRoots();
-	    const length = roots.length;
-	    if (props.autoExpandAll) {
-	      for (let i = 0; i < length; i++) {
-	        autoExpand(roots[i], 0);
-	      }
-	    } else if (length != 0) {
-	      autoExpand(roots[0], 0);
-	    }
-	  },
-
-	  render() {
-	    const traversal = this._dfsFromRoots();
-
-	    const renderItem = i => {
-	      let { item, depth } = traversal[i];
-	      return TreeNode({
-	        key: this.props.getKey(item, i),
-	        index: i,
-	        item: item,
-	        depth: depth,
-	        renderItem: this.props.renderItem,
-	        focused: this.props.focused === item,
-	        expanded: this.props.isExpanded(item),
-	        hasChildren: !!this.props.getChildren(item).length,
-	        onExpand: this._onExpand,
-	        onCollapse: this._onCollapse,
-	        onFocus: () => this._focus(i, item)
-	      });
-	    };
-
-	    const style = Object.assign({}, this.props.style || {}, {
-	      padding: 0,
-	      margin: 0
-	    });
-
-	    return dom.div({
-	      className: "tree",
-	      ref: "tree",
-	      onKeyDown: this._onKeyDown,
-	      onKeyPress: this._preventArrowKeyScrolling,
-	      onKeyUp: this._preventArrowKeyScrolling,
-	      onScroll: this._onScroll,
-	      style
-	    }, traversal.map((v, i) => renderItem(i)));
-	  },
-
-	  _preventArrowKeyScrolling(e) {
-	    switch (e.key) {
-	      case "ArrowUp":
-	      case "ArrowDown":
-	      case "ArrowLeft":
-	      case "ArrowRight":
-	        e.preventDefault();
-	        e.stopPropagation();
-	        if (e.nativeEvent) {
-	          if (e.nativeEvent.preventDefault) {
-	            e.nativeEvent.preventDefault();
-	          }
-	          if (e.nativeEvent.stopPropagation) {
-	            e.nativeEvent.stopPropagation();
-	          }
-	        }
-	    }
-	  },
-
-	  /**
-	   * Updates the state's height based on clientHeight.
-	   */
-	  _updateHeight() {
-	    this.setState({
-	      height: this.refs.tree.clientHeight
-	    });
-	  },
-
-	  /**
-	   * Perform a pre-order depth-first search from item.
-	   */
-	  _dfs(item, maxDepth = Infinity, traversal = [], _depth = 0) {
-	    traversal.push({ item, depth: _depth });
-
-	    if (!this.props.isExpanded(item)) {
-	      return traversal;
-	    }
-
-	    const nextDepth = _depth + 1;
-
-	    if (nextDepth > maxDepth) {
-	      return traversal;
-	    }
-
-	    const children = this.props.getChildren(item);
-	    const length = children.length;
-	    for (let i = 0; i < length; i++) {
-	      this._dfs(children[i], maxDepth, traversal, nextDepth);
-	    }
-
-	    return traversal;
-	  },
-
-	  /**
-	   * Perform a pre-order depth-first search over the whole forest.
-	   */
-	  _dfsFromRoots(maxDepth = Infinity) {
-	    const traversal = [];
-
-	    const roots = this.props.getRoots();
-	    const length = roots.length;
-	    for (let i = 0; i < length; i++) {
-	      this._dfs(roots[i], maxDepth, traversal);
-	    }
-
-	    return traversal;
-	  },
-
-	  /**
-	   * Expands current row.
-	   *
-	   * @param {Object} item
-	   * @param {Boolean} expandAllChildren
-	   */
-	  _onExpand: oncePerAnimationFrame(function (item, expandAllChildren) {
-	    if (this.props.onExpand) {
-	      this.props.onExpand(item);
-
-	      if (expandAllChildren) {
-	        const children = this._dfs(item);
-	        const length = children.length;
-	        for (let i = 0; i < length; i++) {
-	          this.props.onExpand(children[i].item);
-	        }
-	      }
-	    }
-	  }),
-
-	  /**
-	   * Collapses current row.
-	   *
-	   * @param {Object} item
-	   */
-	  _onCollapse: oncePerAnimationFrame(function (item) {
-	    if (this.props.onCollapse) {
-	      this.props.onCollapse(item);
-	    }
-	  }),
-
-	  /**
-	   * Sets the passed in item to be the focused item.
-	   *
-	   * @param {Number} index
-	   *        The index of the item in a full DFS traversal (ignoring collapsed
-	   *        nodes). Ignored if `item` is undefined.
-	   *
-	   * @param {Object|undefined} item
-	   *        The item to be focused, or undefined to focus no item.
-	   */
-	  _focus(index, item) {
-	    if (item !== undefined) {
-	      const itemStartPosition = index * this.props.itemHeight;
-	      const itemEndPosition = (index + 1) * this.props.itemHeight;
-
-	      // Note that if the height of the viewport (this.state.height) is less than
-	      // `this.props.itemHeight`, we could accidentally try and scroll both up and
-	      // down in a futile attempt to make both the item's start and end positions
-	      // visible. Instead, give priority to the start of the item by checking its
-	      // position first, and then using an "else if", rather than a separate "if",
-	      // for the end position.
-	      if (this.state.scroll > itemStartPosition) {
-	        this.refs.tree.scrollTop = itemStartPosition;
-	      } else if (this.state.scroll + this.state.height < itemEndPosition) {
-	        this.refs.tree.scrollTop = itemEndPosition - this.state.height;
-	      }
-	    }
-
-	    if (this.props.onFocus) {
-	      this.props.onFocus(item);
-	    }
-	  },
-
-	  /**
-	   * Sets the state to have no focused item.
-	   */
-	  _onBlur() {
-	    this._focus(0, undefined);
-	  },
-
-	  /**
-	   * Fired on a scroll within the tree's container, updates
-	   * the stored position of the view port to handle virtual view rendering.
-	   *
-	   * @param {Event} e
-	   */
-	  _onScroll: oncePerAnimationFrame(function (e) {
-	    this.setState({
-	      scroll: Math.max(this.refs.tree.scrollTop, 0),
-	      height: this.refs.tree.clientHeight
-	    });
-	  }),
-
-	  /**
-	   * Handles key down events in the tree's container.
-	   *
-	   * @param {Event} e
-	   */
-	  _onKeyDown(e) {
-	    if (this.props.focused == null) {
-	      return;
-	    }
-
-	    // Allow parent nodes to use navigation arrows with modifiers.
-	    if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) {
-	      return;
-	    }
-
-	    this._preventArrowKeyScrolling(e);
-
-	    switch (e.key) {
-	      case "ArrowUp":
-	        this._focusPrevNode();
-	        return;
-
-	      case "ArrowDown":
-	        this._focusNextNode();
-	        return;
-
-	      case "ArrowLeft":
-	        if (this.props.isExpanded(this.props.focused) && this.props.getChildren(this.props.focused).length) {
-	          this._onCollapse(this.props.focused);
-	        } else {
-	          this._focusParentNode();
-	        }
-	        return;
-
-	      case "ArrowRight":
-	        if (!this.props.isExpanded(this.props.focused)) {
-	          this._onExpand(this.props.focused);
-	        }
-	        return;
-	    }
-	  },
-
-	  /**
-	   * Sets the previous node relative to the currently focused item, to focused.
-	   */
-	  _focusPrevNode: oncePerAnimationFrame(function () {
-	    // Start a depth first search and keep going until we reach the currently
-	    // focused node. Focus the previous node in the DFS, if it exists. If it
-	    // doesn't exist, we're at the first node already.
-
-	    let prev;
-	    let prevIndex;
-
-	    const traversal = this._dfsFromRoots();
-	    const length = traversal.length;
-	    for (let i = 0; i < length; i++) {
-	      const item = traversal[i].item;
-	      if (item === this.props.focused) {
-	        break;
-	      }
-	      prev = item;
-	      prevIndex = i;
-	    }
-
-	    if (prev === undefined) {
-	      return;
-	    }
-
-	    this._focus(prevIndex, prev);
-	  }),
-
-	  /**
-	   * Handles the down arrow key which will focus either the next child
-	   * or sibling row.
-	   */
-	  _focusNextNode: oncePerAnimationFrame(function () {
-	    // Start a depth first search and keep going until we reach the currently
-	    // focused node. Focus the next node in the DFS, if it exists. If it
-	    // doesn't exist, we're at the last node already.
-
-	    const traversal = this._dfsFromRoots();
-	    const length = traversal.length;
-	    let i = 0;
-
-	    while (i < length) {
-	      if (traversal[i].item === this.props.focused) {
-	        break;
-	      }
-	      i++;
-	    }
-
-	    if (i + 1 < traversal.length) {
-	      this._focus(i + 1, traversal[i + 1].item);
-	    }
-	  }),
-
-	  /**
-	   * Handles the left arrow key, going back up to the current rows'
-	   * parent row.
-	   */
-	  _focusParentNode: oncePerAnimationFrame(function () {
-	    const parent = this.props.getParent(this.props.focused);
-	    if (!parent) {
-	      return;
-	    }
-
-	    const traversal = this._dfsFromRoots();
-	    const length = traversal.length;
-	    let parentIndex = 0;
-	    for (; parentIndex < length; parentIndex++) {
-	      if (traversal[parentIndex].item === parent) {
-	        break;
-	      }
-	    }
-
-	    this._focus(parentIndex, parent);
-	  })
-	});
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, '__esModule', {
+    value: true
+});
+
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var _react = __webpack_require__(0);
+
+var _react2 = _interopRequireDefault(_react);
+
+var DOMParser = typeof window !== 'undefined' && window.DOMParser;
+var process = process || {};
+process.env = process.env || {};
+var parserAvailable = typeof DOMParser !== 'undefined' && DOMParser.prototype != null && DOMParser.prototype.parseFromString != null;
+
+function isParsable(src) {
+    // kinda naive but meh, ain't gonna use full-blown parser for this
+    return parserAvailable && typeof src === 'string' && src.trim().substr(0, 4) === '<svg';
+}
+
+// parse SVG string using `DOMParser`
+function parseFromSVGString(src) {
+    var parser = new DOMParser();
+    return parser.parseFromString(src, "image/svg+xml");
+}
+
+// Transform DOM prop/attr names applicable to `<svg>` element but react-limited
+function switchSVGAttrToReactProp(propName) {
+    switch (propName) {
+        case 'class':
+            return 'className';
+        default:
+            return propName;
+    }
+}
+
+var InlineSVG = (function (_React$Component) {
+    _inherits(InlineSVG, _React$Component);
+
+    _createClass(InlineSVG, null, [{
+        key: 'defaultProps',
+        value: {
+            element: 'i',
+            raw: false,
+            src: ''
+        },
+        enumerable: true
+    }, {
+        key: 'propTypes',
+        value: {
+            src: _react2['default'].PropTypes.string.isRequired,
+            element: _react2['default'].PropTypes.string,
+            raw: _react2['default'].PropTypes.bool
+        },
+        enumerable: true
+    }]);
+
+    function InlineSVG(props) {
+        _classCallCheck(this, InlineSVG);
+
+        _get(Object.getPrototypeOf(InlineSVG.prototype), 'constructor', this).call(this, props);
+        this._extractSVGProps = this._extractSVGProps.bind(this);
+    }
+
+    // Serialize `Attr` objects in `NamedNodeMap`
+
+    _createClass(InlineSVG, [{
+        key: '_serializeAttrs',
+        value: function _serializeAttrs(map) {
+            var ret = {};
+            var prop = undefined;
+            for (var i = 0; i < map.length; i++) {
+                prop = switchSVGAttrToReactProp(map[i].name);
+                ret[prop] = map[i].value;
+            }
+            return ret;
+        }
+
+        // get <svg /> element props
+    }, {
+        key: '_extractSVGProps',
+        value: function _extractSVGProps(src) {
+            var map = parseFromSVGString(src).documentElement.attributes;
+            return map.length > 0 ? this._serializeAttrs(map) : null;
+        }
+
+        // get content inside <svg> element.
+    }, {
+        key: '_stripSVG',
+        value: function _stripSVG(src) {
+            return parseFromSVGString(src).documentElement.innerHTML;
+        }
+    }, {
+        key: 'componentWillReceiveProps',
+        value: function componentWillReceiveProps(_ref) {
+            var children = _ref.children;
+
+            if ("production" !== process.env.NODE_ENV && children != null) {
+                console.info('<InlineSVG />: `children` prop will be ignored.');
+            }
+        }
+    }, {
+        key: 'render',
+        value: function render() {
+            var Element = undefined,
+                __html = undefined,
+                svgProps = undefined;
+            var _props = this.props;
+            var element = _props.element;
+            var raw = _props.raw;
+            var src = _props.src;
+
+            var otherProps = _objectWithoutProperties(_props, ['element', 'raw', 'src']);
+
+            if (raw === true && isParsable(src)) {
+                Element = 'svg';
+                svgProps = this._extractSVGProps(src);
+                __html = this._stripSVG(src);
+            }
+            __html = __html || src;
+            Element = Element || element;
+            svgProps = svgProps || {};
+
+            return _react2['default'].createElement(Element, _extends({}, svgProps, otherProps, { src: null, children: null,
+                dangerouslySetInnerHTML: { __html: __html } }));
+        }
+    }]);
+
+    return InlineSVG;
+})(_react2['default'].Component);
+
+exports['default'] = InlineSVG;
+module.exports = exports['default'];
+
+/***/ }),
 /* 48 */
-/***/ function(module, exports) {
-
-	// removed by extract-text-webpack-plugin
-
-/***/ },
-/* 49 */,
+/***/ (function(module, exports) {
+
+module.exports = "<!-- 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/. --><svg viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M8 13.4c-.5 0-.9-.2-1.2-.6L.4 5.2C0 4.7-.1 4.3.2 3.7S1 3 1.6 3h12.8c.6 0 1.2.1 1.4.7.3.6.2 1.1-.2 1.6l-6.4 7.6c-.3.4-.7.5-1.2.5z\"></path></svg>"
+
+/***/ }),
+/* 49 */
+/***/ (function(module, exports) {
+
+module.exports = "<!-- 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/. --><svg viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M8,3L12,3L12,7L14,7L14,8L12,8L12,12L8,12L8,14L7,14L7,12L3,12L3,8L1,8L1,7L3,7L3,3L7,3L7,1L8,1L8,3ZM10,10L10,5L5,5L5,10L10,10Z\"></path></svg>"
+
+/***/ }),
 /* 50 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
-	  Copyright (c) 2016 Jed Watson.
-	  Licensed under the MIT License (MIT), see
-	  http://jedwatson.github.io/classnames
-	*/
-	/* global define */
-
-	(function () {
-		'use strict';
-
-		var hasOwn = {}.hasOwnProperty;
-
-		function classNames () {
-			var classes = [];
-
-			for (var i = 0; i < arguments.length; i++) {
-				var arg = arguments[i];
-				if (!arg) continue;
-
-				var argType = typeof arg;
-
-				if (argType === 'string' || argType === 'number') {
-					classes.push(arg);
-				} else if (Array.isArray(arg)) {
-					classes.push(classNames.apply(null, arg));
-				} else if (argType === 'object') {
-					for (var key in arg) {
-						if (hasOwn.call(arg, key) && arg[key]) {
-							classes.push(key);
-						}
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// ReactJS
+const React = __webpack_require__(0);
+
+// Reps
+const {
+  isGrip,
+  cropString,
+  wrapRender
+} = __webpack_require__(1);
+const { MODE } = __webpack_require__(2);
+const Svg = __webpack_require__(10);
+
+// Shortcuts
+const DOM = React.DOM;
+
+/**
+ * Renders DOM #text node.
+ */
+TextNode.propTypes = {
+  object: React.PropTypes.object.isRequired,
+  // @TODO Change this to Object.values once it's supported in Node's version of V8
+  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
+  onDOMNodeMouseOver: React.PropTypes.func,
+  onDOMNodeMouseOut: React.PropTypes.func,
+  onInspectIconClick: React.PropTypes.func
+};
+
+function TextNode(props) {
+  let {
+    object: grip,
+    mode = MODE.SHORT,
+    onDOMNodeMouseOver,
+    onDOMNodeMouseOut,
+    onInspectIconClick
+  } = props;
+
+  let baseConfig = {
+    "data-link-actor-id": grip.actor,
+    className: "objectBox objectBox-textNode"
+  };
+  let inspectIcon;
+  let isInTree = grip.preview && grip.preview.isConnected === true;
+
+  if (isInTree) {
+    if (onDOMNodeMouseOver) {
+      Object.assign(baseConfig, {
+        onMouseOver: _ => onDOMNodeMouseOver(grip)
+      });
+    }
+
+    if (onDOMNodeMouseOut) {
+      Object.assign(baseConfig, {
+        onMouseOut: onDOMNodeMouseOut
+      });
+    }
+
+    if (onInspectIconClick) {
+      inspectIcon = Svg("open-inspector", {
+        element: "a",
+        draggable: false,
+        // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands
+        title: "Click to select the node in the inspector",
+        onClick: e => onInspectIconClick(grip, e)
+      });
+    }
+  }
+
+  if (mode === MODE.TINY) {
+    return DOM.span(baseConfig, getTitle(grip), inspectIcon);
+  }
+
+  return DOM.span(baseConfig, getTitle(grip), DOM.span({ className: "nodeValue" }, " ", `"${getTextContent(grip)}"`), inspectIcon);
+}
+
+function getTextContent(grip) {
+  return cropString(grip.preview.textContent);
+}
+
+function getTitle(grip) {
+  const title = "#text";
+  return DOM.span({}, title);
+}
+
+// Registration
+function supportsObject(grip, noGrip = false) {
+  if (noGrip === true || !isGrip(grip)) {
+    return false;
+  }
+
+  return grip.preview && grip.class == "Text";
+}
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(TextNode),
+  supportsObject
+};
+
+/***/ }),
+/* 51 */
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// ReactJS
+const React = __webpack_require__(0);
+// Utils
+const {
+  getGripType,
+  isGrip,
+  wrapRender
+} = __webpack_require__(1);
+const { MODE } = __webpack_require__(2);
+
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Renders Error objects.
+ */
+ErrorRep.propTypes = {
+  object: React.PropTypes.object.isRequired,
+  // @TODO Change this to Object.values once it's supported in Node's version of V8
+  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key]))
+};
+
+function ErrorRep(props) {
+  let object = props.object;
+  let preview = object.preview;
+  let name = preview && preview.name ? preview.name : "Error";
+
+  let content = props.mode === MODE.TINY ? name : `${name}: ${preview.message}`;
+
+  if (preview.stack && props.mode !== MODE.TINY) {
+    /*
+      * Since Reps are used in the JSON Viewer, we can't localize
+      * the "Stack trace" label (defined in debugger.properties as
+      * "variablesViewErrorStacktrace" property), until Bug 1317038 lands.
+      */
+    content = `${content}\nStack trace:\n${preview.stack}`;
+  }
+
+  return span({
+    "data-link-actor-id": object.actor,
+    className: "objectBox-stackTrace"
+  }, content);
+}
+
+// Registration
+function supportsObject(object, noGrip = false) {
+  if (noGrip === true || !isGrip(object)) {
+    return false;
+  }
+  return object.preview && getGripType(object, noGrip) === "Error";
+}
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(ErrorRep),
+  supportsObject
+};
+
+/***/ }),
+/* 52 */
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// ReactJS
+const React = __webpack_require__(0);
+
+// Reps
+const {
+  getGripType,
+  isGrip,
+  getURLDisplayString,
+  wrapRender
+} = __webpack_require__(1);
+
+const { MODE } = __webpack_require__(2);
+
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Renders a grip representing a window.
+ */
+WindowRep.propTypes = {
+  // @TODO Change this to Object.values once it's supported in Node's version of V8
+  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
+  object: React.PropTypes.object.isRequired
+};
+
+function WindowRep(props) {
+  let {
+    mode,
+    object
+  } = props;
+
+  const config = {
+    "data-link-actor-id": object.actor,
+    className: "objectBox objectBox-Window"
+  };
+
+  if (mode === MODE.TINY) {
+    return span(config, getTitle(object));
+  }
+
+  return span(config, getTitle(object), " ", span({ className: "objectPropValue" }, getLocation(object)));
+}
+
+function getTitle(object) {
+  let title = object.displayClass || object.class || "Window";
+  return span({ className: "objectBoxTitle" }, title);
+}
+
+function getLocation(object) {
+  return getURLDisplayString(object.preview.url);
+}
+
+// Registration
+function supportsObject(object, noGrip = false) {
+  if (noGrip === true || !isGrip(object)) {
+    return false;
+  }
+
+  return object.preview && getGripType(object, noGrip) == "Window";
+}
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(WindowRep),
+  supportsObject
+};
+
+/***/ }),
+/* 53 */
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// ReactJS
+const React = __webpack_require__(0);
+
+// Reps
+const {
+  isGrip,
+  wrapRender
+} = __webpack_require__(1);
+
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Renders a grip object with textual data.
+ */
+ObjectWithText.propTypes = {
+  object: React.PropTypes.object.isRequired
+};
+
+function ObjectWithText(props) {
+  let grip = props.object;
+  return span({
+    "data-link-actor-id": grip.actor,
+    className: "objectBox objectBox-" + getType(grip)
+  }, span({ className: "objectPropValue" }, getDescription(grip)));
+}
+
+function getType(grip) {
+  return grip.class;
+}
+
+function getDescription(grip) {
+  return "\"" + grip.preview.text + "\"";
+}
+
+// Registration
+function supportsObject(grip, noGrip = false) {
+  if (noGrip === true || !isGrip(grip)) {
+    return false;
+  }
+
+  return grip.preview && grip.preview.kind == "ObjectWithText";
+}
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(ObjectWithText),
+  supportsObject
+};
+
+/***/ }),
+/* 54 */
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// ReactJS
+const React = __webpack_require__(0);
+
+// Reps
+const {
+  isGrip,
+  getURLDisplayString,
+  wrapRender
+} = __webpack_require__(1);
+
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Renders a grip object with URL data.
+ */
+ObjectWithURL.propTypes = {
+  object: React.PropTypes.object.isRequired
+};
+
+function ObjectWithURL(props) {
+  let grip = props.object;
+  return span({
+    "data-link-actor-id": grip.actor,
+    className: "objectBox objectBox-" + getType(grip)
+  }, getTitle(grip), span({ className: "objectPropValue" }, getDescription(grip)));
+}
+
+function getTitle(grip) {
+  return span({ className: "objectTitle" }, getType(grip) + " ");
+}
+
+function getType(grip) {
+  return grip.class;
+}
+
+function getDescription(grip) {
+  return getURLDisplayString(grip.preview.url);
+}
+
+// Registration
+function supportsObject(grip, noGrip = false) {
+  if (noGrip === true || !isGrip(grip)) {
+    return false;
+  }
+
+  return grip.preview && grip.preview.kind == "ObjectWithURL";
+}
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(ObjectWithURL),
+  supportsObject
+};
+
+/***/ }),
+/* 55 */
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+// Dependencies
+const React = __webpack_require__(0);
+const {
+  isGrip,
+  wrapRender
+} = __webpack_require__(1);
+const PropRep = __webpack_require__(4);
+const { MODE } = __webpack_require__(2);
+// Shortcuts
+const { span } = React.DOM;
+
+/**
+ * Renders an map. A map is represented by a list of its
+ * entries enclosed in curly brackets.
+ */
+GripMap.propTypes = {
+  object: React.PropTypes.object,
+  // @TODO Change this to Object.values once it's supported in Node's version of V8
+  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
+  isInterestingEntry: React.PropTypes.func,
+  onDOMNodeMouseOver: React.PropTypes.func,
+  onDOMNodeMouseOut: React.PropTypes.func,
+  onInspectIconClick: React.PropTypes.func,
+  title: React.PropTypes.string
+};
+
+function GripMap(props) {
+  let {
+    mode,
+    object
+  } = props;
+
+  const config = {
+    "data-link-actor-id": object.actor,
+    className: "objectBox objectBox-object"
+  };
+
+  if (mode === MODE.TINY) {
+    return span(config, getTitle(props, object));
+  }
+
+  let propsArray = safeEntriesIterator(props, object, maxLengthMap.get(mode));
+
+  return span(config, getTitle(props, object), span({
+    className: "objectLeftBrace"
+  }, " { "), ...propsArray, span({
+    className: "objectRightBrace"
+  }, " }"));
+}
+
+function getTitle(props, object) {
+  let title = props.title || (object && object.class ? object.class : "Map");
+  return span({
+    className: "objectTitle"
+  }, title);
+}
+
+function safeEntriesIterator(props, object, max) {
+  max = typeof max === "undefined" ? 3 : max;
+  try {
+    return entriesIterator(props, object, max);
+  } catch (err) {
+    console.error(err);
+  }
+  return [];
+}
+
+function entriesIterator(props, object, max) {
+  // Entry filter. Show only interesting entries to the user.
+  let isInterestingEntry = props.isInterestingEntry || ((type, value) => {
+    return type == "boolean" || type == "number" || type == "string" && value.length != 0;
+  });
+
+  let mapEntries = object.preview && object.preview.entries ? object.preview.entries : [];
+
+  let indexes = getEntriesIndexes(mapEntries, max, isInterestingEntry);
+  if (indexes.length < max && indexes.length < mapEntries.length) {
+    // There are not enough entries yet, so we add uninteresting entries.
+    indexes = indexes.concat(getEntriesIndexes(mapEntries, max - indexes.length, (t, value, name) => {
+      return !isInterestingEntry(t, value, name);
+    }));
+  }
+
+  let entries = getEntries(props, mapEntries, indexes);
+  if (entries.length < object.preview.size) {
+    // There are some undisplayed entries. Then display "…".
+    entries.push(span({
+      key: "more",
+      className: "more-ellipsis",
+      title: "more…"
+    }, "…"));
+  }
+
+  return unfoldEntries(entries);
+}
+
+function unfoldEntries(items) {
+  return items.reduce((res, item, index) => {
+    if (Array.isArray(item)) {
+      res = res.concat(item);
+    } else {
+      res.push(item);
+    }
+
+    // Interleave commas between elements
+    if (index !== items.length - 1) {
+      res.push(", ");
+    }
+    return res;
+  }, []);
+}
+
+/**
+ * Get entries ordered by index.
+ *
+ * @param {Object} props Component props.
+ * @param {Array} entries Entries array.
+ * @param {Array} indexes Indexes of entries.
+ * @return {Array} Array of PropRep.
+ */
+function getEntries(props, entries, indexes) {
+  let {
+    onDOMNodeMouseOver,
+    onDOMNodeMouseOut,
+    onInspectIconClick
+  } = props;
+
+  // Make indexes ordered by ascending.
+  indexes.sort(function (a, b) {
+    return a - b;
+  });
+
+  return indexes.map((index, i) => {
+    let [key, entryValue] = entries[index];
+    let value = entryValue.value !== undefined ? entryValue.value : entryValue;
+
+    return PropRep({
+      name: key,
+      equal: " \u2192 ",
+      object: value,
+      mode: MODE.TINY,
+      onDOMNodeMouseOver,
+      onDOMNodeMouseOut,
+      onInspectIconClick
+    });
+  });
+}
+
+/**
+ * Get the indexes of entries in the map.
+ *
+ * @param {Array} entries Entries array.
+ * @param {Number} max The maximum length of indexes array.
+ * @param {Function} filter Filter the entry you want.
+ * @return {Array} Indexes of filtered entries in the map.
+ */
+function getEntriesIndexes(entries, max, filter) {
+  return entries.reduce((indexes, [key, entry], i) => {
+    if (indexes.length < max) {
+      let value = entry && entry.value !== undefined ? entry.value : entry;
+      // Type is specified in grip's "class" field and for primitive
+      // values use typeof.
+      let type = (value && value.class ? value.class : typeof value).toLowerCase();
+
+      if (filter(type, value, key)) {
+        indexes.push(i);
+      }
+    }
+
+    return indexes;
+  }, []);
+}
+
+function supportsObject(grip, noGrip = false) {
+  if (noGrip === true || !isGrip(grip)) {
+    return false;
+  }
+  return grip.preview && grip.preview.kind == "MapLike";
+}
+
+const maxLengthMap = new Map();
+maxLengthMap.set(MODE.SHORT, 3);
+maxLengthMap.set(MODE.LONG, 10);
+
+// Exports from this module
+module.exports = {
+  rep: wrapRender(GripMap),
+  supportsObject,
+  maxLengthMap
+};
+
+/***/ }),
+/* 56 */
+/***/ (function(module, exports, __webpack_require__) {
+
+/* 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/. */
+
+const {
+  Component,
+  createFactory,
+  DOM: dom,
+  PropTypes
+} = __webpack_require__(0);
+
+const Tree = createFactory(__webpack_require__(57).Tree);
+__webpack_require__(59);
+
+const classnames = __webpack_require__(60);
+const Svg = __webpack_require__(10);
+const {
+  REPS: {
+    Rep,
+    Grip
+  }
+} = __webpack_require__(3);
+const {
+  MODE
+} = __webpack_require__(2);
+
+const {
+  getChildren,
+  getParent,
+  getValue,
+  nodeHasAccessors,
+  nodeHasAllEntriesInPreview,
+  nodeHasProperties,
+  nodeIsDefaultProperties,
+  nodeIsEntries,
+  nodeIsGetter,
+  nodeIsMapEntry,
+  nodeIsFunction,
+  nodeIsMissingArguments,
+  nodeIsOptimizedOut,
+  nodeIsPrimitive,
+  nodeIsPrototype,
+  nodeIsSetter,
+  nodeIsWindow
+} = __webpack_require__(21);
+
+// This implements a component that renders an interactive inspector
+// for looking at JavaScript objects. It expects descriptions of
+// objects from the protocol, and will dynamically fetch child
+// properties as objects are expanded.
+//
+// If you want to inspect a single object, pass the name and the
+// protocol descriptor of it:
+//
+//  ObjectInspector({
+//    name: "foo",
+//    desc: { writable: true, ..., { value: { actor: "1", ... }}},
+//    ...
+//  })
+//
+// If you want multiple top-level objects (like scopes), you can pass
+// an array of manually constructed nodes as `roots`:
+//
+//  ObjectInspector({
+//    roots: [{ name: ... }, ...],
+//    ...
+//  });
+
+// There are 3 types of nodes: a simple node with a children array, an
+// object that has properties that should be children when they are
+// fetched, and a primitive value that should be displayed with no
+// children.
+
+class ObjectInspector extends Component {
+  constructor() {
+    super();
+
+    this.actors = {};
+    this.state = {
+      expandedKeys: new Set(),
+      focusedItem: null
+    };
+
+    const self = this;
+
+    self.getChildren = this.getChildren.bind(this);
+    self.renderTreeItem = this.renderTreeItem.bind(this);
+    self.setExpanded = this.setExpanded.bind(this);
+    self.focusItem = this.focusItem.bind(this);
+    self.getRoots = this.getRoots.bind(this);
+  }
+
+  getChildren(item) {
+    const {
+      getObjectEntries,
+      getObjectProperties
+    } = this.props;
+    const { actors } = this;
+
+    return getChildren({
+      getObjectEntries,
+      getObjectProperties,
+      actors,
+      item
+    });
+  }
+
+  getRoots() {
+    return this.props.roots;
+  }
+
+  getKey(item) {
+    return item.path;
+  }
+
+  setExpanded(item, expand) {
+    const { expandedKeys } = this.state;
+    const key = this.getKey(item);
+
+    if (expand === true) {
+      expandedKeys.add(key);
+    } else {
+      expandedKeys.delete(key);
+    }
+
+    this.setState({ expandedKeys });
+
+    if (expand === true) {
+      const {
+        getObjectProperties,
+        getObjectEntries,
+        loadObjectProperties,
+        loadObjectEntries
+      } = this.props;
+
+      const value = getValue(item);
+      const parent = getParent(item);
+      const parentValue = getValue(parent);
+      const parentActor = parentValue ? parentValue.actor : null;
+
+      if (nodeHasProperties(item) && value && !getObjectProperties(value.actor)) {
+        loadObjectProperties(value);
+      }
+
+      if (nodeIsEntries(item) && !nodeHasAllEntriesInPreview(parent) && parentActor && !getObjectEntries(parentActor)) {
+        loadObjectEntries(parentValue);
+      }
+    }
+  }
+
+  focusItem(item) {
+    if (!this.props.disabledFocus && this.state.focusedItem !== item) {
+      this.setState({
+        focusedItem: item
+      });
+
+      if (this.props.onFocus) {
+        this.props.onFocus(item);
+      }
+    }
+  }
+
+  renderTreeItem(item, depth, focused, arrow, expanded) {
+    let objectValue;
+    let label = item.name;
+    let itemValue = getValue(item);
+
+    const isPrimitive = nodeIsPrimitive(item);
+
+    const unavailable = isPrimitive && itemValue && itemValue.hasOwnProperty && itemValue.hasOwnProperty("unavailable");
+
+    if (nodeIsOptimizedOut(item)) {
+      objectValue = dom.span({ className: "unavailable" }, "(optimized away)");
+    } else if (nodeIsMissingArguments(item) || unavailable) {
+      objectValue = dom.span({ className: "unavailable" }, "(unavailable)");
+    } else if (nodeIsFunction(item) && !nodeIsGetter(item) && !nodeIsSetter(item)) {
+      objectValue = undefined;
+      label = this.renderGrip(item, Object.assign({}, this.props, {
+        simplified: depth !== 0,
+        functionName: label
+      }));
+    } else if (nodeHasProperties(item) || nodeHasAccessors(item) || nodeIsMapEntry(item) || isPrimitive) {
+      let repsProp = Object.assign({}, this.props);
+      if (depth > 0) {
+        repsProp.mode = this.props.mode === MODE.LONG ? MODE.SHORT : MODE.TINY;
+      }
+
+      objectValue = this.renderGrip(item, repsProp);
+    }
+
+    const hasLabel = label !== null && typeof label !== "undefined";
+    const hasValue = typeof objectValue !== "undefined";
+
+    const SINGLE_INDENT_WIDTH = 15;
+    const indentWidth = (depth + (isPrimitive ? 1 : 0)) * SINGLE_INDENT_WIDTH;
+
+    const {
+      onDoubleClick,
+      onLabelClick,
+      dimTopLevelWindow
+    } = this.props;
+
+    return dom.div({
+      className: classnames("node object-node", {
+        focused,
+        lessen: !expanded && (nodeIsDefaultProperties(item) || nodeIsPrototype(item) || dimTopLevelWindow === true && nodeIsWindow(item) && depth === 0)
+      }),
+      style: {
+        marginLeft: indentWidth
+      },
+      onClick: isPrimitive === false ? e => {
+        e.stopPropagation();
+        this.setExpanded(item, !expanded);
+      } : null,
+      onDoubleClick: onDoubleClick ? e => {
+        e.stopPropagation();
+        onDoubleClick(item, {
+          depth,
+          focused,
+          expanded
+        });
+      } : null
+    }, isPrimitive === false ? Svg("arrow", {
+      className: classnames({
+        expanded: expanded
+      })
+    }) : null, hasLabel ? dom.span({
+      className: "object-label",
+      onClick: onLabelClick ? event => {
+        event.stopPropagation();
+        onLabelClick(item, {
+          depth,
+          focused,
+          expanded,
+          setExpanded: this.setExpanded
+        });
+      } : null
+    }, label) : null, hasLabel && hasValue ? dom.span({ className: "object-delimiter" }, " : ") : null, hasValue ? objectValue : null);
+  }
+
+  renderGrip(item, props) {
+    const object = getValue(item);
+    return Rep(Object.assign({}, props, {
+      object,
+      mode: props.mode || MODE.TINY,
+      defaultRep: Grip
+    }));
+  }
+
+  render() {
+    const {
+      autoExpandDepth = 1,
+      autoExpandAll = true,
+      disabledFocus,
+      itemHeight = 20,
+      disableWrap = false
+    } = this.props;
+
+    const {
+      expandedKeys,
+      focusedItem
+    } = this.state;
+
+    let roots = this.getRoots();
+    if (roots.length === 1 && nodeIsPrimitive(roots[0])) {
+      return this.renderGrip(roots[0], this.props);
+    }
+
+    return Tree({
+      className: disableWrap ? "nowrap" : "",
+      autoExpandAll,
+      autoExpandDepth,
+      disabledFocus,
+      itemHeight,
+
+      isExpanded: item => expandedKeys.has(this.getKey(item)),
+      focused: focusedItem,
+
+      getRoots: this.getRoots,
+      getParent,
+      getChildren: this.getChildren,
+      getKey: this.getKey,
+
+      onExpand: item => this.setExpanded(item, true),
+      onCollapse: item => this.setExpanded(item, false),
+      onFocus: this.focusItem,
+
+      renderItem: this.renderTreeItem
+    });
+  }
+}
+
+ObjectInspector.displayName = "ObjectInspector";
+
+ObjectInspector.propTypes = {
+  autoExpandAll: PropTypes.bool,
+  autoExpandDepth: PropTypes.number,
+  disabledFocus: PropTypes.bool,
+  disableWrap: PropTypes.bool,
+  roots: PropTypes.array,
+  getObjectProperties: PropTypes.func.isRequired,
+  loadObjectProperties: PropTypes.func.isRequired,
+  itemHeight: PropTypes.number,
+  mode: PropTypes.oneOf(Object.values(MODE)),
+  onFocus: PropTypes.func,
+  onDoubleClick: PropTypes.func,
+  onLabelClick: PropTypes.func
+};
+
+module.exports = ObjectInspector;
+
+/***/ }),
+/* 57 */
+/***/ (function(module, exports, __webpack_require__) {
+
+const Tree = __webpack_require__(58);
+
+module.exports = {
+  Tree
+};
+
+/***/ }),
+/* 58 */
+/***/ (function(module, exports, __webpack_require__) {
+
+const { DOM: dom, createClass, createFactory, PropTypes } = __webpack_require__(0);
+
+const AUTO_EXPAND_DEPTH = 0; // depth
+
+/**
+ * An arrow that displays whether its node is expanded (â–¼) or collapsed
+ * (â–¶). When its node has no children, it is hidden.
+ */
+const ArrowExpander = createFactory(createClass({
+  displayName: "ArrowExpander",
+
+  shouldComponentUpdate(nextProps, nextState) {
+    return this.props.item !== nextProps.item || this.props.visible !== nextProps.visible || this.props.expanded !== nextProps.expanded;
+  },
+
+  render() {
+    const attrs = {
+      className: "arrow theme-twisty",
+      onClick: this.props.expanded ? () => this.props.onCollapse(this.props.item) : e => this.props.onExpand(this.props.item, e.altKey)
+    };
+
+    if (this.props.expanded) {
+      attrs.className += " open";
+    }
+
+    if (!this.props.visible) {
+      attrs.style = Object.assign({}, this.props.style || {}, {
+        visibility: "hidden"
+      });
+    }
+
+    return dom.div(attrs, this.props.children);
+  }
+}));
+
+const TreeNode = createFactory(createClass({
+  displayName: "TreeNode",
+
+  componentDidMount() {
+    if (this.props.focused) {
+      this.refs.button.focus();
+    }
+  },
+
+  componentDidUpdate() {
+    if (this.props.focused) {
+      this.refs.button.focus();
+    }
+  },
+
+  shouldComponentUpdate(nextProps) {
+    return this.props.item !== nextProps.item || this.props.focused !== nextProps.focused || this.props.expanded !== nextProps.expanded;
+  },
+
+  render() {
+    const arrow = ArrowExpander({
+      item: this.props.item,
+      expanded: this.props.expanded,
+      visible: this.props.hasChildren,
+      onExpand: this.props.onExpand,
+      onCollapse: this.props.onCollapse
+    });
+
+    let isOddRow = this.props.index % 2;
+    return dom.div({
+      className: `tree-node div ${isOddRow ? "tree-node-odd" : ""}`,
+      onFocus: this.props.onFocus,
+      onClick: this.props.onFocus,
+      onBlur: this.props.onBlur,
+      style: {
+        padding: 0,
+        margin: 0
+      }
+    }, this.props.renderItem(this.props.item, this.props.depth, this.props.focused, arrow, this.props.expanded),
+
+    // XXX: OSX won't focus/blur regular elements even if you set tabindex
+    // unless there is an input/button child.
+    dom.button(this._buttonAttrs));
+  },
+
+  _buttonAttrs: {
+    ref: "button",
+    style: {
+      opacity: 0,
+      width: "0 !important",
+      height: "0 !important",
+      padding: "0 !important",
+      outline: "none",
+      MozAppearance: "none",
+      // XXX: Despite resetting all of the above properties (and margin), the
+      // button still ends up with ~79px width, so we set a large negative
+      // margin to completely hide it.
+      MozMarginStart: "-1000px !important"
+    }
+  }
+}));
+
+/**
+ * Create a function that calls the given function `fn` only once per animation
+ * frame.
+ *
+ * @param {Function} fn
+ * @returns {Function}
+ */
+function oncePerAnimationFrame(fn) {
+  let animationId = null;
+  let argsToPass = null;
+  return function (...args) {
+    argsToPass = args;
+    if (animationId !== null) {
+      return;
+    }
+
+    animationId = requestAnimationFrame(() => {
+      fn.call(this, ...argsToPass);
+      animationId = null;
+      argsToPass = null;
+    });
+  };
+}
+
+const NUMBER_OF_OFFSCREEN_ITEMS = 1;
+
+/**
+ * A generic tree component. See propTypes for the public API.
+ *
+ * @see `devtools/client/memory/components/test/mochitest/head.js` for usage
+ * @see `devtools/client/memory/components/heap.js` for usage
+ */
+const Tree = module.exports = createClass({
+  displayName: "Tree",
+
+  propTypes: {
+    // Required props
+
+    // A function to get an item's parent, or null if it is a root.
+    getParent: PropTypes.func.isRequired,
+    // A function to get an item's children.
+    getChildren: PropTypes.func.isRequired,
+    // A function which takes an item and ArrowExpander and returns a
+    // component.
+    renderItem: PropTypes.func.isRequired,
+    // A function which returns the roots of the tree (forest).
+    getRoots: PropTypes.func.isRequired,
+    // A function to get a unique key for the given item.
+    getKey: PropTypes.func.isRequired,
+    // A function to get whether an item is expanded or not. If an item is not
+    // expanded, then it must be collapsed.
+    isExpanded: PropTypes.func.isRequired,
+    // The height of an item in the tree including margin and padding, in
+    // pixels.
+    itemHeight: PropTypes.number.isRequired,
+
+    // Optional props
+
+    // The currently focused item, if any such item exists.
+    focused: PropTypes.any,
+    // Handle when a new item is focused.
+    onFocus: PropTypes.func,
+    // The depth to which we should automatically expand new items.
+    autoExpandDepth: PropTypes.number,
+    // Should auto expand all new items or just the new items under the first
+    // root item.
+    autoExpandAll: PropTypes.bool,
+    // Optional event handlers for when items are expanded or collapsed.
+    onExpand: PropTypes.func,
+    onCollapse: PropTypes.func
+  },
+
+  getDefaultProps() {
+    return {
+      autoExpandDepth: AUTO_EXPAND_DEPTH,
+      autoExpandAll: true
+    };
+  },
+
+  getInitialState() {
+    return {
+      scroll: 0,
+      height: window.innerHeight,
+      seen: new Set()
+    };
+  },
+
+  componentDidMount() {
+    window.addEventListener("resize", this._updateHeight);
+    this._autoExpand(this.props);
+    this._updateHeight();
+  },
+
+  componentWillUnmount() {
+    window.removeEventListener("resize", this._updateHeight);
+  },
+
+  componentWillReceiveProps(nextProps) {
+    this._autoExpand(nextProps);
+    this._updateHeight();
+  },
+
+  _autoExpand(props) {
+    if (!props.autoExpandDepth) {
+      return;
+    }
+
+    // Automatically expand the first autoExpandDepth levels for new items. Do
+    // not use the usual DFS infrastructure because we don't want to ignore
+    // collapsed nodes.
+    const autoExpand = (item, currentDepth) => {
+      if (currentDepth >= props.autoExpandDepth || this.state.seen.has(item)) {
+        return;
+      }
+
+      props.onExpand(item);
+      this.state.seen.add(item);
+
+      const children = props.getChildren(item);
+      const length = children.length;
+      for (let i = 0; i < length; i++) {
+        autoExpand(children[i], currentDepth + 1);
+      }
+    };
+
+    const roots = props.getRoots();
+    const length = roots.length;
+    if (props.autoExpandAll) {
+      for (let i = 0; i < length; i++) {
+        autoExpand(roots[i], 0);
+      }
+    } else if (length != 0) {
+      autoExpand(roots[0], 0);
+    }
+  },
+
+  render() {
+    const traversal = this._dfsFromRoots();
+
+    const renderItem = i => {
+      let { item, depth } = traversal[i];
+      return TreeNode({
+        key: this.props.getKey(item, i),
+        index: i,
+        item: item,
+        depth: depth,
+        renderItem: this.props.renderItem,
+        focused: this.props.focused === item,
+        expanded: this.props.isExpanded(item),
+        hasChildren: !!this.props.getChildren(item).length,
+        onExpand: this._onExpand,
+        onCollapse: this._onCollapse,
+        onFocus: () => this._focus(i, item)
+      });
+    };
+
+    const style = Object.assign({}, this.props.style || {}, {
+      padding: 0,
+      margin: 0
+    });
+
+    return dom.div({
+      className: "tree",
+      ref: "tree",
+      onKeyDown: this._onKeyDown,
+      onKeyPress: this._preventArrowKeyScrolling,
+      onKeyUp: this._preventArrowKeyScrolling,
+      onScroll: this._onScroll,
+      style
+    }, traversal.map((v, i) => renderItem(i)));
+  },
+
+  _preventArrowKeyScrolling(e) {
+    switch (e.key) {
+      case "ArrowUp":
+      case "ArrowDown":
+      case "ArrowLeft":
+      case "ArrowRight":
+        e.preventDefault();
+        e.stopPropagation();
+        if (e.nativeEvent) {
+          if (e.nativeEvent.preventDefault) {
+            e.nativeEvent.preventDefault();
+          }
+          if (e.nativeEvent.stopPropagation) {
+            e.nativeEvent.stopPropagation();
+          }
+        }
+    }
+  },
+
+  /**
+   * Updates the state's height based on clientHeight.
+   */
+  _updateHeight() {
+    this.setState({
+      height: this.refs.tree.clientHeight
+    });
+  },
+
+  /**
+   * Perform a pre-order depth-first search from item.
+   */
+  _dfs(item, maxDepth = Infinity, traversal = [], _depth = 0) {
+    traversal.push({ item, depth: _depth });
+
+    if (!this.props.isExpanded(item)) {
+      return traversal;
+    }
+
+    const nextDepth = _depth + 1;
+
+    if (nextDepth > maxDepth) {
+      return traversal;
+    }
+
+    const children = this.props.getChildren(item);
+    const length = children.length;
+    for (let i = 0; i < length; i++) {
+      this._dfs(children[i], maxDepth, traversal, nextDepth);
+    }
+
+    return traversal;
+  },
+
+  /**
+   * Perform a pre-order depth-first search over the whole forest.
+   */
+  _dfsFromRoots(maxDepth = Infinity) {
+    const traversal = [];
+
+    const roots = this.props.getRoots();
+    const length = roots.length;
+    for (let i = 0; i < length; i++) {
+      this._dfs(roots[i], maxDepth, traversal);
+    }
+
+    return traversal;
+  },
+
+  /**
+   * Expands current row.
+   *
+   * @param {Object} item
+   * @param {Boolean} expandAllChildren
+   */
+  _onExpand: oncePerAnimationFrame(function (item, expandAllChildren) {
+    if (this.props.onExpand) {
+      this.props.onExpand(item);
+
+      if (expandAllChildren) {
+        const children = this._dfs(item);
+        const length = children.length;
+        for (let i = 0; i < length; i++) {
+          this.props.onExpand(children[i].item);
+        }
+      }
+    }
+  }),
+
+  /**
+   * Collapses current row.
+   *
+   * @param {Object} item
+   */
+  _onCollapse: oncePerAnimationFrame(function (item) {
+    if (this.props.onCollapse) {
+      this.props.onCollapse(item);
+    }
+  }),
+
+  /**
+   * Sets the passed in item to be the focused item.
+   *
+   * @param {Number} index
+   *        The index of the item in a full DFS traversal (ignoring collapsed
+   *        nodes). Ignored if `item` is undefined.
+   *
+   * @param {Object|undefined} item
+   *        The item to be focused, or undefined to focus no item.
+   */
+  _focus(index, item) {
+    if (item !== undefined) {
+      const itemStartPosition = index * this.props.itemHeight;
+      const itemEndPosition = (index + 1) * this.props.itemHeight;
+
+      // Note that if the height of the viewport (this.state.height) is less than
+      // `this.props.itemHeight`, we could accidentally try and scroll both up and
+      // down in a futile attempt to make both the item's start and end positions
+      // visible. Instead, give priority to the start of the item by checking its
+      // position first, and then using an "else if", rather than a separate "if",
+      // for the end position.
+      if (this.state.scroll > itemStartPosition) {
+        this.refs.tree.scrollTop = itemStartPosition;
+      } else if (this.state.scroll + this.state.height < itemEndPosition) {
+        this.refs.tree.scrollTop = itemEndPosition - this.state.height;
+      }
+    }
+
+    if (this.props.onFocus) {
+      this.props.onFocus(item);
+    }
+  },
+
+  /**
+   * Sets the state to have no focused item.
+   */
+  _onBlur() {
+    this._focus(0, undefined);
+  },
+
+  /**
+   * Fired on a scroll within the tree's container, updates
+   * the stored position of the view port to handle virtual view rendering.
+   *
+   * @param {Event} e
+   */
+  _onScroll: oncePerAnimationFrame(function (e) {
+    this.setState({
+      scroll: Math.max(this.refs.tree.scrollTop, 0),
+      height: this.refs.tree.clientHeight
+    });
+  }),
+
+  /**
+   * Handles key down events in the tree's container.
+   *
+   * @param {Event} e
+   */
+  _onKeyDown(e) {
+    if (this.props.focused == null) {
+      return;
+    }
+
+    // Allow parent nodes to use navigation arrows with modifiers.
+    if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) {
+      return;
+    }
+
+    this._preventArrowKeyScrolling(e);
+
+    switch (e.key) {
+      case "ArrowUp":
+        this._focusPrevNode();
+        return;
+
+      case "ArrowDown":
+        this._focusNextNode();
+        return;
+
+      case "ArrowLeft":
+        if (this.props.isExpanded(this.props.focused) && this.props.getChildren(this.props.focused).length) {
+          this._onCollapse(this.props.focused);
+        } else {
+          this._focusParentNode();
+        }
+        return;
+
+      case "ArrowRight":
+        if (!this.props.isExpanded(this.props.focused)) {
+          this._onExpand(this.props.focused);
+        }
+        return;
+    }
+  },
+
+  /**
+   * Sets the previous node relative to the currently focused item, to focused.
+   */
+  _focusPrevNode: oncePerAnimationFrame(function () {
+    // Start a depth first search and keep going until we reach the currently
+    // focused node. Focus the previous node in the DFS, if it exists. If it
+    // doesn't exist, we're at the first node already.
+
+    let prev;
+    let prevIndex;
+
+    const traversal = this._dfsFromRoots();
+    const length = traversal.length;
+    for (let i = 0; i < length; i++) {
+      const item = traversal[i].item;
+      if (item === this.props.focused) {
+        break;
+      }
+      prev = item;
+      prevIndex = i;
+    }
+
+    if (prev === undefined) {
+      return;
+    }
+
+    this._focus(prevIndex, prev);
+  }),
+
+  /**
+   * Handles the down arrow key which will focus either the next child
+   * or sibling row.
+   */
+  _focusNextNode: oncePerAnimationFrame(function () {
+    // Start a depth first search and keep going until we reach the currently
+    // focused node. Focus the next node in the DFS, if it exists. If it
+    // doesn't exist, we're at the last node already.
+
+    const traversal = this._dfsFromRoots();
+    const length = traversal.length;
+    let i = 0;
+
+    while (i < length) {
+      if (traversal[i].item === this.props.focused) {
+        break;
+      }
+      i++;
+    }
+
+    if (i + 1 < traversal.length) {
+      this._focus(i + 1, traversal[i + 1].item);
+    }
+  }),
+
+  /**
+   * Handles the left arrow key, going back up to the current rows'
+   * parent row.
+   */
+  _focusParentNode: oncePerAnimationFrame(function () {
+    const parent = this.props.getParent(this.props.focused);
+    if (!parent) {
+      return;
+    }
+
+    const traversal = this._dfsFromRoots();
+    const length = traversal.length;
+    let parentIndex = 0;
+    for (; parentIndex < length; parentIndex++) {
+      if (traversal[parentIndex].item === parent) {
+        break;
+      }
+    }
+
+    this._focus(parentIndex, parent);
+  })
+});
+
+/***/ }),
+/* 59 */
+/***/ (function(module, exports) {
+
+// removed by extract-text-webpack-plugin
+
+/***/ }),
+/* 60 */
+/***/ (function(module, exports, __webpack_require__) {
+
+var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
+  Copyright (c) 2016 Jed Watson.
+  Licensed under the MIT License (MIT), see
+  http://jedwatson.github.io/classnames
+*/
+/* global define */
+
+(function () {
+	'use strict';
+
+	var hasOwn = {}.hasOwnProperty;
+
+	function classNames () {
+		var classes = [];
+
+		for (var i = 0; i < arguments.length; i++) {
+			var arg = arguments[i];
+			if (!arg) continue;
+
+			var argType = typeof arg;
+
+			if (argType === 'string' || argType === 'number') {
+				classes.push(arg);
+			} else if (Array.isArray(arg)) {
+				classes.push(classNames.apply(null, arg));
+			} else if (argType === 'object') {
+				for (var key in arg) {
+					if (hasOwn.call(arg, key) && arg[key]) {
+						classes.push(key);
 					}
 				}
 			}
-
-			return classes.join(' ');
 		}
 
-		if (typeof module !== 'undefined' && module.exports) {
-			module.exports = classNames;
-		} else if (true) {
-			// register as 'classnames', consistent with npm package name
-			!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () {
-				return classNames;
-			}.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-		} else {
-			window.classNames = classNames;
-		}
-	}());
-
-
-/***/ },
-/* 51 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* 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/. */
-
-	const get = __webpack_require__(52);
-	const has = __webpack_require__(104);
-	const { maybeEscapePropertyName } = __webpack_require__(7);
-	const GripMapEntry = __webpack_require__(44);
-
-	const NODE_TYPES = {
-	  BUCKET: Symbol("[n…n]"),
-	  DEFAULT_PROPERTIES: Symbol("[default properties]"),
-	  ENTRIES: Symbol("<entries>"),
-	  GET: Symbol("<get>"),
-	  GRIP: Symbol("GRIP"),
-	  MAP_ENTRY_KEY: Symbol("<key>"),
-	  MAP_ENTRY_VALUE: Symbol("<value>"),
-	  PROMISE_REASON: Symbol("<reason>"),
-	  PROMISE_STATE: Symbol("<state>"),
-	  PROMISE_VALUE: Symbol("<value>"),
-	  SET: Symbol("<set>"),
-	  PROTOTYPE: Symbol("__proto__")
-	};
-
-	let WINDOW_PROPERTIES = {};
-
-	if (typeof window === "object") {
-	  WINDOW_PROPERTIES = Object.getOwnPropertyNames(window);
-	}
-
-	const SAFE_PATH_PREFIX = "##-";
-
-	function getType(item) {
-	  return item.type;
-	}
-
-	function getValue(item) {
-	  if (has(item, "contents.value")) {
-	    return get(item, "contents.value");
-	  }
-
-	  if (has(item, "contents.getterValue")) {
-	    return get(item, "contents.getterValue", undefined);
-	  }
-
-	  if (nodeHasAccessors(item)) {
-	    return item.contents;
-	  }
-
-	  return undefined;
-	}
-
-	function nodeIsBucket(item) {
-	  return getType(item) === NODE_TYPES.BUCKET;
-	}
-
-	function nodeIsEntries(item) {
-	  return getType(item) === NODE_TYPES.ENTRIES;
-	}
-
-	function nodeIsMapEntry(item) {
-	  return GripMapEntry.supportsObject(getValue(item));
-	}
-
-	function nodeHasChildren(item) {
-	  return Array.isArray(item.contents) || nodeIsBucket(item);
-	}
-
-	function nodeIsObject(item) {
-	  const value = getValue(item);
-	  return value && value.type === "object";
-	}
-
-	function nodeIsArray(item) {
-	  const value = getValue(item);
-	  return value && value.class === "Array";
-	}
-
-	function nodeIsFunction(item) {
-	  const value = getValue(item);
-	  return value && value.class === "Function";
-	}
-
-	function nodeIsOptimizedOut(item) {
-	  const value = getValue(item);
-	  return !nodeHasChildren(item) && value && value.optimizedOut;
-	}
-
-	function nodeIsMissingArguments(item) {
-	  const value = getValue(item);
-	  return !nodeHasChildren(item) && value && value.missingArguments;
-	}
-
-	function nodeHasProperties(item) {
-	  return !nodeHasChildren(item) && nodeIsObject(item);
-	}
-
-	function nodeIsPrimitive(item) {
-	  return !nodeHasChildren(item) && !nodeHasProperties(item) && !nodeIsEntries(item) && !nodeIsMapEntry(item) && !nodeHasAccessors(item);
-	}
-
-	function nodeIsDefaultProperties(item) {
-	  return getType(item) === NODE_TYPES.DEFAULT_PROPERTIES;
-	}
-
-	function isDefaultWindowProperty(name) {
-	  return WINDOW_PROPERTIES.includes(name);
-	}
-
-	function nodeIsPromise(item) {
-	  const value = getValue(item);
-	  if (!value) {
-	    return false;
-	  }
-
-	  return value.class == "Promise";
-	}
-
-	function nodeIsPrototype(item) {
-	  return getType(item) === NODE_TYPES.PROTOTYPE;
-	}
-
-	function nodeHasAccessors(item) {
-	  return !!getNodeGetter(item) || !!getNodeSetter(item);
-	}
-
-	function nodeSupportsBucketing(item) {
-	  return nodeIsArray(item) || nodeIsEntries(item);
-	}
-
-	function nodeHasEntries(item) {
-	  const value = getValue(item);
-	  if (!value) {
-	    return false;
-	  }
-
-	  return value.class === "Map" || value.class === "Set" || value.class === "WeakMap" || value.class === "WeakSet";
-	}
-
-	function nodeHasAllEntriesInPreview(item) {
-	  const { preview } = getValue(item) || {};
-	  if (!preview) {
-	    return false;
-	  }
-
-	  const {
-	    entries,
-	    items,
-	    length,
-	    size
-	  } = preview;
-
-	  return entries ? entries.length === size : items.length === length;
-	}
-
-	function makeNodesForPromiseProperties(item) {
-	  const { promiseState: { reason, value, state } } = getValue(item);
-
-	  const properties = [];
-
-	  if (state) {
-	    properties.push(createNode(item, "<state>", `${item.path}/${SAFE_PATH_PREFIX}state`, { value: state }, NODE_TYPES.PROMISE_STATE));
-	  }
-
-	  if (reason) {
-	    properties.push(createNode(item, "<reason>", `${item.path}/${SAFE_PATH_PREFIX}reason`, { value: reason }, NODE_TYPES.PROMISE_REASON));
-	  }
-
-	  if (value) {
-	    properties.push(createNode(item, "<value>", `${item.path}/${SAFE_PATH_PREFIX}value`, { value: value }, NODE_TYPES.PROMISE_VALUE));
-	  }
-
-	  return properties;
-	}
-
-	function makeNodesForEntries(item) {
-	  const { path } = item;
-	  const { preview } = getValue(item);
-	  const nodeName = "<entries>";
-	  const entriesPath = `${path}/${SAFE_PATH_PREFIX}entries`;
-
-	  if (nodeHasAllEntriesInPreview(item)) {
-	    let entriesNodes = [];
-	    if (preview.entries) {
-	      entriesNodes = preview.entries.map(([key, value], index) => {
-	        return createNode(item, index, `${entriesPath}/${index}`, {
-	          value: GripMapEntry.createGripMapEntry(key, value)
-	        });
-	      });
-	    } else if (preview.items) {
-	      entriesNodes = preview.items.map((value, index) => {
-	        return createNode(item, index, `${entriesPath}/${index}`, { value });
-	      });
-	    }
-	    return createNode(item, nodeName, entriesPath, entriesNodes, NODE_TYPES.ENTRIES);
-	  }
-	  return createNode(item, nodeName, entriesPath, null, NODE_TYPES.ENTRIES);
-	}
-
-	function makeNodesForMapEntry(item) {
-	  const nodeValue = getValue(item);
-	  if (!nodeValue || !nodeValue.preview) {
-	    return [];
-	  }
-
-	  const { key, value } = nodeValue.preview;
-	  const path = item.path;
-
-	  return [createNode(item, "<key>", `${path}/##key`, { value: key }, NODE_TYPES.MAP_ENTRY_KEY), createNode(item, "<value>", `${path}/##value`, { value }, NODE_TYPES.MAP_ENTRY_VALUE)];
-	}
-
-	function getNodeGetter(item) {
-	  return get(item, "contents.get", undefined);
-	}
-
-	function getNodeSetter(item) {
-	  return get(item, "contents.set", undefined);
-	}
-
-	function makeNodesForAccessors(item) {
-	  const accessors = [];
-
-	  const getter = getNodeGetter(item);
-	  if (getter && getter.type !== "undefined") {
-	    accessors.push(createNode(item, "<get>", `${item.path}/${SAFE_PATH_PREFIX}get`, { value: getter }, NODE_TYPES.GET));
-	  }
-
-	  const setter = getNodeSetter(item);
-	  if (setter && setter.type !== "undefined") {
-	    accessors.push(createNode(item, "<set>", `${item.path}/${SAFE_PATH_PREFIX}set`, { value: setter }, NODE_TYPES.SET));
-	  }
-
-	  return accessors;
-	}
-
-	function sortProperties(properties) {
-	  return properties.sort((a, b) => {
-	    // Sort numbers in ascending order and sort strings lexicographically
-	    const aInt = parseInt(a, 10);
-	    const bInt = parseInt(b, 10);
-
-	    if (isNaN(aInt) || isNaN(bInt)) {
-	      return a > b ? 1 : -1;
-	    }
-
-	    return aInt - bInt;
-	  });
+		return classes.join(' ');
 	}
 
-	function makeNumericalBuckets(propertiesNames, bucketSize, parent, ownProperties) {
-	  const parentPath = parent.path;
-	  const numProperties = propertiesNames.length;
-	  const numBuckets = Math.ceil(numProperties / bucketSize);
-	  let buckets = [];
-	  for (let i = 1; i <= numBuckets; i++) {
-	    const bucketKey = `${SAFE_PATH_PREFIX}bucket${i}`;
-	    const minKey = (i - 1) * bucketSize;
-	    const maxKey = Math.min(i * bucketSize - 1, numProperties);
-	    const bucketName = `[${minKey}..${maxKey}]`;
-	    const bucketProperties = propertiesNames.slice(minKey, maxKey);
-
-	    const bucketNodes = bucketProperties.map(name => createNode(parent, name, `${parentPath}/${bucketKey}/${name}`, ownProperties[name]));
-
-	    buckets.push(createNode(parent, bucketName, `${parentPath}/${bucketKey}`, bucketNodes, NODE_TYPES.BUCKET));
-	  }
-	  return buckets;
-	}
-
-	function makeDefaultPropsBucket(propertiesNames, parent, ownProperties) {
-	  const parentPath = parent.path;
-
-	  const userPropertiesNames = [];
-	  const defaultProperties = [];
-
-	  propertiesNames.forEach(name => {
-	    if (isDefaultWindowProperty(name)) {
-	      defaultProperties.push(name);
-	    } else {
-	      userPropertiesNames.push(name);
-	    }
-	  });
-
-	  let nodes = makeNodesForOwnProps(userPropertiesNames, parent, ownProperties);
-
-	  if (defaultProperties.length > 0) {
-	    const defaultPropertiesNode = createNode(parent, "[default properties]", `${parentPath}/${SAFE_PATH_PREFIX}default`, null, NODE_TYPES.DEFAULT_PROPERTIES);
-
-	    const defaultNodes = defaultProperties.map((name, index) => createNode(defaultPropertiesNode, maybeEscapePropertyName(name), `${parentPath}/${SAFE_PATH_PREFIX}bucket${index}/${name}`, ownProperties[name]));
-	    nodes.push(setNodeChildren(defaultPropertiesNode, defaultNodes));
-	  }
-	  return nodes;
-	}
-
-	function makeNodesForOwnProps(propertiesNames, parent, ownProperties) {
-	  const parentPath = parent.path;
-	  return propertiesNames.map(name => createNode(parent, maybeEscapePropertyName(name), `${parentPath}/${name}`, ownProperties[name]));
-	}
-
-	function makeNodesForProperties(objProps, parent, {
-	  bucketSize = 100
-	} = {}) {
-	  const {
-	    ownProperties = {},
-	    ownSymbols,
-	    prototype,
-	    safeGetterValues
-	  } = objProps;
-
-	  const parentPath = parent.path;
-	  const parentValue = getValue(parent);
-
-	  let allProperties = Object.assign({}, ownProperties, safeGetterValues);
-
-	  // Ignore properties that are neither non-concrete nor getters/setters.
-	  const propertiesNames = sortProperties(Object.keys(allProperties)).filter(name => allProperties[name].hasOwnProperty("value") || allProperties[name].hasOwnProperty("getterValue") || allProperties[name].hasOwnProperty("get") || allProperties[name].hasOwnProperty("set"));
-
-	  const numProperties = propertiesNames.length;
-
-	  let nodes = [];
-	  if (nodeSupportsBucketing(parent) && numProperties > bucketSize) {
-	    nodes = makeNumericalBuckets(propertiesNames, bucketSize, parent, allProperties);
-	  } else if (parentValue && parentValue.class == "Window") {
-	    nodes = makeDefaultPropsBucket(propertiesNames, parent, allProperties);
-	  } else {
-	    nodes = makeNodesForOwnProps(propertiesNames, parent, allProperties);
-	  }
-
-	  if (Array.isArray(ownSymbols)) {
-	    ownSymbols.forEach((ownSymbol, index) => {
-	      nodes.push(createNode(parent, ownSymbol.name, `${parentPath}/${SAFE_PATH_PREFIX}symbol-${index}`, ownSymbol.descriptor));
-	    }, this);
-	  }
-
-	  if (nodeIsPromise(parent)) {
-	    nodes.push(...makeNodesForPromiseProperties(parent));
-	  }
-
-	  if (nodeHasEntries(parent)) {
-	    nodes.push(makeNodesForEntries(parent));
-	  }
-
-	  // Add the prototype if it exists and is not null
-	  if (prototype && prototype.type !== "null") {
-	    nodes.push(createNode(parent, "__proto__", `${parentPath}/__proto__`, { value: prototype }, NODE_TYPES.PROTOTYPE));
-	  }
-
-	  return nodes;
-	}
-
-	function createNode(parent, name, path, contents, type = NODE_TYPES.GRIP) {
-	  if (contents === undefined) {
-	    return null;
-	  }
-
-	  // The path is important to uniquely identify the item in the entire
-	  // tree. This helps debugging & optimizes React's rendering of large
-	  // lists. The path will be separated by property name,
-	  // i.e. `{ foo: { bar: { baz: 5 }}}` will have a path of `foo/bar/baz`
-	  // for the inner object.
-	  return {
-	    parent,
-	    name,
-	    path,
-	    contents,
-	    type
-	  };
-	}
-
-	function setNodeChildren(node, children) {
-	  node.contents = children;
-	  return node;
-	}
-
-	function getChildren(options) {
-	  const {
-	    actors = {},
-	    getObjectEntries,
-	    getObjectProperties,
-	    item
-	  } = options;
-	  // Nodes can either have children already, or be an object with
-	  // properties that we need to go and fetch.
-	  if (nodeHasAccessors(item)) {
-	    return makeNodesForAccessors(item);
-	  }
-
-	  if (nodeIsMapEntry(item)) {
-	    return makeNodesForMapEntry(item);
-	  }
-
-	  if (nodeHasChildren(item)) {
-	    return item.contents;
-	  }
-
-	  if (!nodeHasProperties(item) && !nodeIsEntries(item)) {
-	    return [];
-	  }
-
-	  // Because we are dynamically creating the tree as the user
-	  // expands it (not precalculated tree structure), we cache child
-	  // arrays. This not only helps performance, but is necessary
-	  // because the expanded state depends on instances of nodes
-	  // being the same across renders. If we didn't do this, each
-	  // node would be a new instance every render.
-	  const key = item.path;
-	  if (actors && actors[key]) {
-	    return actors[key];
-	  }
-
-	  if (nodeIsBucket(item)) {
-	    return item.contents.children;
-	  }
-
-	  let loadedProps;
-	  if (nodeIsEntries(item)) {
-	    // If `item` is an <entries> node, we need to get the entries
-	    // matching the parent node actor.
-	    const parent = getParent(item);
-	    loadedProps = getObjectEntries(get(getValue(parent), "actor", undefined));
-	  } else {
-	    loadedProps = getObjectProperties(get(getValue(item), "actor", undefined));
-	  }
-
-	  const {
-	    ownProperties,
-	    ownSymbols,
-	    safeGetterValues,
-	    prototype
-	  } = loadedProps || {};
-
-	  if (!ownProperties && !ownSymbols && !safeGetterValues && !prototype) {
-	    return [];
-	  }
-
-	  let children = makeNodesForProperties(loadedProps, item);
-	  actors[key] = children;
-	  return children;
-	}
-
-	function getParent(item) {
-	  return item.parent;
-	}
-
-	module.exports = {
-	  createNode,
-	  getChildren,
-	  getParent,
-	  getValue,
-	  makeNodesForEntries,
-	  makeNodesForPromiseProperties,
-	  makeNodesForProperties,
-	  nodeHasAccessors,
-	  nodeHasAllEntriesInPreview,
-	  nodeHasChildren,
-	  nodeHasEntries,
-	  nodeHasProperties,
-	  nodeIsDefaultProperties,
-	  nodeIsEntries,
-	  nodeIsFunction,
-	  nodeIsMapEntry,
-	  nodeIsMissingArguments,
-	  nodeIsObject,
-	  nodeIsOptimizedOut,
-	  nodeIsPrimitive,
-	  nodeIsPromise,
-	  nodeIsPrototype,
-	  nodeSupportsBucketing,
-	  sortProperties,
-	  NODE_TYPES,
-	  // Export for testing purpose.
-	  SAFE_PATH_PREFIX
-	};
-
-/***/ },
-/* 52 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var baseGet = __webpack_require__(53);
-
-	/**
-	 * Gets the value at `path` of `object`. If the resolved value is
-	 * `undefined`, the `defaultValue` is returned in its place.
-	 *
-	 * @static
-	 * @memberOf _
-	 * @since 3.7.0
-	 * @category Object
-	 * @param {Object} object The object to query.
-	 * @param {Array|string} path The path of the property to get.
-	 * @param {*} [defaultValue] The value returned for `undefined` resolved values.
-	 * @returns {*} Returns the resolved value.
-	 * @example
-	 *
-	 * var object = { 'a': [{ 'b': { 'c': 3 } }] };
-	 *
-	 * _.get(object, 'a[0].b.c');
-	 * // => 3
-	 *
-	 * _.get(object, ['a', '0', 'b', 'c']);
-	 * // => 3
-	 *
-	 * _.get(object, 'a.b.c', 'default');
-	 * // => 'default'
-	 */
-	function get(object, path, defaultValue) {
-	  var result = object == null ? undefined : baseGet(object, path);
-	  return result === undefined ? defaultValue : result;
-	}
-
-	module.exports = get;
-
-
-/***/ },
-/* 53 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var castPath = __webpack_require__(54),
-	    toKey = __webpack_require__(103);
-
-	/**
-	 * 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;
+	if (typeof module !== 'undefined' && module.exports) {
+		module.exports = classNames;
+	} else if (true) {
+		// register as 'classnames', consistent with npm package name
+		!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () {
+			return classNames;
+		}.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),
+				__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+	} else {
+		window.classNames = classNames;
 	}
-
-	module.exports = baseGet;
-
-
-/***/ },
-/* 54 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var isArray = __webpack_require__(55),
-	    isKey = __webpack_require__(56),
-	    stringToPath = __webpack_require__(65),
-	    toString = __webpack_require__(100);
-
-	/**
-	 * 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));
-	}
-
-	module.exports = castPath;
-
-
-/***/ },
-/* 55 */
-/***/ function(module, exports) {
-
-	/**
-	 * Checks if `value` is classified as an `Array` object.
-	 *
-	 * @static
-	 * @memberOf _
-	 * @since 0.1.0
-	 * @category Lang
-	 * @param {*} value The value to check.
-	 * @returns {boolean} Returns `true` if `value` is an array, else `false`.
-	 * @example
-	 *
-	 * _.isArray([1, 2, 3]);
-	 * // => true
-	 *
-	 * _.isArray(document.body.children);
-	 * // => false
-	 *
-	 * _.isArray('abc');
-	 * // => false
-	 *
-	 * _.isArray(_.noop);
-	 * // => false
-	 */
-	var isArray = Array.isArray;
-
-	module.exports = isArray;
-
-
-/***/ },
-/* 56 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var isArray = __webpack_require__(55),
-	    isSymbol = __webpack_require__(57);
-
-	/** Used to match property names within property paths. */
-	var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
-	    reIsPlainProp = /^\w*$/;
-
-	/**
-	 * Checks if `value` is a property name and not a property path.
-	 *
-	 * @private
-	 * @param {*} value The value to check.
-	 * @param {Object} [object] The object to query keys on.
-	 * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
-	 */
-	function isKey(value, object) {
-	  if (isArray(value)) {
-	    return false;
-	  }
-	  var type = typeof value;
-	  if (type == 'number' || type == 'symbol' || type == 'boolean' ||
-	      value == null || isSymbol(value)) {
-	    return true;
-	  }
-	  return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
-	    (object != null && value in Object(object));
-	}
-
-	module.exports = isKey;
-
-
-/***/ },
-/* 57 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var baseGetTag = __webpack_require__(58),
-	    isObjectLike = __webpack_require__(64);
-
-	/** `Object#toString` result references. */
-	var symbolTag = '[object Symbol]';
-
-	/**
-	 * Checks if `value` is classified as a `Symbol` primitive or object.
-	 *
-	 * @static
-	 * @memberOf _
-	 * @since 4.0.0
-	 * @category Lang
-	 * @param {*} value The value to check.
-	 * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
-	 * @example
-	 *
-	 * _.isSymbol(Symbol.iterator);
-	 * // => true
-	 *
-	 * _.isSymbol('abc');
-	 * // => false
-	 */
-	function isSymbol(value) {
-	  return typeof value == 'symbol' ||
-	    (isObjectLike(value) && baseGetTag(value) == symbolTag);
-	}
-
-	module.exports = isSymbol;
-
-
-/***/ },
-/* 58 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var Symbol = __webpack_require__(59),
-	    getRawTag = __webpack_require__(62),
-	    objectToString = __webpack_require__(63);
-
-	/** `Object#toString` result references. */
-	var nullTag = '[object Null]',
-	    undefinedTag = '[object Undefined]';
-
-	/** Built-in value references. */
-	var symToStringTag = Symbol ? Symbol.toStringTag : undefined;
-
-	/**
-	 * 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);
-	}
-
-	module.exports = baseGetTag;
-
-
-/***/ },
-/* 59 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var root = __webpack_require__(60);
-
-	/** Built-in value references. */
-	var Symbol = root.Symbol;
-
-	module.exports = Symbol;
-
-
-/***/ },
-/* 60 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var freeGlobal = __webpack_require__(61);
-
-	/** 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')();
-
-	module.exports = root;
-
-
-/***/ },
+}());
+
+
+/***/ }),
 /* 61 */
-/***/ function(module, exports) {
-
-	/* WEBPACK VAR INJECTION */(function(global) {/** Detect free variable `global` from Node.js. */
-	var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
-
-	module.exports = freeGlobal;
-
-	/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var baseGet = __webpack_require__(62);
+
+/**
+ * Gets the value at `path` of `object`. If the resolved value is
+ * `undefined`, the `defaultValue` is returned in its place.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.7.0
+ * @category Object
+ * @param {Object} object The object to query.
+ * @param {Array|string} path The path of the property to get.
+ * @param {*} [defaultValue] The value returned for `undefined` resolved values.
+ * @returns {*} Returns the resolved value.
+ * @example
+ *
+ * var object = { 'a': [{ 'b': { 'c': 3 } }] };
+ *
+ * _.get(object, 'a[0].b.c');
+ * // => 3
+ *
+ * _.get(object, ['a', '0', 'b', 'c']);
+ * // => 3
+ *
+ * _.get(object, 'a.b.c', 'default');
+ * // => 'default'
+ */
+function get(object, path, defaultValue) {
+  var result = object == null ? undefined : baseGet(object, path);
+  return result === undefined ? defaultValue : result;
+}
+
+module.exports = get;
+
+
+/***/ }),
 /* 62 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var Symbol = __webpack_require__(59);
-
-	/** Used for built-in method references. */
-	var objectProto = Object.prototype;
-
-	/** Used to check objects for own properties. */
-	var hasOwnProperty = objectProto.hasOwnProperty;
-
-	/**
-	 * Used to resolve the
-	 * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
-	 * of values.
-	 */
-	var nativeObjectToString = objectProto.toString;
-
-	/** Built-in value references. */
-	var symToStringTag = Symbol ? Symbol.toStringTag : undefined;
-
-	/**
-	 * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
-	 *
-	 * @private
-	 * @param {*} value The value to query.
-	 * @returns {string} Returns the raw `toStringTag`.
-	 */
-	function getRawTag(value) {
-	  var isOwn = hasOwnProperty.call(value, symToStringTag),
-	      tag = value[symToStringTag];
-
-	  try {
-	    value[symToStringTag] = undefined;
-	    var unmasked = true;
-	  } catch (e) {}
-
-	  var result = nativeObjectToString.call(value);
-	  if (unmasked) {
-	    if (isOwn) {
-	      value[symToStringTag] = tag;
-	    } else {
-	      delete value[symToStringTag];
-	    }
-	  }
-	  return result;
-	}
-
-	module.exports = getRawTag;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var castPath = __webpack_require__(22),
+    toKey = __webpack_require__(25);
+
+/**
+ * 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;
+}
+
+module.exports = baseGet;
+
+
+/***/ }),
 /* 63 */
-/***/ function(module, exports) {
-
-	/** Used for built-in method references. */
-	var objectProto = Object.prototype;
-
-	/**
-	 * Used to resolve the
-	 * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
-	 * of values.
-	 */
-	var nativeObjectToString = objectProto.toString;
-
-	/**
-	 * Converts `value` to a string using `Object.prototype.toString`.
-	 *
-	 * @private
-	 * @param {*} value The value to convert.
-	 * @returns {string} Returns the converted string.
-	 */
-	function objectToString(value) {
-	  return nativeObjectToString.call(value);
-	}
-
-	module.exports = objectToString;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var isArray = __webpack_require__(5),
+    isSymbol = __webpack_require__(11);
+
+/** Used to match property names within property paths. */
+var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
+    reIsPlainProp = /^\w*$/;
+
+/**
+ * Checks if `value` is a property name and not a property path.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {Object} [object] The object to query keys on.
+ * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
+ */
+function isKey(value, object) {
+  if (isArray(value)) {
+    return false;
+  }
+  var type = typeof value;
+  if (type == 'number' || type == 'symbol' || type == 'boolean' ||
+      value == null || isSymbol(value)) {
+    return true;
+  }
+  return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
+    (object != null && value in Object(object));
+}
+
+module.exports = isKey;
+
+
+/***/ }),
 /* 64 */
-/***/ function(module, exports) {
-
-	/**
-	 * Checks if `value` is object-like. A value is object-like if it's not `null`
-	 * and has a `typeof` result of "object".
-	 *
-	 * @static
-	 * @memberOf _
-	 * @since 4.0.0
-	 * @category Lang
-	 * @param {*} value The value to check.
-	 * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
-	 * @example
-	 *
-	 * _.isObjectLike({});
-	 * // => true
-	 *
-	 * _.isObjectLike([1, 2, 3]);
-	 * // => true
-	 *
-	 * _.isObjectLike(_.noop);
-	 * // => false
-	 *
-	 * _.isObjectLike(null);
-	 * // => false
-	 */
-	function isObjectLike(value) {
-	  return value != null && typeof value == 'object';
-	}
-
-	module.exports = isObjectLike;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+/* WEBPACK VAR INJECTION */(function(global) {/** Detect free variable `global` from Node.js. */
+var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
+
+module.exports = freeGlobal;
+
+/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(65)))
+
+/***/ }),
 /* 65 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var memoizeCapped = __webpack_require__(66);
-
-	/** Used to match property names within property paths. */
-	var reLeadingDot = /^\./,
-	    rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
-
-	/** Used to match backslashes in property paths. */
-	var reEscapeChar = /\\(\\)?/g;
-
-	/**
-	 * Converts `string` to a property path array.
-	 *
-	 * @private
-	 * @param {string} string The string to convert.
-	 * @returns {Array} Returns the property path array.
-	 */
-	var stringToPath = memoizeCapped(function(string) {
-	  var result = [];
-	  if (reLeadingDot.test(string)) {
-	    result.push('');
-	  }
-	  string.replace(rePropName, function(match, number, quote, string) {
-	    result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match));
-	  });
-	  return result;
-	});
-
-	module.exports = stringToPath;
-
-
-/***/ },
+/***/ (function(module, exports) {
+
+var g;
+
+// This works in non-strict mode
+g = (function() {
+	return this;
+})();
+
+try {
+	// This works if eval is allowed (see CSP)
+	g = g || Function("return this")() || (1,eval)("this");
+} catch(e) {
+	// This works if the window reference is available
+	if(typeof window === "object")
+		g = window;
+}
+
+// g can still be undefined, but nothing to do about it...
+// We return undefined, instead of nothing here, so it's
+// easier to handle this case. if(!global) { ...}
+
+module.exports = g;
+
+
+/***/ }),
 /* 66 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var memoize = __webpack_require__(67);
-
-	/** Used as the maximum memoize cache size. */
-	var MAX_MEMOIZE_SIZE = 500;
-
-	/**
-	 * A specialized version of `_.memoize` which clears the memoized function's
-	 * cache when it exceeds `MAX_MEMOIZE_SIZE`.
-	 *
-	 * @private
-	 * @param {Function} func The function to have its output memoized.
-	 * @returns {Function} Returns the new memoized function.
-	 */
-	function memoizeCapped(func) {
-	  var result = memoize(func, function(key) {
-	    if (cache.size === MAX_MEMOIZE_SIZE) {
-	      cache.clear();
-	    }
-	    return key;
-	  });
-
-	  var cache = result.cache;
-	  return result;
-	}
-
-	module.exports = memoizeCapped;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var Symbol = __webpack_require__(13);
+
+/** Used for built-in method references. */
+var objectProto = Object.prototype;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+var nativeObjectToString = objectProto.toString;
+
+/** Built-in value references. */
+var symToStringTag = Symbol ? Symbol.toStringTag : undefined;
+
+/**
+ * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @returns {string} Returns the raw `toStringTag`.
+ */
+function getRawTag(value) {
+  var isOwn = hasOwnProperty.call(value, symToStringTag),
+      tag = value[symToStringTag];
+
+  try {
+    value[symToStringTag] = undefined;
+    var unmasked = true;
+  } catch (e) {}
+
+  var result = nativeObjectToString.call(value);
+  if (unmasked) {
+    if (isOwn) {
+      value[symToStringTag] = tag;
+    } else {
+      delete value[symToStringTag];
+    }
+  }
+  return result;
+}
+
+module.exports = getRawTag;
+
+
+/***/ }),
 /* 67 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var MapCache = __webpack_require__(68);
-
-	/** Error message constants. */
-	var FUNC_ERROR_TEXT = 'Expected a function';
-
-	/**
-	 * Creates a function that memoizes the result of `func`. If `resolver` is
-	 * provided, it determines the cache key for storing the result based on the
-	 * arguments provided to the memoized function. By default, the first argument
-	 * provided to the memoized function is used as the map cache key. The `func`
-	 * is invoked with the `this` binding of the memoized function.
-	 *
-	 * **Note:** The cache is exposed as the `cache` property on the memoized
-	 * function. Its creation may be customized by replacing the `_.memoize.Cache`
-	 * constructor with one whose instances implement the
-	 * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
-	 * method interface of `clear`, `delete`, `get`, `has`, and `set`.
-	 *
-	 * @static
-	 * @memberOf _
-	 * @since 0.1.0
-	 * @category Function
-	 * @param {Function} func The function to have its output memoized.
-	 * @param {Function} [resolver] The function to resolve the cache key.
-	 * @returns {Function} Returns the new memoized function.
-	 * @example
-	 *
-	 * var object = { 'a': 1, 'b': 2 };
-	 * var other = { 'c': 3, 'd': 4 };
-	 *
-	 * var values = _.memoize(_.values);
-	 * values(object);
-	 * // => [1, 2]
-	 *
-	 * values(other);
-	 * // => [3, 4]
-	 *
-	 * object.a = 2;
-	 * values(object);
-	 * // => [1, 2]
-	 *
-	 * // Modify the result cache.
-	 * values.cache.set(object, ['a', 'b']);
-	 * values(object);
-	 * // => ['a', 'b']
-	 *
-	 * // Replace `_.memoize.Cache`.
-	 * _.memoize.Cache = WeakMap;
-	 */
-	function memoize(func, resolver) {
-	  if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {
-	    throw new TypeError(FUNC_ERROR_TEXT);
-	  }
-	  var memoized = function() {
-	    var args = arguments,
-	        key = resolver ? resolver.apply(this, args) : args[0],
-	        cache = memoized.cache;
-
-	    if (cache.has(key)) {
-	      return cache.get(key);
-	    }
-	    var result = func.apply(this, args);
-	    memoized.cache = cache.set(key, result) || cache;
-	    return result;
-	  };
-	  memoized.cache = new (memoize.Cache || MapCache);
-	  return memoized;
-	}
-
-	// Expose `MapCache`.
-	memoize.Cache = MapCache;
-
-	module.exports = memoize;
-
-
-/***/ },
+/***/ (function(module, exports) {
+
+/** Used for built-in method references. */
+var objectProto = Object.prototype;
+
+/**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+var nativeObjectToString = objectProto.toString;
+
+/**
+ * Converts `value` to a string using `Object.prototype.toString`.
+ *
+ * @private
+ * @param {*} value The value to convert.
+ * @returns {string} Returns the converted string.
+ */
+function objectToString(value) {
+  return nativeObjectToString.call(value);
+}
+
+module.exports = objectToString;
+
+
+/***/ }),
 /* 68 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var mapCacheClear = __webpack_require__(69),
-	    mapCacheDelete = __webpack_require__(94),
-	    mapCacheGet = __webpack_require__(97),
-	    mapCacheHas = __webpack_require__(98),
-	    mapCacheSet = __webpack_require__(99);
-
-	/**
-	 * 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]);
-	  }
-	}
-
-	// Add methods to `MapCache`.
-	MapCache.prototype.clear = mapCacheClear;
-	MapCache.prototype['delete'] = mapCacheDelete;
-	MapCache.prototype.get = mapCacheGet;
-	MapCache.prototype.has = mapCacheHas;
-	MapCache.prototype.set = mapCacheSet;
-
-	module.exports = MapCache;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var memoizeCapped = __webpack_require__(69);
+
+/** Used to match property names within property paths. */
+var reLeadingDot = /^\./,
+    rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
+
+/** Used to match backslashes in property paths. */
+var reEscapeChar = /\\(\\)?/g;
+
+/**
+ * Converts `string` to a property path array.
+ *
+ * @private
+ * @param {string} string The string to convert.
+ * @returns {Array} Returns the property path array.
+ */
+var stringToPath = memoizeCapped(function(string) {
+  var result = [];
+  if (reLeadingDot.test(string)) {
+    result.push('');
+  }
+  string.replace(rePropName, function(match, number, quote, string) {
+    result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match));
+  });
+  return result;
+});
+
+module.exports = stringToPath;
+
+
+/***/ }),
 /* 69 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var Hash = __webpack_require__(70),
-	    ListCache = __webpack_require__(85),
-	    Map = __webpack_require__(93);
-
-	/**
-	 * 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
-	  };
-	}
-
-	module.exports = mapCacheClear;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var memoize = __webpack_require__(70);
+
+/** Used as the maximum memoize cache size. */
+var MAX_MEMOIZE_SIZE = 500;
+
+/**
+ * A specialized version of `_.memoize` which clears the memoized function's
+ * cache when it exceeds `MAX_MEMOIZE_SIZE`.
+ *
+ * @private
+ * @param {Function} func The function to have its output memoized.
+ * @returns {Function} Returns the new memoized function.
+ */
+function memoizeCapped(func) {
+  var result = memoize(func, function(key) {
+    if (cache.size === MAX_MEMOIZE_SIZE) {
+      cache.clear();
+    }
+    return key;
+  });
+
+  var cache = result.cache;
+  return result;
+}
+
+module.exports = memoizeCapped;
+
+
+/***/ }),
 /* 70 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var hashClear = __webpack_require__(71),
-	    hashDelete = __webpack_require__(81),
-	    hashGet = __webpack_require__(82),
-	    hashHas = __webpack_require__(83),
-	    hashSet = __webpack_require__(84);
-
-	/**
-	 * 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]);
-	  }
-	}
-
-	// Add methods to `Hash`.
-	Hash.prototype.clear = hashClear;
-	Hash.prototype['delete'] = hashDelete;
-	Hash.prototype.get = hashGet;
-	Hash.prototype.has = hashHas;
-	Hash.prototype.set = hashSet;
-
-	module.exports = Hash;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var MapCache = __webpack_require__(71);
+
+/** Error message constants. */
+var FUNC_ERROR_TEXT = 'Expected a function';
+
+/**
+ * Creates a function that memoizes the result of `func`. If `resolver` is
+ * provided, it determines the cache key for storing the result based on the
+ * arguments provided to the memoized function. By default, the first argument
+ * provided to the memoized function is used as the map cache key. The `func`
+ * is invoked with the `this` binding of the memoized function.
+ *
+ * **Note:** The cache is exposed as the `cache` property on the memoized
+ * function. Its creation may be customized by replacing the `_.memoize.Cache`
+ * constructor with one whose instances implement the
+ * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
+ * method interface of `clear`, `delete`, `get`, `has`, and `set`.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Function
+ * @param {Function} func The function to have its output memoized.
+ * @param {Function} [resolver] The function to resolve the cache key.
+ * @returns {Function} Returns the new memoized function.
+ * @example
+ *
+ * var object = { 'a': 1, 'b': 2 };
+ * var other = { 'c': 3, 'd': 4 };
+ *
+ * var values = _.memoize(_.values);
+ * values(object);
+ * // => [1, 2]
+ *
+ * values(other);
+ * // => [3, 4]
+ *
+ * object.a = 2;
+ * values(object);
+ * // => [1, 2]
+ *
+ * // Modify the result cache.
+ * values.cache.set(object, ['a', 'b']);
+ * values(object);
+ * // => ['a', 'b']
+ *
+ * // Replace `_.memoize.Cache`.
+ * _.memoize.Cache = WeakMap;
+ */
+function memoize(func, resolver) {
+  if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {
+    throw new TypeError(FUNC_ERROR_TEXT);
+  }
+  var memoized = function() {
+    var args = arguments,
+        key = resolver ? resolver.apply(this, args) : args[0],
+        cache = memoized.cache;
+
+    if (cache.has(key)) {
+      return cache.get(key);
+    }
+    var result = func.apply(this, args);
+    memoized.cache = cache.set(key, result) || cache;
+    return result;
+  };
+  memoized.cache = new (memoize.Cache || MapCache);
+  return memoized;
+}
+
+// Expose `MapCache`.
+memoize.Cache = MapCache;
+
+module.exports = memoize;
+
+
+/***/ }),
 /* 71 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var nativeCreate = __webpack_require__(72);
-
-	/**
-	 * Removes all key-value entries from the hash.
-	 *
-	 * @private
-	 * @name clear
-	 * @memberOf Hash
-	 */
-	function hashClear() {
-	  this.__data__ = nativeCreate ? nativeCreate(null) : {};
-	  this.size = 0;
-	}
-
-	module.exports = hashClear;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var mapCacheClear = __webpack_require__(72),
+    mapCacheDelete = __webpack_require__(93),
+    mapCacheGet = __webpack_require__(95),
+    mapCacheHas = __webpack_require__(96),
+    mapCacheSet = __webpack_require__(97);
+
+/**
+ * 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]);
+  }
+}
+
+// Add methods to `MapCache`.
+MapCache.prototype.clear = mapCacheClear;
+MapCache.prototype['delete'] = mapCacheDelete;
+MapCache.prototype.get = mapCacheGet;
+MapCache.prototype.has = mapCacheHas;
+MapCache.prototype.set = mapCacheSet;
+
+module.exports = MapCache;
+
+
+/***/ }),
 /* 72 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var getNative = __webpack_require__(73);
-
-	/* Built-in method references that are verified to be native. */
-	var nativeCreate = getNative(Object, 'create');
-
-	module.exports = nativeCreate;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var Hash = __webpack_require__(73),
+    ListCache = __webpack_require__(85),
+    Map = __webpack_require__(92);
+
+/**
+ * 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
+  };
+}
+
+module.exports = mapCacheClear;
+
+
+/***/ }),
 /* 73 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var baseIsNative = __webpack_require__(74),
-	    getValue = __webpack_require__(80);
-
-	/**
-	 * Gets the native function at `key` of `object`.
-	 *
-	 * @private
-	 * @param {Object} object The object to query.
-	 * @param {string} key The key of the method to get.
-	 * @returns {*} Returns the function if it's native, else `undefined`.
-	 */
-	function getNative(object, key) {
-	  var value = getValue(object, key);
-	  return baseIsNative(value) ? value : undefined;
-	}
-
-	module.exports = getNative;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var hashClear = __webpack_require__(74),
+    hashDelete = __webpack_require__(81),
+    hashGet = __webpack_require__(82),
+    hashHas = __webpack_require__(83),
+    hashSet = __webpack_require__(84);
+
+/**
+ * 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]);
+  }
+}
+
+// Add methods to `Hash`.
+Hash.prototype.clear = hashClear;
+Hash.prototype['delete'] = hashDelete;
+Hash.prototype.get = hashGet;
+Hash.prototype.has = hashHas;
+Hash.prototype.set = hashSet;
+
+module.exports = Hash;
+
+
+/***/ }),
 /* 74 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var isFunction = __webpack_require__(75),
-	    isMasked = __webpack_require__(77),
-	    isObject = __webpack_require__(76),
-	    toSource = __webpack_require__(79);
-
-	/**
-	 * Used to match `RegExp`
-	 * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
-	 */
-	var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
-
-	/** Used to detect host constructors (Safari). */
-	var reIsHostCtor = /^\[object .+?Constructor\]$/;
-
-	/** Used for built-in method references. */
-	var funcProto = Function.prototype,
-	    objectProto = Object.prototype;
-
-	/** 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 detect if a method is native. */
-	var reIsNative = RegExp('^' +
-	  funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
-	  .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
-	);
-
-	/**
-	 * 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));
-	}
-
-	module.exports = baseIsNative;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var nativeCreate = __webpack_require__(6);
+
+/**
+ * Removes all key-value entries from the hash.
+ *
+ * @private
+ * @name clear
+ * @memberOf Hash
+ */
+function hashClear() {
+  this.__data__ = nativeCreate ? nativeCreate(null) : {};
+  this.size = 0;
+}
+
+module.exports = hashClear;
+
+
+/***/ }),
 /* 75 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var baseGetTag = __webpack_require__(58),
-	    isObject = __webpack_require__(76);
-
-	/** `Object#toString` result references. */
-	var asyncTag = '[object AsyncFunction]',
-	    funcTag = '[object Function]',
-	    genTag = '[object GeneratorFunction]',
-	    proxyTag = '[object Proxy]';
-
-	/**
-	 * Checks if `value` is classified as a `Function` object.
-	 *
-	 * @static
-	 * @memberOf _
-	 * @since 0.1.0
-	 * @category Lang
-	 * @param {*} value The value to check.
-	 * @returns {boolean} Returns `true` if `value` is a function, else `false`.
-	 * @example
-	 *
-	 * _.isFunction(_);
-	 * // => true
-	 *
-	 * _.isFunction(/abc/);
-	 * // => false
-	 */
-	function isFunction(value) {
-	  if (!isObject(value)) {
-	    return false;
-	  }
-	  // The use of `Object#toString` avoids issues with the `typeof` operator
-	  // in Safari 9 which returns 'object' for typed arrays and other constructors.
-	  var tag = baseGetTag(value);
-	  return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
-	}
-
-	module.exports = isFunction;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var isFunction = __webpack_require__(76),
+    isMasked = __webpack_require__(77),
+    isObject = __webpack_require__(24),
+    toSource = __webpack_require__(79);
+
+/**
+ * Used to match `RegExp`
+ * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
+ */
+var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
+
+/** Used to detect host constructors (Safari). */
+var reIsHostCtor = /^\[object .+?Constructor\]$/;
+
+/** Used for built-in method references. */
+var funcProto = Function.prototype,
+    objectProto = Object.prototype;
+
+/** 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 detect if a method is native. */
+var reIsNative = RegExp('^' +
+  funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
+  .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
+);
+
+/**
+ * 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));
+}
+
+module.exports = baseIsNative;
+
+
+/***/ }),
 /* 76 */
-/***/ function(module, exports) {
-
-	/**
-	 * Checks if `value` is the
-	 * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
-	 * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
-	 *
-	 * @static
-	 * @memberOf _
-	 * @since 0.1.0
-	 * @category Lang
-	 * @param {*} value The value to check.
-	 * @returns {boolean} Returns `true` if `value` is an object, else `false`.
-	 * @example
-	 *
-	 * _.isObject({});
-	 * // => true
-	 *
-	 * _.isObject([1, 2, 3]);
-	 * // => true
-	 *
-	 * _.isObject(_.noop);
-	 * // => true
-	 *
-	 * _.isObject(null);
-	 * // => false
-	 */
-	function isObject(value) {
-	  var type = typeof value;
-	  return value != null && (type == 'object' || type == 'function');
-	}
-
-	module.exports = isObject;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var baseGetTag = __webpack_require__(12),
+    isObject = __webpack_require__(24);
+
+/** `Object#toString` result references. */
+var asyncTag = '[object AsyncFunction]',
+    funcTag = '[object Function]',
+    genTag = '[object GeneratorFunction]',
+    proxyTag = '[object Proxy]';
+
+/**
+ * Checks if `value` is classified as a `Function` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a function, else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ *
+ * _.isFunction(/abc/);
+ * // => false
+ */
+function isFunction(value) {
+  if (!isObject(value)) {
+    return false;
+  }
+  // The use of `Object#toString` avoids issues with the `typeof` operator
+  // in Safari 9 which returns 'object' for typed arrays and other constructors.
+  var tag = baseGetTag(value);
+  return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
+}
+
+module.exports = isFunction;
+
+
+/***/ }),
 /* 77 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var coreJsData = __webpack_require__(78);
-
-	/** 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) : '';
-	}());
-
-	/**
-	 * Checks if `func` has its source masked.
-	 *
-	 * @private
-	 * @param {Function} func The function to check.
-	 * @returns {boolean} Returns `true` if `func` is masked, else `false`.
-	 */
-	function isMasked(func) {
-	  return !!maskSrcKey && (maskSrcKey in func);
-	}
-
-	module.exports = isMasked;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var coreJsData = __webpack_require__(78);
+
+/** 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) : '';
+}());
+
+/**
+ * Checks if `func` has its source masked.
+ *
+ * @private
+ * @param {Function} func The function to check.
+ * @returns {boolean} Returns `true` if `func` is masked, else `false`.
+ */
+function isMasked(func) {
+  return !!maskSrcKey && (maskSrcKey in func);
+}
+
+module.exports = isMasked;
+
+
+/***/ }),
 /* 78 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var root = __webpack_require__(60);
-
-	/** Used to detect overreaching core-js shims. */
-	var coreJsData = root['__core-js_shared__'];
-
-	module.exports = coreJsData;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var root = __webpack_require__(14);
+
+/** Used to detect overreaching core-js shims. */
+var coreJsData = root['__core-js_shared__'];
+
+module.exports = coreJsData;
+
+
+/***/ }),
 /* 79 */
-/***/ function(module, exports) {
-
-	/** Used for built-in method references. */
-	var funcProto = Function.prototype;
-
-	/** Used to resolve the decompiled source of functions. */
-	var funcToString = funcProto.toString;
-
-	/**
-	 * Converts `func` to its source code.
-	 *
-	 * @private
-	 * @param {Function} func The function to convert.
-	 * @returns {string} Returns the source code.
-	 */
-	function toSource(func) {
-	  if (func != null) {
-	    try {
-	      return funcToString.call(func);
-	    } catch (e) {}
-	    try {
-	      return (func + '');
-	    } catch (e) {}
-	  }
-	  return '';
-	}
-
-	module.exports = toSource;
-
-
-/***/ },
+/***/ (function(module, exports) {
+
+/** Used for built-in method references. */
+var funcProto = Function.prototype;
+
+/** Used to resolve the decompiled source of functions. */
+var funcToString = funcProto.toString;
+
+/**
+ * Converts `func` to its source code.
+ *
+ * @private
+ * @param {Function} func The function to convert.
+ * @returns {string} Returns the source code.
+ */
+function toSource(func) {
+  if (func != null) {
+    try {
+      return funcToString.call(func);
+    } catch (e) {}
+    try {
+      return (func + '');
+    } catch (e) {}
+  }
+  return '';
+}
+
+module.exports = toSource;
+
+
+/***/ }),
 /* 80 */
-/***/ function(module, exports) {
-
-	/**
-	 * 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];
-	}
-
-	module.exports = getValue;
-
-
-/***/ },
+/***/ (function(module, exports) {
+
+/**
+ * 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];
+}
+
+module.exports = getValue;
+
+
+/***/ }),
 /* 81 */
-/***/ function(module, exports) {
-
-	/**
-	 * 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;
-	}
-
-	module.exports = hashDelete;
-
-
-/***/ },
+/***/ (function(module, exports) {
+
+/**
+ * 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;
+}
+
+module.exports = hashDelete;
+
+
+/***/ }),
 /* 82 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var nativeCreate = __webpack_require__(72);
-
-	/** Used to stand-in for `undefined` hash values. */
-	var HASH_UNDEFINED = '__lodash_hash_undefined__';
-
-	/** Used for built-in method references. */
-	var objectProto = Object.prototype;
-
-	/** Used to check objects for own properties. */
-	var hasOwnProperty = objectProto.hasOwnProperty;
-
-	/**
-	 * 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;
-	}
-
-	module.exports = hashGet;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var nativeCreate = __webpack_require__(6);
+
+/** Used to stand-in for `undefined` hash values. */
+var HASH_UNDEFINED = '__lodash_hash_undefined__';
+
+/** Used for built-in method references. */
+var objectProto = Object.prototype;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/**
+ * 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;
+}
+
+module.exports = hashGet;
+
+
+/***/ }),
 /* 83 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var nativeCreate = __webpack_require__(72);
-
-	/** Used for built-in method references. */
-	var objectProto = Object.prototype;
-
-	/** Used to check objects for own properties. */
-	var hasOwnProperty = objectProto.hasOwnProperty;
-
-	/**
-	 * 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);
-	}
-
-	module.exports = hashHas;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var nativeCreate = __webpack_require__(6);
+
+/** Used for built-in method references. */
+var objectProto = Object.prototype;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/**
+ * 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);
+}
+
+module.exports = hashHas;
+
+
+/***/ }),
 /* 84 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var nativeCreate = __webpack_require__(72);
-
-	/** Used to stand-in for `undefined` hash values. */
-	var HASH_UNDEFINED = '__lodash_hash_undefined__';
-
-	/**
-	 * 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;
-	}
-
-	module.exports = hashSet;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var nativeCreate = __webpack_require__(6);
+
+/** Used to stand-in for `undefined` hash values. */
+var HASH_UNDEFINED = '__lodash_hash_undefined__';
+
+/**
+ * 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;
+}
+
+module.exports = hashSet;
+
+
+/***/ }),
 /* 85 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var listCacheClear = __webpack_require__(86),
-	    listCacheDelete = __webpack_require__(87),
-	    listCacheGet = __webpack_require__(90),
-	    listCacheHas = __webpack_require__(91),
-	    listCacheSet = __webpack_require__(92);
-
-	/**
-	 * 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]);
-	  }
-	}
-
-	// Add methods to `ListCache`.
-	ListCache.prototype.clear = listCacheClear;
-	ListCache.prototype['delete'] = listCacheDelete;
-	ListCache.prototype.get = listCacheGet;
-	ListCache.prototype.has = listCacheHas;
-	ListCache.prototype.set = listCacheSet;
-
-	module.exports = ListCache;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var listCacheClear = __webpack_require__(86),
+    listCacheDelete = __webpack_require__(87),
+    listCacheGet = __webpack_require__(89),
+    listCacheHas = __webpack_require__(90),
+    listCacheSet = __webpack_require__(91);
+
+/**
+ * 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]);
+  }
+}
+
+// Add methods to `ListCache`.
+ListCache.prototype.clear = listCacheClear;
+ListCache.prototype['delete'] = listCacheDelete;
+ListCache.prototype.get = listCacheGet;
+ListCache.prototype.has = listCacheHas;
+ListCache.prototype.set = listCacheSet;
+
+module.exports = ListCache;
+
+
+/***/ }),
 /* 86 */
-/***/ function(module, exports) {
-
-	/**
-	 * Removes all key-value entries from the list cache.
-	 *
-	 * @private
-	 * @name clear
-	 * @memberOf ListCache
-	 */
-	function listCacheClear() {
-	  this.__data__ = [];
-	  this.size = 0;
-	}
-
-	module.exports = listCacheClear;
-
-
-/***/ },
+/***/ (function(module, exports) {
+
+/**
+ * Removes all key-value entries from the list cache.
+ *
+ * @private
+ * @name clear
+ * @memberOf ListCache
+ */
+function listCacheClear() {
+  this.__data__ = [];
+  this.size = 0;
+}
+
+module.exports = listCacheClear;
+
+
+/***/ }),
 /* 87 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var assocIndexOf = __webpack_require__(88);
-
-	/** Used for built-in method references. */
-	var arrayProto = Array.prototype;
-
-	/** Built-in value references. */
-	var splice = arrayProto.splice;
-
-	/**
-	 * 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;
-	}
-
-	module.exports = listCacheDelete;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var assocIndexOf = __webpack_require__(7);
+
+/** Used for built-in method references. */
+var arrayProto = Array.prototype;
+
+/** Built-in value references. */
+var splice = arrayProto.splice;
+
+/**
+ * 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;
+}
+
+module.exports = listCacheDelete;
+
+
+/***/ }),
 /* 88 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var eq = __webpack_require__(89);
-
-	/**
-	 * 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;
-	}
-
-	module.exports = assocIndexOf;
-
-
-/***/ },
+/***/ (function(module, exports) {
+
+/**
+ * Performs a
+ * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+ * comparison between two values to determine if they are equivalent.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ * @example
+ *
+ * var object = { 'a': 1 };
+ * var other = { 'a': 1 };
+ *
+ * _.eq(object, object);
+ * // => true
+ *
+ * _.eq(object, other);
+ * // => false
+ *
+ * _.eq('a', 'a');
+ * // => true
+ *
+ * _.eq('a', Object('a'));
+ * // => false
+ *
+ * _.eq(NaN, NaN);
+ * // => true
+ */
+function eq(value, other) {
+  return value === other || (value !== value && other !== other);
+}
+
+module.exports = eq;
+
+
+/***/ }),
 /* 89 */
-/***/ function(module, exports) {
-
-	/**
-	 * Performs a
-	 * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
-	 * comparison between two values to determine if they are equivalent.
-	 *
-	 * @static
-	 * @memberOf _
-	 * @since 4.0.0
-	 * @category Lang
-	 * @param {*} value The value to compare.
-	 * @param {*} other The other value to compare.
-	 * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
-	 * @example
-	 *
-	 * var object = { 'a': 1 };
-	 * var other = { 'a': 1 };
-	 *
-	 * _.eq(object, object);
-	 * // => true
-	 *
-	 * _.eq(object, other);
-	 * // => false
-	 *
-	 * _.eq('a', 'a');
-	 * // => true
-	 *
-	 * _.eq('a', Object('a'));
-	 * // => false
-	 *
-	 * _.eq(NaN, NaN);
-	 * // => true
-	 */
-	function eq(value, other) {
-	  return value === other || (value !== value && other !== other);
-	}
-
-	module.exports = eq;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var assocIndexOf = __webpack_require__(7);
+
+/**
+ * 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];
+}
+
+module.exports = listCacheGet;
+
+
+/***/ }),
 /* 90 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var assocIndexOf = __webpack_require__(88);
-
-	/**
-	 * 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];
-	}
-
-	module.exports = listCacheGet;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var assocIndexOf = __webpack_require__(7);
+
+/**
+ * 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;
+}
+
+module.exports = listCacheHas;
+
+
+/***/ }),
 /* 91 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var assocIndexOf = __webpack_require__(88);
-
-	/**
-	 * 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;
-	}
-
-	module.exports = listCacheHas;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var assocIndexOf = __webpack_require__(7);
+
+/**
+ * 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;
+}
+
+module.exports = listCacheSet;
+
+
+/***/ }),
 /* 92 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var assocIndexOf = __webpack_require__(88);
-
-	/**
-	 * 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;
-	}
-
-	module.exports = listCacheSet;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var getNative = __webpack_require__(23),
+    root = __webpack_require__(14);
+
+/* Built-in method references that are verified to be native. */
+var Map = getNative(root, 'Map');
+
+module.exports = Map;
+
+
+/***/ }),
 /* 93 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var getNative = __webpack_require__(73),
-	    root = __webpack_require__(60);
-
-	/* Built-in method references that are verified to be native. */
-	var Map = getNative(root, 'Map');
-
-	module.exports = Map;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var getMapData = __webpack_require__(8);
+
+/**
+ * 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;
+}
+
+module.exports = mapCacheDelete;
+
+
+/***/ }),
 /* 94 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var getMapData = __webpack_require__(95);
-
-	/**
-	 * 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;
-	}
-
-	module.exports = mapCacheDelete;
-
-
-/***/ },
+/***/ (function(module, exports) {
+
+/**
+ * Checks if `value` is suitable for use as unique object key.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
+ */
+function isKeyable(value) {
+  var type = typeof value;
+  return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
+    ? (value !== '__proto__')
+    : (value === null);
+}
+
+module.exports = isKeyable;
+
+
+/***/ }),
 /* 95 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var isKeyable = __webpack_require__(96);
-
-	/**
-	 * Gets the data for `map`.
-	 *
-	 * @private
-	 * @param {Object} map The map to query.
-	 * @param {string} key The reference key.
-	 * @returns {*} Returns the map data.
-	 */
-	function getMapData(map, key) {
-	  var data = map.__data__;
-	  return isKeyable(key)
-	    ? data[typeof key == 'string' ? 'string' : 'hash']
-	    : data.map;
-	}
-
-	module.exports = getMapData;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var getMapData = __webpack_require__(8);
+
+/**
+ * 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);
+}
+
+module.exports = mapCacheGet;
+
+
+/***/ }),
 /* 96 */
-/***/ function(module, exports) {
-
-	/**
-	 * Checks if `value` is suitable for use as unique object key.
-	 *
-	 * @private
-	 * @param {*} value The value to check.
-	 * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
-	 */
-	function isKeyable(value) {
-	  var type = typeof value;
-	  return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
-	    ? (value !== '__proto__')
-	    : (value === null);
-	}
-
-	module.exports = isKeyable;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var getMapData = __webpack_require__(8);
+
+/**
+ * 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);
+}
+
+module.exports = mapCacheHas;
+
+
+/***/ }),
 /* 97 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var getMapData = __webpack_require__(95);
-
-	/**
-	 * 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);
-	}
-
-	module.exports = mapCacheGet;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var getMapData = __webpack_require__(8);
+
+/**
+ * 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;
+}
+
+module.exports = mapCacheSet;
+
+
+/***/ }),
 /* 98 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var getMapData = __webpack_require__(95);
-
-	/**
-	 * 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);
-	}
-
-	module.exports = mapCacheHas;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var baseToString = __webpack_require__(99);
+
+/**
+ * Converts `value` to a string. An empty string is returned for `null`
+ * and `undefined` values. The sign of `-0` is preserved.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to convert.
+ * @returns {string} Returns the converted string.
+ * @example
+ *
+ * _.toString(null);
+ * // => ''
+ *
+ * _.toString(-0);
+ * // => '-0'
+ *
+ * _.toString([1, 2, 3]);
+ * // => '1,2,3'
+ */
+function toString(value) {
+  return value == null ? '' : baseToString(value);
+}
+
+module.exports = toString;
+
+
+/***/ }),
 /* 99 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var getMapData = __webpack_require__(95);
-
-	/**
-	 * 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;
-	}
-
-	module.exports = mapCacheSet;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var Symbol = __webpack_require__(13),
+    arrayMap = __webpack_require__(100),
+    isArray = __webpack_require__(5),
+    isSymbol = __webpack_require__(11);
+
+/** Used as references for various `Number` constants. */
+var INFINITY = 1 / 0;
+
+/** Used to convert symbols to primitives and strings. */
+var symbolProto = Symbol ? Symbol.prototype : undefined,
+    symbolToString = symbolProto ? symbolProto.toString : undefined;
+
+/**
+ * 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;
+}
+
+module.exports = baseToString;
+
+
+/***/ }),
 /* 100 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var baseToString = __webpack_require__(101);
-
-	/**
-	 * Converts `value` to a string. An empty string is returned for `null`
-	 * and `undefined` values. The sign of `-0` is preserved.
-	 *
-	 * @static
-	 * @memberOf _
-	 * @since 4.0.0
-	 * @category Lang
-	 * @param {*} value The value to convert.
-	 * @returns {string} Returns the converted string.
-	 * @example
-	 *
-	 * _.toString(null);
-	 * // => ''
-	 *
-	 * _.toString(-0);
-	 * // => '-0'
-	 *
-	 * _.toString([1, 2, 3]);
-	 * // => '1,2,3'
-	 */
-	function toString(value) {
-	  return value == null ? '' : baseToString(value);
-	}
-
-	module.exports = toString;
-
-
-/***/ },
+/***/ (function(module, exports) {
+
+/**
+ * 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;
+}
+
+module.exports = arrayMap;
+
+
+/***/ }),
 /* 101 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var Symbol = __webpack_require__(59),
-	    arrayMap = __webpack_require__(102),
-	    isArray = __webpack_require__(55),
-	    isSymbol = __webpack_require__(57);
-
-	/** Used as references for various `Number` constants. */
-	var INFINITY = 1 / 0;
-
-	/** Used to convert symbols to primitives and strings. */
-	var symbolProto = Symbol ? Symbol.prototype : undefined,
-	    symbolToString = symbolProto ? symbolProto.toString : undefined;
-
-	/**
-	 * 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;
-	}
-
-	module.exports = baseToString;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var baseHas = __webpack_require__(102),
+    hasPath = __webpack_require__(103);
+
+/**
+ * Checks if `path` is a direct property of `object`.
+ *
+ * @static
+ * @since 0.1.0
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @param {Array|string} path The path to check.
+ * @returns {boolean} Returns `true` if `path` exists, else `false`.
+ * @example
+ *
+ * var object = { 'a': { 'b': 2 } };
+ * var other = _.create({ 'a': _.create({ 'b': 2 }) });
+ *
+ * _.has(object, 'a');
+ * // => true
+ *
+ * _.has(object, 'a.b');
+ * // => true
+ *
+ * _.has(object, ['a', 'b']);
+ * // => true
+ *
+ * _.has(other, 'a');
+ * // => false
+ */
+function has(object, path) {
+  return object != null && hasPath(object, path, baseHas);
+}
+
+module.exports = has;
+
+
+/***/ }),
 /* 102 */
-/***/ function(module, exports) {
-
-	/**
-	 * 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;
-	}
-
-	module.exports = arrayMap;
-
-
-/***/ },
+/***/ (function(module, exports) {
+
+/** Used for built-in method references. */
+var objectProto = Object.prototype;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/**
+ * 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);
+}
+
+module.exports = baseHas;
+
+
+/***/ }),
 /* 103 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var isSymbol = __webpack_require__(57);
-
-	/** Used as references for various `Number` constants. */
-	var INFINITY = 1 / 0;
-
-	/**
-	 * Converts `value` to a string key if it's not a string or symbol.
-	 *
-	 * @private
-	 * @param {*} value The value to inspect.
-	 * @returns {string|symbol} Returns the key.
-	 */
-	function toKey(value) {
-	  if (typeof value == 'string' || isSymbol(value)) {
-	    return value;
-	  }
-	  var result = (value + '');
-	  return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
-	}
-
-	module.exports = toKey;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var castPath = __webpack_require__(22),
+    isArguments = __webpack_require__(104),
+    isArray = __webpack_require__(5),
+    isIndex = __webpack_require__(106),
+    isLength = __webpack_require__(107),
+    toKey = __webpack_require__(25);
+
+/**
+ * Checks if `path` exists on `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Array|string} path The path to check.
+ * @param {Function} hasFunc The function to check properties.
+ * @returns {boolean} Returns `true` if `path` exists, else `false`.
+ */
+function hasPath(object, path, hasFunc) {
+  path = castPath(path, object);
+
+  var index = -1,
+      length = path.length,
+      result = false;
+
+  while (++index < length) {
+    var key = toKey(path[index]);
+    if (!(result = object != null && hasFunc(object, key))) {
+      break;
+    }
+    object = object[key];
+  }
+  if (result || ++index != length) {
+    return result;
+  }
+  length = object == null ? 0 : object.length;
+  return !!length && isLength(length) && isIndex(key, length) &&
+    (isArray(object) || isArguments(object));
+}
+
+module.exports = hasPath;
+
+
+/***/ }),
 /* 104 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var baseHas = __webpack_require__(105),
-	    hasPath = __webpack_require__(106);
-
-	/**
-	 * Checks if `path` is a direct property of `object`.
-	 *
-	 * @static
-	 * @since 0.1.0
-	 * @memberOf _
-	 * @category Object
-	 * @param {Object} object The object to query.
-	 * @param {Array|string} path The path to check.
-	 * @returns {boolean} Returns `true` if `path` exists, else `false`.
-	 * @example
-	 *
-	 * var object = { 'a': { 'b': 2 } };
-	 * var other = _.create({ 'a': _.create({ 'b': 2 }) });
-	 *
-	 * _.has(object, 'a');
-	 * // => true
-	 *
-	 * _.has(object, 'a.b');
-	 * // => true
-	 *
-	 * _.has(object, ['a', 'b']);
-	 * // => true
-	 *
-	 * _.has(other, 'a');
-	 * // => false
-	 */
-	function has(object, path) {
-	  return object != null && hasPath(object, path, baseHas);
-	}
-
-	module.exports = has;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var baseIsArguments = __webpack_require__(105),
+    isObjectLike = __webpack_require__(15);
+
+/** Used for built-in method references. */
+var objectProto = Object.prototype;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/** Built-in value references. */
+var propertyIsEnumerable = objectProto.propertyIsEnumerable;
+
+/**
+ * Checks if `value` is likely an `arguments` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an `arguments` object,
+ *  else `false`.
+ * @example
+ *
+ * _.isArguments(function() { return arguments; }());
+ * // => true
+ *
+ * _.isArguments([1, 2, 3]);
+ * // => false
+ */
+var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {
+  return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&
+    !propertyIsEnumerable.call(value, 'callee');
+};
+
+module.exports = isArguments;
+
+
+/***/ }),
 /* 105 */
-/***/ function(module, exports) {
-
-	/** Used for built-in method references. */
-	var objectProto = Object.prototype;
-
-	/** Used to check objects for own properties. */
-	var hasOwnProperty = objectProto.hasOwnProperty;
-
-	/**
-	 * 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);
-	}
-
-	module.exports = baseHas;
-
-
-/***/ },
+/***/ (function(module, exports, __webpack_require__) {
+
+var baseGetTag = __webpack_require__(12),
+    isObjectLike = __webpack_require__(15);
+
+/** `Object#toString` result references. */
+var argsTag = '[object Arguments]';
+
+/**
+ * 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;
+}
+
+module.exports = baseIsArguments;
+
+
+/***/ }),
 /* 106 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var castPath = __webpack_require__(54),
-	    isArguments = __webpack_require__(107),
-	    isArray = __webpack_require__(55),
-	    isIndex = __webpack_require__(109),
-	    isLength = __webpack_require__(110),
-	    toKey = __webpack_require__(103);
-
-	/**
-	 * Checks if `path` exists on `object`.
-	 *
-	 * @private
-	 * @param {Object} object The object to query.
-	 * @param {Array|string} path The path to check.
-	 * @param {Function} hasFunc The function to check properties.
-	 * @returns {boolean} Returns `true` if `path` exists, else `false`.
-	 */
-	function hasPath(object, path, hasFunc) {
-	  path = castPath(path, object);
-
-	  var index = -1,
-	      length = path.length,
-	      result = false;
-
-	  while (++index < length) {
-	    var key = toKey(path[index]);
-	    if (!(result = object != null && hasFunc(object, key))) {
-	      break;
-	    }
-	    object = object[key];
-	  }
-	  if (result || ++index != length) {
-	    return result;
-	  }
-	  length = object == null ? 0 : object.length;
-	  return !!length && isLength(length) && isIndex(key, length) &&
-	    (isArray(object) || isArguments(object));
-	}
-
-	module.exports = hasPath;
-
-
-/***/ },
+/***/ (function(module, exports) {
+
+/** Used as references for various `Number` constants. */
+var MAX_SAFE_INTEGER = 9007199254740991;
+
+/** Used to detect unsigned integer values. */
+var reIsUint = /^(?:0|[1-9]\d*)$/;
+
+/**
+ * Checks if `value` is a valid array-like index.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
+ * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
+ */
+function isIndex(value, length) {
+  length = length == null ? MAX_SAFE_INTEGER : length;
+  return !!length &&
+    (typeof value == 'number' || reIsUint.test(value)) &&
+    (value > -1 && value % 1 == 0 && value < length);
+}
+
+module.exports = isIndex;
+
+
+/***/ }),
 /* 107 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var baseIsArguments = __webpack_require__(108),
-	    isObjectLike = __webpack_require__(64);
-
-	/** Used for built-in method references. */
-	var objectProto = Object.prototype;
-
-	/** Used to check objects for own properties. */
-	var hasOwnProperty = objectProto.hasOwnProperty;
-
-	/** Built-in value references. */
-	var propertyIsEnumerable = objectProto.propertyIsEnumerable;
-
-	/**
-	 * Checks if `value` is likely an `arguments` object.
-	 *
-	 * @static
-	 * @memberOf _
-	 * @since 0.1.0
-	 * @category Lang
-	 * @param {*} value The value to check.
-	 * @returns {boolean} Returns `true` if `value` is an `arguments` object,
-	 *  else `false`.
-	 * @example
-	 *
-	 * _.isArguments(function() { return arguments; }());
-	 * // => true
-	 *
-	 * _.isArguments([1, 2, 3]);
-	 * // => false
-	 */
-	var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {
-	  return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&
-	    !propertyIsEnumerable.call(value, 'callee');
-	};
-
-	module.exports = isArguments;
-
-
-/***/ },
-/* 108 */
-/***/ function(module, exports, __webpack_require__) {
-
-	var baseGetTag = __webpack_require__(58),
-	    isObjectLike = __webpack_require__(64);
-
-	/** `Object#toString` result references. */
-	var argsTag = '[object Arguments]';
-
-	/**
-	 * 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;
-	}
-
-	module.exports = baseIsArguments;
-
-
-/***/ },
-/* 109 */
-/***/ function(module, exports) {
-
-	/** Used as references for various `Number` constants. */
-	var MAX_SAFE_INTEGER = 9007199254740991;
-
-	/** Used to detect unsigned integer values. */
-	var reIsUint = /^(?:0|[1-9]\d*)$/;
-
-	/**
-	 * Checks if `value` is a valid array-like index.
-	 *
-	 * @private
-	 * @param {*} value The value to check.
-	 * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
-	 * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
-	 */
-	function isIndex(value, length) {
-	  length = length == null ? MAX_SAFE_INTEGER : length;
-	  return !!length &&
-	    (typeof value == 'number' || reIsUint.test(value)) &&
-	    (value > -1 && value % 1 == 0 && value < length);
-	}
-
-	module.exports = isIndex;
-
-
-/***/ },
-/* 110 */
-/***/ function(module, exports) {
-
-	/** Used as references for various `Number` constants. */
-	var MAX_SAFE_INTEGER = 9007199254740991;
-
-	/**
-	 * Checks if `value` is a valid array-like length.
-	 *
-	 * **Note:** This method is loosely based on
-	 * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
-	 *
-	 * @static
-	 * @memberOf _
-	 * @since 4.0.0
-	 * @category Lang
-	 * @param {*} value The value to check.
-	 * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
-	 * @example
-	 *
-	 * _.isLength(3);
-	 * // => true
-	 *
-	 * _.isLength(Number.MIN_VALUE);
-	 * // => false
-	 *
-	 * _.isLength(Infinity);
-	 * // => false
-	 *
-	 * _.isLength('3');
-	 * // => false
-	 */
-	function isLength(value) {
-	  return typeof value == 'number' &&
-	    value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
-	}
-
-	module.exports = isLength;
-
-
-/***/ }
-/******/ ])
-});
-;
\ No newline at end of file
+/***/ (function(module, exports) {
+
+/** Used as references for various `Number` constants. */
+var MAX_SAFE_INTEGER = 9007199254740991;
+
+/**
+ * Checks if `value` is a valid array-like length.
+ *
+ * **Note:** This method is loosely based on
+ * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
+ * @example
+ *
+ * _.isLength(3);
+ * // => true
+ *
+ * _.isLength(Number.MIN_VALUE);
+ * // => false
+ *
+ * _.isLength(Infinity);
+ * // => false
+ *
+ * _.isLength('3');
+ * // => false
+ */
+function isLength(value) {
+  return typeof value == 'number' &&
+    value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+}
+
+module.exports = isLength;
+
+
+/***/ })
+/******/ ]);
+});
\ No newline at end of file
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_object_inspector_entries.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_object_inspector_entries.js
@@ -2,16 +2,17 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Check expanding/collapsing maps and sets in the console.
 const TEST_URI = "data:text/html;charset=utf8,<h1>Object Inspector on Maps & Sets</h1>";
+const {ELLIPSIS} = require("devtools/shared/l10n");
 
 add_task(async function () {
   const hud = await openNewTabAndConsole(TEST_URI);
   const store = hud.ui.newConsoleOutput.getStore();
   // Adding logging each time the store is modified in order to check
   // the store state in case of failure.
   store.subscribe(() => {
     const messages = store.getState().messages.messagesById
@@ -108,20 +109,20 @@ async function testLargeMap(oi) {
   });
 
   entriesNode.querySelector(".arrow").click();
   await onMapOiMutation;
 
   oiNodes = oi.querySelectorAll(".node");
   // There are now 8 nodes, the 4 original ones, and the 4 buckets.
   is(oiNodes.length, 8, "There is the expected number of nodes in the tree");
-  is(oiNodes[3].textContent, "[0..99]");
-  is(oiNodes[4].textContent, "[100..199]");
-  is(oiNodes[5].textContent, "[200..299]");
-  is(oiNodes[6].textContent, "[300..331]");
+  is(oiNodes[3].textContent, `[0${ELLIPSIS}99]`);
+  is(oiNodes[4].textContent, `[100${ELLIPSIS}199]`);
+  is(oiNodes[5].textContent, `[200${ELLIPSIS}299]`);
+  is(oiNodes[6].textContent, `[300${ELLIPSIS}330]`);
 }
 
 async function testSet(oi) {
   info("Expanding the Set");
   let onSetOiMutation = waitForNodeMutation(oi, {
     childList: true
   });
 
@@ -174,12 +175,12 @@ async function testLargeSet(oi) {
   });
 
   entriesNode.querySelector(".arrow").click();
   await onSetOiMutation;
 
   oiNodes = oi.querySelectorAll(".node");
   // There are now 7 nodes, the 4 original ones, and the 3 buckets.
   is(oiNodes.length, 7, "There is the expected number of nodes in the tree");
-  is(oiNodes[3].textContent, "[0..99]");
-  is(oiNodes[4].textContent, "[100..199]");
-  is(oiNodes[5].textContent, "[200..222]");
+  is(oiNodes[3].textContent, `[0${ELLIPSIS}99]`);
+  is(oiNodes[4].textContent, `[100${ELLIPSIS}199]`);
+  is(oiNodes[5].textContent, `[200${ELLIPSIS}221]`);
 }