Bug 1325401 - Add a reps bundle, disabled by default;r=jlast draft
authorJulian Descottes <jdescottes@mozilla.com>
Wed, 18 Jan 2017 14:38:10 +0100
changeset 463084 0b954d265215467248443cac17a2b7a4b9b0ee78
parent 461121 8eaf154b385bbe0ff06155294ccf7962aa2d3324
child 463085 2e14b023d479705217aeaaba3382a05fc3c4c904
push id41946
push userjdescottes@mozilla.com
push dateWed, 18 Jan 2017 13:39:08 +0000
reviewersjlast
bugs1325401
milestone53.0a1
Bug 1325401 - Add a reps bundle, disabled by default;r=jlast MozReview-Commit-ID: IJL8wevR0wo
.eslintignore
devtools/client/dom/content/components/dom-tree.js
devtools/client/dom/content/components/main-toolbar.js
devtools/client/jsonview/components/headers-panel.js
devtools/client/jsonview/components/json-panel.js
devtools/client/jsonview/components/main-tabbed-area.js
devtools/client/jsonview/components/text-panel.js
devtools/client/jsonview/json-viewer.js
devtools/client/shared/components/reps/load-reps.js
devtools/client/shared/components/reps/moz.build
devtools/client/shared/components/reps/rep.js
devtools/client/shared/components/reps/reps.js
devtools/client/webconsole/net/components/net-info-body.js
devtools/client/webconsole/net/components/post-tab.js
devtools/client/webconsole/net/components/response-tab.js
devtools/client/webconsole/net/main.js
devtools/client/webconsole/net/net-request.js
devtools/client/webconsole/new-console-output/components/console-table.js
devtools/client/webconsole/new-console-output/components/grip-message-body.js
--- a/.eslintignore
+++ b/.eslintignore
@@ -85,16 +85,17 @@ devtools/client/framework/**
 !devtools/client/framework/toolbox.js
 devtools/client/netmonitor/test/**
 devtools/client/netmonitor/har/test/**
 devtools/client/projecteditor/**
 devtools/client/responsivedesign/**
 devtools/client/scratchpad/**
 devtools/client/shadereditor/**
 devtools/client/shared/*.jsm
+devtools/client/shared/components/reps/reps.js
 devtools/client/shared/webgl-utils.js
 devtools/client/shared/widgets/*.jsm
 devtools/client/webaudioeditor/**
 devtools/client/webconsole/net/**
 devtools/client/webconsole/test/**
 devtools/client/webconsole/console-output.js
 devtools/client/webconsole/hudservice.js
 devtools/client/webconsole/utils.js
--- a/devtools/client/dom/content/components/dom-tree.js
+++ b/devtools/client/dom/content/components/dom-tree.js
@@ -4,22 +4,22 @@
  * 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/. */
 "use strict";
 
 // React & Redux
 const React = require("devtools/client/shared/vendor/react");
 const { connect } = require("devtools/client/shared/vendor/react-redux");
 
+const TreeView = React.createFactory(require("devtools/client/shared/components/tree/tree-view"));
+
 // Reps
-const { createFactories } = require("devtools/client/shared/components/reps/rep-utils");
-const TreeView = React.createFactory(require("devtools/client/shared/components/tree/tree-view"));
-const { Rep } = createFactories(require("devtools/client/shared/components/reps/rep"));
-const { Grip } = require("devtools/client/shared/components/reps/grip");
-const { MODE } = require("devtools/client/shared/components/reps/constants");
+const { REPS, MODE } = require("devtools/client/shared/components/reps/load-reps");
+const Rep = React.createFactory(REPS.Rep);
+const Grip = REPS.Grip;
 
 // DOM Panel
 const { GripProvider } = require("../grip-provider");
 const { DomDecorator } = require("../dom-decorator");
 
 // Shortcuts
 const PropTypes = React.PropTypes;
 
@@ -84,9 +84,8 @@ const mapStateToProps = (state) => {
   return {
     grips: state.grips,
     filter: state.filter
   };
 };
 
 // Exports from this module
 module.exports = connect(mapStateToProps)(DomTree);
-
--- a/devtools/client/dom/content/components/main-toolbar.js
+++ b/devtools/client/dom/content/components/main-toolbar.js
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 // React
 const React = require("devtools/client/shared/vendor/react");
 const { l10n } = require("../utils");
 
 // Reps
-const { createFactories } = require("devtools/client/shared/components/reps/rep-utils");
+const { createFactories } = require("devtools/client/shared/components/reps/load-reps");
 const { Toolbar, ToolbarButton } = createFactories(require("devtools/client/jsonview/components/reps/toolbar"));
 
 // DOM Panel
 const SearchBox = React.createFactory(require("devtools/client/shared/components/search-box"));
 
 // Actions
 const { fetchProperties } = require("../actions/grips");
 const { setVisibilityFilter } = require("../actions/filter");
--- a/devtools/client/jsonview/components/headers-panel.js
+++ b/devtools/client/jsonview/components/headers-panel.js
@@ -3,17 +3,19 @@
 /* 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/. */
 
 "use strict";
 
 define(function (require, exports, module) {
   const { DOM: dom, createFactory, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
-  const { createFactories } = require("devtools/client/shared/components/reps/rep-utils");
+
+  const { createFactories } = require("devtools/client/shared/components/reps/load-reps");
+
   const { Headers } = createFactories(require("./headers"));
   const { Toolbar, ToolbarButton } = createFactories(require("./reps/toolbar"));
 
   const { div } = dom;
 
   /**
    * This template represents the 'Headers' panel
    * s responsible for rendering its content.
--- a/devtools/client/jsonview/components/json-panel.js
+++ b/devtools/client/jsonview/components/json-panel.js
@@ -3,20 +3,21 @@
 /* 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/. */
 
 "use strict";
 
 define(function (require, exports, module) {
   const { DOM: dom, createFactory, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
-  const { createFactories } = require("devtools/client/shared/components/reps/rep-utils");
   const TreeView = createFactory(require("devtools/client/shared/components/tree/tree-view"));
-  const { Rep } = createFactories(require("devtools/client/shared/components/reps/rep"));
-  const { MODE } = require("devtools/client/shared/components/reps/constants");
+
+  const { REPS, createFactories, MODE } = require("devtools/client/shared/components/reps/load-reps");
+  const Rep = createFactory(REPS.Rep);
+
   const { SearchBox } = createFactories(require("./search-box"));
   const { Toolbar, ToolbarButton } = createFactories(require("./reps/toolbar"));
 
   const { div } = dom;
   const AUTO_EXPAND_MAX_SIZE = 100 * 1024;
   const AUTO_EXPAND_MAX_LEVEL = 7;
 
   /**
--- a/devtools/client/jsonview/components/main-tabbed-area.js
+++ b/devtools/client/jsonview/components/main-tabbed-area.js
@@ -3,17 +3,18 @@
 /* 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/. */
 
 "use strict";
 
 define(function (require, exports, module) {
   const { createClass, PropTypes } = require("devtools/client/shared/vendor/react");
-  const { createFactories } = require("devtools/client/shared/components/reps/rep-utils");
+
+  const { createFactories } = require("devtools/client/shared/components/reps/load-reps");
   const { JsonPanel } = createFactories(require("./json-panel"));
   const { TextPanel } = createFactories(require("./text-panel"));
   const { HeadersPanel } = createFactories(require("./headers-panel"));
   const { Tabs, TabPanel } = createFactories(require("devtools/client/shared/components/tabs/tabs"));
 
   /**
    * This object represents the root application template
    * responsible for rendering the basic tab layout.
--- a/devtools/client/jsonview/components/text-panel.js
+++ b/devtools/client/jsonview/components/text-panel.js
@@ -3,17 +3,19 @@
 /* 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/. */
 
 "use strict";
 
 define(function (require, exports, module) {
   const { DOM: dom, createFactory, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
-  const { createFactories } = require("devtools/client/shared/components/reps/rep-utils");
+
+  // we'll need to make load-reps define friendly aka UMD
+  const { createFactories } = require("devtools/client/shared/components/reps/load-reps");
   const { Toolbar, ToolbarButton } = createFactories(require("./reps/toolbar"));
   const { div, pre } = dom;
 
   /**
    * This template represents the 'Raw Data' panel displaying
    * JSON as a text received from the server.
    */
   let TextPanel = createClass({
--- a/devtools/client/jsonview/json-viewer.js
+++ b/devtools/client/jsonview/json-viewer.js
@@ -3,17 +3,17 @@
 /* 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/. */
 
 "use strict";
 
 define(function (require, exports, module) {
   const { render } = require("devtools/client/shared/vendor/react-dom");
-  const { createFactories } = require("devtools/client/shared/components/reps/rep-utils");
+  const { createFactories } = require("devtools/client/shared/components/reps/load-reps");
   const { MainTabbedArea } = createFactories(require("./components/main-tabbed-area"));
 
   const json = document.getElementById("json");
   const headers = document.getElementById("headers");
 
   let jsonData;
 
   try {
@@ -104,9 +104,8 @@ define(function (require, exports, modul
   onResize();
 
   // Send notification event to the window. Can be useful for
   // tests as well as extensions.
   let event = new CustomEvent("JSONViewInitialized", {});
   window.jsonViewInitialized = true;
   window.dispatchEvent(event);
 });
-
new file mode 100644
--- /dev/null
+++ b/devtools/client/shared/components/reps/load-reps.js
@@ -0,0 +1,37 @@
+/* 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/. */
+
+"use strict";
+
+// Make this available to both AMD and CJS environments
+define(function (require, exports, module) {
+  let REPS;
+  let MODE;
+  let createFactories;
+  let parseURLEncodedText;
+  let parseURLParams;
+
+  // useRepsBundle hardcoded to false while we experiment with the reps bundle in
+  // bugs 1325401 and 1330779. Set it to true to test devtools using the reps bundle.
+  let useRepsBundle = false;
+  if (useRepsBundle) {
+    const bundle = require("devtools/client/shared/components/reps/reps");
+    REPS = bundle.REPS;
+    MODE = bundle.MODE;
+    createFactories = bundle.createFactories;
+    parseURLEncodedText = bundle.parseURLEncodedText;
+    parseURLParams = bundle.parseURLParams;
+  } else {
+    ({ createFactories, parseURLEncodedText, parseURLParams } =
+      require("devtools/client/shared/components/reps/rep-utils"));
+    REPS = require("devtools/client/shared/components/reps/rep").REPS;
+    MODE = require("devtools/client/shared/components/reps/constants").MODE;
+  }
+
+  exports.REPS = REPS;
+  exports.MODE = MODE;
+  exports.createFactories = createFactories;
+  exports.parseURLEncodedText = parseURLEncodedText;
+  exports.parseURLParams = parseURLParams;
+});
--- a/devtools/client/shared/components/reps/moz.build
+++ b/devtools/client/shared/components/reps/moz.build
@@ -15,28 +15,30 @@ DevToolsModules(
     'element-node.js',
     'error.js',
     'event.js',
     'function.js',
     'grip-array.js',
     'grip-map.js',
     'grip.js',
     'infinity.js',
+    'load-reps.js',
     'long-string.js',
     'nan.js',
     'null.js',
     'number.js',
     'object-with-text.js',
     'object-with-url.js',
     'object.js',
     'promise.js',
     'prop-rep.js',
     'regexp.js',
     'rep-utils.js',
     'rep.js',
     'reps.css',
+    'reps.js',
     'string.js',
     'stylesheet.js',
     'symbol.js',
     'text-node.js',
     'undefined.js',
     'window.js',
 )
--- a/devtools/client/shared/components/reps/rep.js
+++ b/devtools/client/shared/components/reps/rep.js
@@ -140,9 +140,41 @@ define(function (require, exports, modul
       }
     }
 
     return React.createFactory(defaultRep.rep);
   }
 
   // Exports from this module
   exports.Rep = Rep;
+
+  // Export all reps
+  exports.REPS = {
+    ArrayRep,
+    Attribute,
+    CommentNode,
+    DateTime,
+    Document,
+    ElementNode,
+    ErrorRep,
+    Event,
+    Func,
+    Grip,
+    GripArray,
+    GripMap,
+    InfinityRep,
+    LongStringRep,
+    NaNRep,
+    Null,
+    Number,
+    ObjectWithText,
+    ObjectWithURL,
+    PromiseRep,
+    RegExp,
+    Rep,
+    StringRep,
+    StyleSheet,
+    SymbolRep,
+    TextNode,
+    Undefined,
+    Window,
+  };
 });
new file mode 100644
--- /dev/null
+++ b/devtools/client/shared/components/reps/reps.js
@@ -0,0 +1,2731 @@
+(function webpackUniversalModuleDefinition(root, factory) {
+	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_1__) {
+return /******/ (function(modules) { // webpackBootstrap
+/******/ 	// The module cache
+/******/ 	var installedModules = {};
+/******/
+/******/ 	// The require function
+/******/ 	function __webpack_require__(moduleId) {
+/******/ 		// SingleModulePlugin
+/******/ 		const smpCache = this.smpCache = this.smpCache || {};
+/******/ 		const smpMap = this.smpMap = this.smpMap || new Map();
+/******/ 		function sanitizeString(text) {
+/******/ 		   return text.replace(/__webpack_require__\(\d+\)/g,"");
+/******/ 		}
+/******/ 		function getModuleBody(id) {
+/******/ 		  if (smpCache.hasOwnProperty(id)) {
+/******/ 		    return smpCache[id];
+/******/ 		  }
+/******/
+/******/ 		  const body = sanitizeString(String(modules[id]));
+/******/ 		  smpCache[id] = body;
+/******/ 		  return body;
+/******/ 		}
+/******/ 		if (!installedModules[moduleId]) {
+/******/ 			const body = getModuleBody(moduleId);
+/******/ 			if (smpMap.has(body)) {
+/******/ 				installedModules[moduleId] = installedModules[smpMap.get(body)];
+/******/ 			}
+/******/ 			else {
+/******/ 				smpMap.set(body, moduleId)
+/******/ 			}
+/******/ 		}
+/******/
+/******/ 		// Check if module is in cache
+/******/ 		if(installedModules[moduleId])
+/******/ 			return installedModules[moduleId].exports;
+/******/
+/******/ 		// Create a new module (and put it into the cache)
+/******/ 		var module = installedModules[moduleId] = {
+/******/ 			exports: {},
+/******/ 			id: moduleId,
+/******/ 			loaded: false
+/******/ 		};
+/******/
+/******/ 		// Execute the module function
+/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+/******/
+/******/ 		// Flag the module as loaded
+/******/ 		module.loaded = 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;
+/******/
+/******/ 	// __webpack_public_path__
+/******/ 	__webpack_require__.p = "/assets/build";
+/******/
+/******/ 	// Load entry module and return exports
+/******/ 	return __webpack_require__(0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+
+	const { MODE } = __webpack_require__(2);
+	const { REPS } = __webpack_require__(3);
+	const { createFactories, parseURLEncodedText, parseURLParams } = __webpack_require__(4);
+
+	module.exports = {
+	  REPS,
+	  MODE,
+	  createFactories,
+	  parseURLEncodedText,
+	  parseURLParams
+	};
+
+/***/ },
+/* 1 */
+/***/ function(module, exports) {
+
+	module.exports = __WEBPACK_EXTERNAL_MODULE_1__;
+
+/***/ },
+/* 2 */
+/***/ function(module, exports) {
+
+	module.exports = {
+	  MODE: {
+	    TINY: Symbol("TINY"),
+	    SHORT: Symbol("SHORT"),
+	    LONG: Symbol("LONG")
+	  }
+	};
+
+/***/ },
+/* 3 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+
+	const { isGrip } = __webpack_require__(4);
+	const { MODE } = __webpack_require__(2);
+
+	// Load all existing rep templates
+	const Undefined = __webpack_require__(5);
+	const Null = __webpack_require__(6);
+	const StringRep = __webpack_require__(7);
+	const LongStringRep = __webpack_require__(8);
+	const Number = __webpack_require__(9);
+	const ArrayRep = __webpack_require__(10);
+	const Obj = __webpack_require__(12);
+	const SymbolRep = __webpack_require__(15);
+	const InfinityRep = __webpack_require__(16);
+	const NaNRep = __webpack_require__(17);
+
+	// DOM types (grips)
+	const Attribute = __webpack_require__(18);
+	const DateTime = __webpack_require__(19);
+	const Document = __webpack_require__(20);
+	const Event = __webpack_require__(21);
+	const Func = __webpack_require__(22);
+	const PromiseRep = __webpack_require__(23);
+	const RegExp = __webpack_require__(24);
+	const StyleSheet = __webpack_require__(25);
+	const CommentNode = __webpack_require__(26);
+	const ElementNode = __webpack_require__(28);
+	const TextNode = __webpack_require__(29);
+	const ErrorRep = __webpack_require__(30);
+	const Window = __webpack_require__(31);
+	const ObjectWithText = __webpack_require__(32);
+	const ObjectWithURL = __webpack_require__(33);
+	const GripArray = __webpack_require__(34);
+	const GripMap = __webpack_require__(35);
+	const Grip = __webpack_require__(14);
+
+	// 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, Grip, Undefined, Null, StringRep, Number, SymbolRep, InfinityRep, NaNRep];
+
+	/**
+	 * 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 = React.createClass({
+	  displayName: "Rep",
+
+	  propTypes: {
+	    object: React.PropTypes.any,
+	    defaultRep: 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]))
+	  },
+
+	  render: function () {
+	    let rep = getRep(this.props.object, this.props.defaultRep);
+	    return rep(this.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.
+	 */
+	function getRep(object, defaultRep = Obj) {
+	  let type = typeof object;
+	  if (type == "object" && object instanceof String) {
+	    type = "string";
+	  } else if (object && type == "object" && object.type) {
+	    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)) {
+	        return React.createFactory(rep.rep);
+	      }
+	    } catch (err) {
+	      console.error(err);
+	    }
+	  }
+
+	  return React.createFactory(defaultRep.rep);
+	}
+
+	module.exports = {
+	  Rep,
+	  REPS: {
+	    ArrayRep,
+	    Attribute,
+	    CommentNode,
+	    DateTime,
+	    Document,
+	    ElementNode,
+	    ErrorRep,
+	    Event,
+	    Func,
+	    Grip,
+	    GripArray,
+	    GripMap,
+	    InfinityRep,
+	    LongStringRep,
+	    NaNRep,
+	    Null,
+	    Number,
+	    ObjectWithText,
+	    ObjectWithURL,
+	    PromiseRep,
+	    RegExp,
+	    Rep,
+	    StringRep,
+	    StyleSheet,
+	    SymbolRep,
+	    TextNode,
+	    Undefined,
+	    Window
+	  }
+	};
+
+/***/ },
+/* 4 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+
+	/**
+	 * Create React factories for given arguments.
+	 * Example:
+	 *   const { Rep } = createFactories(require("./rep"));
+	 */
+	function createFactories(args) {
+	  let result = {};
+	  for (let p in args) {
+	    result[p] = React.createFactory(args[p]);
+	  }
+	  return result;
+	}
+
+	/**
+	 * 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");
+	}
+
+	function cropMultipleLines(text, limit) {
+	  return escapeNewLines(cropString(text, limit));
+	}
+
+	function cropString(text, limit, alternativeText) {
+	  if (!alternativeText) {
+	    alternativeText = "\u2026";
+	  }
+
+	  // Make sure it's a string and sanitize it.
+	  text = sanitizeString(text + "");
+
+	  // 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 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\x80-\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]
+	  };
+	}
+
+	module.exports = {
+	  createFactories,
+	  isGrip,
+	  cropString,
+	  sanitizeString,
+	  cropMultipleLines,
+	  parseURLParams,
+	  parseURLEncodedText,
+	  getFileName,
+	  getURLDisplayString
+	};
+
+/***/ },
+/* 5 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+
+	// Shortcuts
+	const { span } = React.DOM;
+
+	/**
+	 * Renders undefined value
+	 */
+	const Undefined = React.createClass({
+	  displayName: "UndefinedRep",
+
+	  render: function () {
+	    return span({ className: "objectBox objectBox-undefined" }, "undefined");
+	  }
+	});
+
+	function supportsObject(object, type) {
+	  if (object && object.type && object.type == "undefined") {
+	    return true;
+	  }
+
+	  return type == "undefined";
+	}
+
+	module.exports = {
+	  rep: Undefined,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 6 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+
+	// Shortcuts
+	const { span } = React.DOM;
+
+	/**
+	 * Renders null value
+	 */
+	const Null = React.createClass({
+	  displayName: "NullRep",
+
+	  render: function () {
+	    return span({ className: "objectBox objectBox-null" }, "null");
+	  }
+	});
+
+	function supportsObject(object, type) {
+	  if (object && object.type && object.type == "null") {
+	    return true;
+	  }
+
+	  return object == null;
+	}
+
+	module.exports = {
+	  rep: Null,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 7 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+	const { cropString } = __webpack_require__(4);
+
+	// Shortcuts
+	const { span } = React.DOM;
+
+	/**
+	 * Renders a string. String value is enclosed within quotes.
+	 */
+	const StringRep = React.createClass({
+	  displayName: "StringRep",
+
+	  propTypes: {
+	    useQuotes: React.PropTypes.bool,
+	    style: React.PropTypes.object
+	  },
+
+	  getDefaultProps: function () {
+	    return {
+	      useQuotes: true
+	    };
+	  },
+
+	  render: function () {
+	    let text = this.props.object;
+	    let member = this.props.member;
+	    let style = this.props.style;
+
+	    let config = { className: "objectBox objectBox-string" };
+	    if (style) {
+	      config.style = style;
+	    }
+
+	    if (member && member.open) {
+	      return span(config, "\"" + text + "\"");
+	    }
+
+	    let croppedString = this.props.cropLimit ? cropString(text, this.props.cropLimit) : cropString(text);
+
+	    let formattedString = this.props.useQuotes ? "\"" + croppedString + "\"" : croppedString;
+
+	    return span(config, formattedString);
+	  }
+	});
+
+	function supportsObject(object, type) {
+	  return type == "string";
+	}
+
+	module.exports = {
+	  rep: StringRep,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 8 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+	const { sanitizeString, isGrip } = __webpack_require__(4);
+	// Shortcuts
+	const { span } = React.DOM;
+
+	/**
+	 * Renders a long string grip.
+	 */
+	const LongStringRep = React.createClass({
+	  displayName: "LongStringRep",
+
+	  propTypes: {
+	    useQuotes: React.PropTypes.bool,
+	    style: React.PropTypes.object
+	  },
+
+	  getDefaultProps: function () {
+	    return {
+	      useQuotes: true
+	    };
+	  },
+
+	  render: function () {
+	    let {
+	      cropLimit,
+	      member,
+	      object,
+	      style,
+	      useQuotes
+	    } = this.props;
+	    let { fullText, initial, length } = object;
+
+	    let config = { 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 ? `"${ string }"` : string;
+	    return span(config, sanitizeString(formattedString));
+	  }
+	});
+
+	function supportsObject(object, type) {
+	  if (!isGrip(object)) {
+	    return false;
+	  }
+	  return object.type === "longString";
+	}
+
+	module.exports = {
+	  rep: LongStringRep,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 9 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+
+	// Shortcuts
+	const { span } = React.DOM;
+
+	/**
+	 * Renders a number
+	 */
+	const Number = React.createClass({
+	  displayName: "Number",
+
+	  stringify: function (object) {
+	    let isNegativeZero = Object.is(object, -0) || object.type && object.type == "-0";
+
+	    return isNegativeZero ? "-0" : String(object);
+	  },
+
+	  render: function () {
+	    let value = this.props.object;
+
+	    return span({ className: "objectBox objectBox-number" }, this.stringify(value));
+	  }
+	});
+
+	function supportsObject(object, type) {
+	  return ["boolean", "number", "-0"].includes(type);
+	}
+
+	module.exports = {
+	  rep: Number,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 10 */
+/***/ function(module, exports, __webpack_require__) {
+
+
+	const React = __webpack_require__(1);
+	const Caption = React.createFactory(__webpack_require__(11));
+	const { MODE } = __webpack_require__(2);
+
+	// 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.
+	 */
+	let ArrayRep = React.createClass({
+	  displayName: "ArrayRep",
+
+	  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]))
+	  },
+
+	  getTitle: function (object, context) {
+	    return "[" + object.length + "]";
+	  },
+
+	  arrayIterator: function (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) {
+	      let objectLink = this.props.objectLink || DOM.span;
+	      items.push(Caption({
+	        object: objectLink({
+	          object: this.props.object
+	        }, array.length - max + " more…")
+	      }));
+	    }
+
+	    return items;
+	  },
+
+	  /**
+	   * Returns true if the passed object is an array with additional (custom)
+	   * properties, otherwise returns false. Custom properties should be
+	   * displayed in extra expandable section.
+	   *
+	   * Example array with a custom property.
+	   * let arr = [0, 1];
+	   * arr.myProp = "Hello";
+	   *
+	   * @param {Array} array The array object.
+	   */
+	  hasSpecialProperties: function (array) {
+	    function isInteger(x) {
+	      let y = parseInt(x, 10);
+	      if (isNaN(y)) {
+	        return false;
+	      }
+	      return x === y.toString();
+	    }
+
+	    let props = Object.getOwnPropertyNames(array);
+	    for (let i = 0; i < props.length; i++) {
+	      let p = props[i];
+
+	      // Valid indexes are skipped
+	      if (isInteger(p)) {
+	        continue;
+	      }
+
+	      // Ignore standard 'length' property, anything else is custom.
+	      if (p != "length") {
+	        return true;
+	      }
+	    }
+
+	    return false;
+	  },
+
+	  // Event Handlers
+
+	  onToggleProperties: function (event) {},
+
+	  onClickBracket: function (event) {},
+
+	  render: function () {
+	    let {
+	      object,
+	      mode = MODE.SHORT
+	    } = this.props;
+
+	    let items;
+	    let brackets;
+	    let needSpace = function (space) {
+	      return space ? { left: "[ ", right: " ]" } : { left: "[", right: "]" };
+	    };
+
+	    if (mode === MODE.TINY) {
+	      let isEmpty = object.length === 0;
+	      items = [DOM.span({ className: "length" }, isEmpty ? "" : object.length)];
+	      brackets = needSpace(false);
+	    } else {
+	      let max = mode === MODE.SHORT ? 3 : 10;
+	      items = this.arrayIterator(object, max);
+	      brackets = needSpace(items.length > 0);
+	    }
+
+	    let objectLink = this.props.objectLink || DOM.span;
+
+	    return DOM.span({
+	      className: "objectBox objectBox-array" }, objectLink({
+	      className: "arrayLeftBracket",
+	      object: object
+	    }, brackets.left), ...items, objectLink({
+	      className: "arrayRightBracket",
+	      object: object
+	    }, brackets.right), DOM.span({
+	      className: "arrayProperties",
+	      role: "group" }));
+	  }
+	});
+
+	/**
+	 * Renders array item. Individual values are separated by a comma.
+	 */
+	let ItemRep = React.createFactory(React.createClass({
+	  displayName: "ItemRep",
+
+	  render: function () {
+	    const Rep = React.createFactory(__webpack_require__(3));
+
+	    let object = this.props.object;
+	    let delim = this.props.delim;
+	    let mode = this.props.mode;
+	    return DOM.span({}, Rep({ object: object, mode: mode }), delim);
+	  }
+	}));
+
+	function supportsObject(object, type) {
+	  return Array.isArray(object) || Object.prototype.toString.call(object) === "[object Arguments]";
+	}
+
+	module.exports = {
+	  rep: ArrayRep,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 11 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+	const DOM = React.DOM;
+
+	/**
+	 * Renders a caption. This template is used by other components
+	 * that needs to distinguish between a simple text/value and a label.
+	 */
+	const Caption = React.createClass({
+	  displayName: "Caption",
+
+	  render: function () {
+	    return DOM.span({ "className": "caption" }, this.props.object);
+	  }
+	});
+
+	module.exports = Caption;
+
+/***/ },
+/* 12 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+	const Caption = React.createFactory(__webpack_require__(11));
+	const PropRep = React.createFactory(__webpack_require__(13));
+	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.
+	 */
+	const Obj = React.createClass({
+	  displayName: "Obj",
+
+	  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]))
+	  },
+
+	  getTitle: function (object) {
+	    let className = object && object.class ? object.class : "Object";
+	    if (this.props.objectLink) {
+	      return this.props.objectLink({
+	        object: object
+	      }, className);
+	    }
+	    return className;
+	  },
+
+	  safePropIterator: function (object, max) {
+	    max = typeof max === "undefined" ? 3 : max;
+	    try {
+	      return this.propIterator(object, max);
+	    } catch (err) {
+	      console.error(err);
+	    }
+	    return [];
+	  },
+
+	  propIterator: function (object, max) {
+	    let isInterestingProp = (t, value) => {
+	      // Do not pick objects, it could cause recursion.
+	      return t == "boolean" || t == "number" || t == "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 props = this.getProps(object, max, isInterestingProp);
+
+	    if (props.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.
+	      props = props.concat(this.getProps(object, max, (t, value) => {
+	        return !isInterestingProp(t, value);
+	      }));
+	    }
+
+	    if (props.length > max) {
+	      props.pop();
+	      let objectLink = this.props.objectLink || span;
+
+	      props.push(Caption({
+	        object: objectLink({
+	          object: object
+	        }, Object.keys(object).length - max + " more…")
+	      }));
+	    } else if (props.length > 0) {
+	      // Remove the last comma.
+	      props[props.length - 1] = React.cloneElement(props[props.length - 1], { delim: "" });
+	    }
+
+	    return props;
+	  },
+
+	  getProps: function (object, max, filter) {
+	    let props = [];
+
+	    max = max || 3;
+	    if (!object) {
+	      return props;
+	    }
+
+	    // Hardcode tiny mode to avoid recursive handling.
+	    let mode = MODE.TINY;
+
+	    try {
+	      for (let name in object) {
+	        if (props.length > max) {
+	          return props;
+	        }
+
+	        let value;
+	        try {
+	          value = object[name];
+	        } catch (exc) {
+	          continue;
+	        }
+
+	        let t = typeof value;
+	        if (filter(t, value)) {
+	          props.push(PropRep({
+	            mode: mode,
+	            name: name,
+	            object: value,
+	            equal: ": ",
+	            delim: ", "
+	          }));
+	        }
+	      }
+	    } catch (err) {
+	      console.error(err);
+	    }
+
+	    return props;
+	  },
+
+	  render: function () {
+	    let object = this.props.object;
+	    let props = this.safePropIterator(object);
+	    let objectLink = this.props.objectLink || span;
+
+	    if (this.props.mode === MODE.TINY || !props.length) {
+	      return span({ className: "objectBox objectBox-object" }, objectLink({ className: "objectTitle" }, this.getTitle(object)));
+	    }
+
+	    return span({ className: "objectBox objectBox-object" }, this.getTitle(object), objectLink({
+	      className: "objectLeftBrace",
+	      object: object
+	    }, " { "), ...props, objectLink({
+	      className: "objectRightBrace",
+	      object: object
+	    }, " }"));
+	  }
+	});
+	function supportsObject(object, type) {
+	  return true;
+	}
+
+	module.exports = {
+	  rep: Obj,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 13 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __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.
+	 */
+	let PropRep = React.createFactory(React.createClass({
+	  displayName: "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,
+	    // Delimiter character used to separate individual properties.
+	    delim: 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]))
+	  },
+
+	  render: function () {
+	    const Grip = __webpack_require__(14);
+	    let Rep = React.createFactory(__webpack_require__(3));
+
+	    let key;
+	    // The key can be a simple string, for plain objects,
+	    // or another object for maps and weakmaps.
+	    if (typeof this.props.name === "string") {
+	      key = span({ "className": "nodeName" }, this.props.name);
+	    } else {
+	      key = Rep({
+	        object: this.props.name,
+	        mode: this.props.mode || MODE.TINY,
+	        defaultRep: Grip,
+	        objectLink: this.props.objectLink
+	      });
+	    }
+
+	    return span({}, key, span({
+	      "className": "objectEqual"
+	    }, this.props.equal), Rep(this.props), span({
+	      "className": "objectComma"
+	    }, this.props.delim));
+	  }
+	}));
+
+	module.exports = PropRep;
+
+/***/ },
+/* 14 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+	// Dependencies
+	const { isGrip } = __webpack_require__(4);
+	const Caption = React.createFactory(__webpack_require__(11));
+	const PropRep = React.createFactory(__webpack_require__(13));
+	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.
+	 */
+	const GripRep = React.createClass({
+	  displayName: "Grip",
+
+	  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
+	  },
+
+	  getTitle: function (object) {
+	    let title = this.props.title || object.class || "Object";
+	    if (this.props.objectLink) {
+	      return this.props.objectLink({
+	        object: object
+	      }, title);
+	    }
+	    return title;
+	  },
+
+	  safePropIterator: function (object, max) {
+	    max = typeof max === "undefined" ? 3 : max;
+	    try {
+	      return this.propIterator(object, max);
+	    } catch (err) {
+	      console.error(err);
+	    }
+	    return [];
+	  },
+
+	  propIterator: function (object, max) {
+	    if (object.preview && Object.keys(object.preview).includes("wrappedValue")) {
+	      const Rep = React.createFactory(__webpack_require__(3));
+
+	      return [Rep({
+	        object: object.preview.wrappedValue,
+	        mode: this.props.mode || MODE.TINY,
+	        defaultRep: Grip
+	      })];
+	    }
+
+	    // Property filter. Show only interesting properties to the user.
+	    let isInterestingProp = this.props.isInterestingProp || ((type, value) => {
+	      return type == "boolean" || type == "number" || type == "string" && value.length != 0;
+	    });
+
+	    let properties = object.preview ? object.preview.ownProperties : {};
+	    let propertiesLength = object.preview && object.preview.ownPropertiesLength ? object.preview.ownPropertiesLength : object.ownPropertyLength;
+
+	    if (object.preview && object.preview.safeGetterValues) {
+	      properties = Object.assign({}, properties, object.preview.safeGetterValues);
+	      propertiesLength += Object.keys(object.preview.safeGetterValues).length;
+	    }
+
+	    let indexes = this.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(this.getPropIndexes(properties, max - indexes.length, (t, value, name) => {
+	        return !isInterestingProp(t, value, name);
+	      }));
+	    }
+
+	    const truncate = Object.keys(properties).length > max;
+	    let props = this.getProps(properties, indexes, truncate);
+	    if (truncate) {
+	      // There are some undisplayed props. Then display "more...".
+	      let objectLink = this.props.objectLink || span;
+
+	      props.push(Caption({
+	        object: objectLink({
+	          object: object
+	        }, `${ object.ownPropertyLength - max } more…`)
+	      }));
+	    }
+
+	    return props;
+	  },
+
+	  /**
+	   * Get props ordered by index.
+	   *
+	   * @param {Object} properties Props object.
+	   * @param {Array} indexes Indexes of props.
+	   * @param {Boolean} truncate true if the grip will be truncated.
+	   * @return {Array} Props.
+	   */
+	  getProps: function (properties, indexes, truncate) {
+	    let props = [];
+
+	    // Make indexes ordered by ascending.
+	    indexes.sort(function (a, b) {
+	      return a - b;
+	    });
+
+	    indexes.forEach(i => {
+	      let name = Object.keys(properties)[i];
+	      let value = this.getPropValue(properties[name]);
+
+	      props.push(PropRep(Object.assign({}, this.props, {
+	        mode: MODE.TINY,
+	        name: name,
+	        object: value,
+	        equal: ": ",
+	        delim: i !== indexes.length - 1 || truncate ? ", " : "",
+	        defaultRep: Grip
+	      })));
+	    });
+
+	    return props;
+	  },
+
+	  /**
+	   * 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.
+	   */
+	  getPropIndexes: function (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 = this.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.
+	   */
+	  getPropValue: function (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;
+	  },
+
+	  render: function () {
+	    let object = this.props.object;
+	    let props = this.safePropIterator(object, this.props.mode === MODE.LONG ? 10 : 3);
+
+	    let objectLink = this.props.objectLink || span;
+	    if (this.props.mode === MODE.TINY) {
+	      return span({ className: "objectBox objectBox-object" }, this.getTitle(object), objectLink({
+	        className: "objectLeftBrace",
+	        object: object
+	      }, ""));
+	    }
+
+	    return span({ className: "objectBox objectBox-object" }, this.getTitle(object), objectLink({
+	      className: "objectLeftBrace",
+	      object: object
+	    }, " { "), ...props, objectLink({
+	      className: "objectRightBrace",
+	      object: object
+	    }, " }"));
+	  }
+	});
+
+	// Registration
+	function supportsObject(object, type) {
+	  if (!isGrip(object)) {
+	    return false;
+	  }
+	  return object.preview && object.preview.ownProperties;
+	}
+
+	let Grip = {
+	  rep: GripRep,
+	  supportsObject: supportsObject
+	};
+
+	module.exports = Grip;
+
+/***/ },
+/* 15 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+
+	// Shortcuts
+	const { span } = React.DOM;
+
+	/**
+	 * Renders a symbol.
+	 */
+	const SymbolRep = React.createClass({
+	  displayName: "SymbolRep",
+
+	  propTypes: {
+	    object: React.PropTypes.object.isRequired
+	  },
+
+	  render: function () {
+	    let { object } = this.props;
+	    let { name } = object;
+
+	    return span({ className: "objectBox objectBox-symbol" }, `Symbol(${ name || "" })`);
+	  }
+	});
+
+	function supportsObject(object, type) {
+	  return type == "symbol";
+	}
+
+	module.exports = {
+	  rep: SymbolRep,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 16 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+
+	// Shortcuts
+	const { span } = React.DOM;
+
+	/**
+	 * Renders a Infinity object
+	 */
+	const InfinityRep = React.createClass({
+	  displayName: "Infinity",
+
+	  render: function () {
+	    return span({ className: "objectBox objectBox-number" }, this.props.object.type);
+	  }
+	});
+
+	function supportsObject(object, type) {
+	  return type == "Infinity" || type == "-Infinity";
+	}
+
+	module.exports = {
+	  rep: InfinityRep,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 17 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+
+	// Shortcuts
+	const { span } = React.DOM;
+
+	/**
+	 * Renders a NaN object
+	 */
+	const NaNRep = React.createClass({
+	  displayName: "NaN",
+
+	  render: function () {
+	    return span({ className: "objectBox objectBox-nan" }, "NaN");
+	  }
+	});
+
+	function supportsObject(object, type) {
+	  return type == "NaN";
+	}
+
+	module.exports = {
+	  rep: NaNRep,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 18 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+
+	// Reps
+	const { isGrip } = __webpack_require__(4);
+	const StringRep = React.createFactory(__webpack_require__(7).rep);
+
+	// Shortcuts
+	const { span } = React.DOM;
+
+	/**
+	 * Renders DOM attribute
+	 */
+	let Attribute = React.createClass({
+	  displayName: "Attr",
+
+	  propTypes: {
+	    object: React.PropTypes.object.isRequired
+	  },
+
+	  getTitle: function (grip) {
+	    return grip.preview.nodeName;
+	  },
+
+	  render: function () {
+	    let object = this.props.object;
+	    let value = object.preview.value;
+	    let objectLink = this.props.objectLink || span;
+
+	    return objectLink({ className: "objectLink-Attr", object }, span({}, span({ className: "attrTitle" }, this.getTitle(object)), span({ className: "attrEqual" }, "="), StringRep({ object: value })));
+	  }
+	});
+
+	// Registration
+
+	function supportsObject(grip, type) {
+	  if (!isGrip(grip)) {
+	    return false;
+	  }
+
+	  return type == "Attr" && grip.preview;
+	}
+
+	module.exports = {
+	  rep: Attribute,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 19 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+
+	// Reps
+	const { isGrip } = __webpack_require__(4);
+
+	// Shortcuts
+	const { span } = React.DOM;
+
+	/**
+	 * Used to render JS built-in Date() object.
+	 */
+	let DateTime = React.createClass({
+	  displayName: "Date",
+
+	  propTypes: {
+	    object: React.PropTypes.object.isRequired
+	  },
+
+	  getTitle: function (grip) {
+	    if (this.props.objectLink) {
+	      return this.props.objectLink({
+	        object: grip
+	      }, grip.class + " ");
+	    }
+	    return "";
+	  },
+
+	  render: function () {
+	    let grip = this.props.object;
+	    let date;
+	    try {
+	      date = span({ className: "objectBox" }, this.getTitle(grip), span({ className: "Date" }, new Date(grip.preview.timestamp).toISOString()));
+	    } catch (e) {
+	      date = span({ className: "objectBox" }, "Invalid Date");
+	    }
+	    return date;
+	  }
+	});
+
+	// Registration
+
+	function supportsObject(grip, type) {
+	  if (!isGrip(grip)) {
+	    return false;
+	  }
+
+	  return type == "Date" && grip.preview;
+	}
+
+	module.exports = {
+	  rep: DateTime,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 20 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+
+	// Reps
+	const { isGrip, getURLDisplayString } = __webpack_require__(4);
+
+	// Shortcuts
+	const { span } = React.DOM;
+
+	/**
+	 * Renders DOM document object.
+	 */
+	let Document = React.createClass({
+	  displayName: "Document",
+
+	  propTypes: {
+	    object: React.PropTypes.object.isRequired
+	  },
+
+	  getLocation: function (grip) {
+	    let location = grip.preview.location;
+	    return location ? getURLDisplayString(location) : "";
+	  },
+
+	  getTitle: function (grip) {
+	    if (this.props.objectLink) {
+	      return span({ className: "objectBox" }, this.props.objectLink({
+	        object: grip
+	      }, grip.class + " "));
+	    }
+	    return "";
+	  },
+
+	  getTooltip: function (doc) {
+	    return doc.location.href;
+	  },
+
+	  render: function () {
+	    let grip = this.props.object;
+
+	    return span({ className: "objectBox objectBox-object" }, this.getTitle(grip), span({ className: "objectPropValue" }, this.getLocation(grip)));
+	  }
+	});
+
+	// Registration
+
+	function supportsObject(object, type) {
+	  if (!isGrip(object)) {
+	    return false;
+	  }
+
+	  return object.preview && type == "HTMLDocument";
+	}
+
+	module.exports = {
+	  rep: Document,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 21 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+
+	// Reps
+	const { isGrip } = __webpack_require__(4);
+	const rep = React.createFactory(__webpack_require__(14).rep);
+
+	/**
+	 * Renders DOM event objects.
+	 */
+	let Event = React.createClass({
+	  displayName: "event",
+
+	  propTypes: {
+	    object: React.PropTypes.object.isRequired
+	  },
+
+	  getTitle: function (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;
+	  },
+
+	  render: function () {
+	    // Use `Object.assign` to keep `this.props` without changes because:
+	    // 1. JSON.stringify/JSON.parse is slow.
+	    // 2. Immutable.js is planned for the future.
+	    let props = Object.assign({
+	      title: this.getTitle(this.props)
+	    }, this.props);
+	    props.object = Object.assign({}, this.props.object);
+	    props.object.preview = Object.assign({}, this.props.object.preview);
+
+	    props.object.preview.ownProperties = {};
+	    if (props.object.preview.target) {
+	      Object.assign(props.object.preview.ownProperties, {
+	        target: props.object.preview.target
+	      });
+	    }
+	    Object.assign(props.object.preview.ownProperties, props.object.preview.properties);
+
+	    delete props.object.preview.properties;
+	    props.object.ownPropertyLength = Object.keys(props.object.preview.ownProperties).length;
+
+	    switch (props.object.class) {
+	      case "MouseEvent":
+	        props.isInterestingProp = (type, value, name) => {
+	          return ["target", "clientX", "clientY", "layerX", "layerY"].includes(name);
+	        };
+	        break;
+	      case "KeyboardEvent":
+	        props.isInterestingProp = (type, value, name) => {
+	          return ["target", "key", "charCode", "keyCode"].includes(name);
+	        };
+	        break;
+	      case "MessageEvent":
+	        props.isInterestingProp = (type, value, name) => {
+	          return ["target", "isTrusted", "data"].includes(name);
+	        };
+	        break;
+	      default:
+	        props.isInterestingProp = (type, value, name) => {
+	          // We want to show the properties in the order they are declared.
+	          return Object.keys(props.object.preview.ownProperties).includes(name);
+	        };
+	    }
+
+	    return rep(props);
+	  }
+	});
+
+	// Registration
+	function supportsObject(grip, type) {
+	  if (!isGrip(grip)) {
+	    return false;
+	  }
+
+	  return grip.preview && grip.preview.kind == "DOMEvent";
+	}
+
+	module.exports = {
+	  rep: Event,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 22 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+
+	// Reps
+	const { isGrip, cropString } = __webpack_require__(4);
+
+	// Shortcuts
+	const { span } = React.DOM;
+
+	/**
+	 * This component represents a template for Function objects.
+	 */
+	let Func = React.createClass({
+	  displayName: "Func",
+
+	  propTypes: {
+	    object: React.PropTypes.object.isRequired
+	  },
+
+	  getTitle: function (grip) {
+	    if (this.props.objectLink) {
+	      return this.props.objectLink({
+	        object: grip
+	      }, "function ");
+	    }
+	    return "";
+	  },
+
+	  summarizeFunction: function (grip) {
+	    let name = grip.userDisplayName || grip.displayName || grip.name || "function";
+	    return cropString(name + "()", 100);
+	  },
+
+	  render: function () {
+	    let grip = this.props.object;
+
+	    return (
+	      // Set dir="ltr" to prevent function parentheses from
+	      // appearing in the wrong direction
+	      span({ dir: "ltr", className: "objectBox objectBox-function" }, this.getTitle(grip), this.summarizeFunction(grip))
+	    );
+	  }
+	});
+
+	// Registration
+
+	function supportsObject(grip, type) {
+	  if (!isGrip(grip)) {
+	    return type == "function";
+	  }
+
+	  return type == "Function";
+	}
+
+	module.exports = {
+	  rep: Func,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 23 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+	// Dependencies
+	const { isGrip } = __webpack_require__(4);
+	const PropRep = React.createFactory(__webpack_require__(13));
+	const { MODE } = __webpack_require__(2);
+	// Shortcuts
+	const { span } = React.DOM;
+
+	/**
+	 * Renders a DOM Promise object.
+	 */
+	const PromiseRep = React.createClass({
+	  displayName: "Promise",
+
+	  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]))
+	  },
+
+	  getTitle: function (object) {
+	    const title = object.class;
+	    if (this.props.objectLink) {
+	      return this.props.objectLink({
+	        object: object
+	      }, title);
+	    }
+	    return title;
+	  },
+
+	  getProps: function (promiseState) {
+	    const keys = ["state"];
+	    if (Object.keys(promiseState).includes("value")) {
+	      keys.push("value");
+	    }
+
+	    return keys.map((key, i) => {
+	      return PropRep(Object.assign({}, this.props, {
+	        mode: MODE.TINY,
+	        name: `<${ key }>`,
+	        object: promiseState[key],
+	        equal: ": ",
+	        delim: i < keys.length - 1 ? ", " : ""
+	      }));
+	    });
+	  },
+
+	  render: function () {
+	    const object = this.props.object;
+	    const { promiseState } = object;
+	    let objectLink = this.props.objectLink || span;
+
+	    if (this.props.mode === MODE.TINY) {
+	      let Rep = React.createFactory(__webpack_require__(3));
+
+	      return span({ className: "objectBox objectBox-object" }, this.getTitle(object), objectLink({
+	        className: "objectLeftBrace",
+	        object: object
+	      }, " { "), Rep({ object: promiseState.state }), objectLink({
+	        className: "objectRightBrace",
+	        object: object
+	      }, " }"));
+	    }
+
+	    const props = this.getProps(promiseState);
+	    return span({ className: "objectBox objectBox-object" }, this.getTitle(object), objectLink({
+	      className: "objectLeftBrace",
+	      object: object
+	    }, " { "), ...props, objectLink({
+	      className: "objectRightBrace",
+	      object: object
+	    }, " }"));
+	  }
+	});
+
+	// Registration
+	function supportsObject(object, type) {
+	  if (!isGrip(object)) {
+	    return false;
+	  }
+	  return type === "Promise";
+	}
+
+	module.exports = {
+	  rep: PromiseRep,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 24 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+
+	// Reps
+	const { isGrip } = __webpack_require__(4);
+
+	// Shortcuts
+	const { span } = React.DOM;
+
+	/**
+	 * Renders a grip object with regular expression.
+	 */
+	let RegExp = React.createClass({
+	  displayName: "regexp",
+
+	  propTypes: {
+	    object: React.PropTypes.object.isRequired
+	  },
+
+	  getSource: function (grip) {
+	    return grip.displayString;
+	  },
+
+	  render: function () {
+	    let grip = this.props.object;
+	    let objectLink = this.props.objectLink || span;
+
+	    return span({ className: "objectBox objectBox-regexp" }, objectLink({
+	      object: grip,
+	      className: "regexpSource"
+	    }, this.getSource(grip)));
+	  }
+	});
+
+	// Registration
+
+	function supportsObject(object, type) {
+	  if (!isGrip(object)) {
+	    return false;
+	  }
+
+	  return type == "RegExp";
+	}
+
+	module.exports = {
+	  rep: RegExp,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 25 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+
+	// Reps
+	const { isGrip, getURLDisplayString } = __webpack_require__(4);
+
+	// Shortcuts
+	const DOM = React.DOM;
+
+	/**
+	 * Renders a grip representing CSSStyleSheet
+	 */
+	let StyleSheet = React.createClass({
+	  displayName: "object",
+
+	  propTypes: {
+	    object: React.PropTypes.object.isRequired
+	  },
+
+	  getTitle: function (grip) {
+	    let title = "StyleSheet ";
+	    if (this.props.objectLink) {
+	      return DOM.span({ className: "objectBox" }, this.props.objectLink({
+	        object: grip
+	      }, title));
+	    }
+	    return title;
+	  },
+
+	  getLocation: function (grip) {
+	    // Embedded stylesheets don't have URL and so, no preview.
+	    let url = grip.preview ? grip.preview.url : "";
+	    return url ? getURLDisplayString(url) : "";
+	  },
+
+	  render: function () {
+	    let grip = this.props.object;
+
+	    return DOM.span({ className: "objectBox objectBox-object" }, this.getTitle(grip), DOM.span({ className: "objectPropValue" }, this.getLocation(grip)));
+	  }
+	});
+
+	// Registration
+
+	function supportsObject(object, type) {
+	  if (!isGrip(object)) {
+	    return false;
+	  }
+
+	  return type == "CSSStyleSheet";
+	}
+
+	module.exports = {
+	  rep: StyleSheet,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 26 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+	const { isGrip, cropString, cropMultipleLines } = __webpack_require__(4);
+	const { MODE } = __webpack_require__(2);
+	const nodeConstants = __webpack_require__(27);
+
+	// Shortcuts
+	const { span } = React.DOM;
+
+	/**
+	 * Renders DOM comment node.
+	 */
+	const CommentNode = React.createClass({
+	  displayName: "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]))
+	  },
+
+	  render: function () {
+	    let {
+	      object,
+	      mode = MODE.SHORT
+	    } = this.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" }, `<!-- ${ textContent } -->`);
+	  }
+	});
+
+	// Registration
+	function supportsObject(object, type) {
+	  if (!isGrip(object)) {
+	    return false;
+	  }
+	  return object.preview && object.preview.nodeType === nodeConstants.COMMENT_NODE;
+	}
+
+	module.exports = {
+	  rep: CommentNode,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 27 */
+/***/ function(module, exports) {
+
+	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
+	};
+
+/***/ },
+/* 28 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+
+	// Utils
+	const { isGrip } = __webpack_require__(4);
+	const { MODE } = __webpack_require__(2);
+	const nodeConstants = __webpack_require__(27);
+
+	// Shortcuts
+	const { span } = React.DOM;
+
+	/**
+	 * Renders DOM element node.
+	 */
+	const ElementNode = React.createClass({
+	  displayName: "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]))
+	  },
+
+	  getElements: function (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 attributeElements = Object.keys(attributes).sort(function getIdAndClassFirst(a1, a2) {
+	      if ([a1, a2].includes("id")) {
+	        return 3 * (a1 === "id" ? -1 : 1);
+	      }
+	      if ([a1, a2].includes("class")) {
+	        return 2 * (a1 === "class" ? -1 : 1);
+	      }
+
+	      // `id` and `class` excepted,
+	      // we want to keep the same order that in `attributes`.
+	      return 0;
+	    }).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, ">"];
+	  },
+
+	  render: function () {
+	    let {
+	      object,
+	      mode,
+	      onDOMNodeMouseOver,
+	      onDOMNodeMouseOut
+	    } = this.props;
+	    let elements = this.getElements(object, mode);
+	    let objectLink = this.props.objectLink || span;
+
+	    let baseConfig = { className: "objectBox objectBox-node" };
+	    if (onDOMNodeMouseOver) {
+	      Object.assign(baseConfig, {
+	        onMouseOver: _ => onDOMNodeMouseOver(object)
+	      });
+	    }
+
+	    if (onDOMNodeMouseOut) {
+	      Object.assign(baseConfig, {
+	        onMouseOut: onDOMNodeMouseOut
+	      });
+	    }
+
+	    return objectLink({ object }, span(baseConfig, ...elements));
+	  }
+	});
+
+	// Registration
+	function supportsObject(object, type) {
+	  if (!isGrip(object)) {
+	    return false;
+	  }
+	  return object.preview && object.preview.nodeType === nodeConstants.ELEMENT_NODE;
+	}
+
+	module.exports = {
+	  rep: ElementNode,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 29 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+
+	// Reps
+	const { isGrip, cropString } = __webpack_require__(4);
+	const { MODE } = __webpack_require__(2);
+
+	// Shortcuts
+	const DOM = React.DOM;
+
+	/**
+	 * Renders DOM #text node.
+	 */
+	let TextNode = React.createClass({
+	  displayName: "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]))
+	  },
+
+	  getTextContent: function (grip) {
+	    return cropString(grip.preview.textContent);
+	  },
+
+	  getTitle: function (grip) {
+	    const title = "#text";
+	    if (this.props.objectLink) {
+	      return this.props.objectLink({
+	        object: grip
+	      }, title);
+	    }
+	    return title;
+	  },
+
+	  render: function () {
+	    let {
+	      object: grip,
+	      mode = MODE.SHORT
+	    } = this.props;
+
+	    let baseConfig = { className: "objectBox objectBox-textNode" };
+	    if (this.props.onDOMNodeMouseOver) {
+	      Object.assign(baseConfig, {
+	        onMouseOver: _ => this.props.onDOMNodeMouseOver(grip)
+	      });
+	    }
+
+	    if (this.props.onDOMNodeMouseOut) {
+	      Object.assign(baseConfig, {
+	        onMouseOut: this.props.onDOMNodeMouseOut
+	      });
+	    }
+
+	    if (mode === MODE.TINY) {
+	      return DOM.span(baseConfig, this.getTitle(grip));
+	    }
+
+	    return DOM.span(baseConfig, this.getTitle(grip), DOM.span({ className: "nodeValue" }, " ", `"${ this.getTextContent(grip) }"`));
+	  }
+	});
+
+	// Registration
+
+	function supportsObject(grip, type) {
+	  if (!isGrip(grip)) {
+	    return false;
+	  }
+
+	  return grip.preview && grip.class == "Text";
+	}
+
+	module.exports = {
+	  rep: TextNode,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 30 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+	// Utils
+	const { isGrip } = __webpack_require__(4);
+	const { MODE } = __webpack_require__(2);
+	// Shortcuts
+	const { span } = React.DOM;
+
+	/**
+	 * Renders Error objects.
+	 */
+	const ErrorRep = React.createClass({
+	  displayName: "Error",
+
+	  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]))
+	  },
+
+	  render: function () {
+	    let object = this.props.object;
+	    let preview = object.preview;
+	    let name = preview && preview.name ? preview.name : "Error";
+
+	    let content = this.props.mode === MODE.TINY ? name : `${ name }: ${ preview.message }`;
+
+	    if (preview.stack && this.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 }`;
+	    }
+
+	    let objectLink = this.props.objectLink || span;
+	    return objectLink({ object, className: "objectBox-stackTrace" }, span({}, content));
+	  }
+	});
+
+	// Registration
+	function supportsObject(object, type) {
+	  if (!isGrip(object)) {
+	    return false;
+	  }
+	  return object.preview && type === "Error";
+	}
+
+	module.exports = {
+	  rep: ErrorRep,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 31 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+	const { MODE } = __webpack_require__(2);
+
+	// Reps
+	const { isGrip, getURLDisplayString } = __webpack_require__(4);
+
+	// Shortcuts
+	const DOM = React.DOM;
+
+	/**
+	 * Renders a grip representing a window.
+	 */
+	let Window = React.createClass({
+	  displayName: "Window",
+
+	  propTypes: {
+	    object: React.PropTypes.object.isRequired,
+	    mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key]))
+	  },
+
+	  getTitle: function (grip) {
+	    if (this.props.objectLink) {
+	      return DOM.span({ className: "objectBox" }, this.props.objectLink({
+	        object: grip
+	      }, grip.class + " "));
+	    }
+	    return "";
+	  },
+
+	  getLocation: function (grip) {
+	    return getURLDisplayString(grip.preview.url);
+	  },
+
+	  getDisplayValue: function (grip) {
+	    if (this.props.mode === MODE.TINY) {
+	      return grip.isGlobal ? "Global" : "Window";
+	    }
+
+	    return this.getLocation(grip);
+	  },
+
+	  render: function () {
+	    let grip = this.props.object;
+
+	    return DOM.span({ className: "objectBox objectBox-Window" }, this.getTitle(grip), DOM.span({ className: "objectPropValue" }, this.getDisplayValue(grip)));
+	  }
+	});
+
+	// Registration
+
+	function supportsObject(object, type) {
+	  if (!isGrip(object)) {
+	    return false;
+	  }
+
+	  return object.preview && type == "Window";
+	}
+
+	module.exports = {
+	  rep: Window,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 32 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+
+	// Reps
+	const { isGrip } = __webpack_require__(4);
+
+	// Shortcuts
+	const { span } = React.DOM;
+
+	/**
+	 * Renders a grip object with textual data.
+	 */
+	let ObjectWithText = React.createClass({
+	  displayName: "ObjectWithText",
+
+	  propTypes: {
+	    object: React.PropTypes.object.isRequired
+	  },
+
+	  getTitle: function (grip) {
+	    if (this.props.objectLink) {
+	      return span({ className: "objectBox" }, this.props.objectLink({
+	        object: grip
+	      }, this.getType(grip) + " "));
+	    }
+	    return "";
+	  },
+
+	  getType: function (grip) {
+	    return grip.class;
+	  },
+
+	  getDescription: function (grip) {
+	    return "\"" + grip.preview.text + "\"";
+	  },
+
+	  render: function () {
+	    let grip = this.props.object;
+	    return span({ className: "objectBox objectBox-" + this.getType(grip) }, this.getTitle(grip), span({ className: "objectPropValue" }, this.getDescription(grip)));
+	  }
+	});
+
+	// Registration
+
+	function supportsObject(grip, type) {
+	  if (!isGrip(grip)) {
+	    return false;
+	  }
+
+	  return grip.preview && grip.preview.kind == "ObjectWithText";
+	}
+
+	module.exports = {
+	  rep: ObjectWithText,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 33 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+
+	// Reps
+	const { isGrip, getURLDisplayString } = __webpack_require__(4);
+
+	// Shortcuts
+	const { span } = React.DOM;
+
+	/**
+	 * Renders a grip object with URL data.
+	 */
+	let ObjectWithURL = React.createClass({
+	  displayName: "ObjectWithURL",
+
+	  propTypes: {
+	    object: React.PropTypes.object.isRequired
+	  },
+
+	  getTitle: function (grip) {
+	    if (this.props.objectLink) {
+	      return span({ className: "objectBox" }, this.props.objectLink({
+	        object: grip
+	      }, this.getType(grip) + " "));
+	    }
+	    return "";
+	  },
+
+	  getType: function (grip) {
+	    return grip.class;
+	  },
+
+	  getDescription: function (grip) {
+	    return getURLDisplayString(grip.preview.url);
+	  },
+
+	  render: function () {
+	    let grip = this.props.object;
+	    return span({ className: "objectBox objectBox-" + this.getType(grip) }, this.getTitle(grip), span({ className: "objectPropValue" }, this.getDescription(grip)));
+	  }
+	});
+
+	// Registration
+
+	function supportsObject(grip, type) {
+	  if (!isGrip(grip)) {
+	    return false;
+	  }
+
+	  return grip.preview && grip.preview.kind == "ObjectWithURL";
+	}
+
+	module.exports = {
+	  rep: ObjectWithURL,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 34 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+	const { isGrip } = __webpack_require__(4);
+	const Caption = React.createFactory(__webpack_require__(11));
+	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.
+	 */
+	let GripArray = React.createClass({
+	  displayName: "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
+	  },
+
+	  getLength: function (grip) {
+	    if (!grip.preview) {
+	      return 0;
+	    }
+
+	    return grip.preview.length || grip.preview.childNodesLength || 0;
+	  },
+
+	  getTitle: function (object, context) {
+	    let objectLink = this.props.objectLink || span;
+	    if (this.props.mode !== MODE.TINY) {
+	      return objectLink({
+	        object: object
+	      }, object.class + " ");
+	    }
+	    return "";
+	  },
+
+	  getPreviewItems: function (grip) {
+	    if (!grip.preview) {
+	      return null;
+	    }
+
+	    return grip.preview.items || grip.preview.childNodes || null;
+	  },
+
+	  arrayIterator: function (grip, max) {
+	    let items = [];
+	    const gripLength = this.getLength(grip);
+
+	    if (!gripLength) {
+	      return items;
+	    }
+
+	    const previewItems = this.getPreviewItems(grip);
+	    if (!previewItems) {
+	      return items;
+	    }
+
+	    let delim;
+	    // number of grip preview items is limited to 10, but we may have more
+	    // items in grip-array.
+	    let delimMax = gripLength > previewItems.length ? previewItems.length : previewItems.length - 1;
+	    let provider = this.props.provider;
+
+	    for (let i = 0; i < previewItems.length && i < max; i++) {
+	      try {
+	        let itemGrip = previewItems[i];
+	        let value = provider ? provider.getValue(itemGrip) : itemGrip;
+
+	        delim = i == delimMax ? "" : ", ";
+
+	        items.push(GripArrayItem(Object.assign({}, this.props, {
+	          object: value,
+	          delim: delim
+	        })));
+	      } catch (exc) {
+	        items.push(GripArrayItem(Object.assign({}, this.props, {
+	          object: exc,
+	          delim: delim
+	        })));
+	      }
+	    }
+	    if (previewItems.length > max || gripLength > previewItems.length) {
+	      let objectLink = this.props.objectLink || span;
+	      let leftItemNum = gripLength - max > 0 ? gripLength - max : gripLength - previewItems.length;
+	      items.push(Caption({
+	        object: objectLink({
+	          object: this.props.object
+	        }, leftItemNum + " more…")
+	      }));
+	    }
+
+	    return items;
+	  },
+
+	  render: function () {
+	    let {
+	      object,
+	      mode = MODE.SHORT
+	    } = this.props;
+
+	    let items;
+	    let brackets;
+	    let needSpace = function (space) {
+	      return space ? { left: "[ ", right: " ]" } : { left: "[", right: "]" };
+	    };
+
+	    if (mode === MODE.TINY) {
+	      let objectLength = this.getLength(object);
+	      let isEmpty = objectLength === 0;
+	      items = [span({ className: "length" }, isEmpty ? "" : objectLength)];
+	      brackets = needSpace(false);
+	    } else {
+	      let max = mode === MODE.SHORT ? 3 : 10;
+	      items = this.arrayIterator(object, max);
+	      brackets = needSpace(items.length > 0);
+	    }
+
+	    let objectLink = this.props.objectLink || span;
+	    let title = this.getTitle(object);
+
+	    return span({
+	      className: "objectBox objectBox-array" }, title, objectLink({
+	      className: "arrayLeftBracket",
+	      object: object
+	    }, brackets.left), ...items, objectLink({
+	      className: "arrayRightBracket",
+	      object: object
+	    }, brackets.right), span({
+	      className: "arrayProperties",
+	      role: "group" }));
+	  }
+	});
+
+	/**
+	 * Renders array item. Individual values are separated by
+	 * a delimiter (a comma by default).
+	 */
+	let GripArrayItem = React.createFactory(React.createClass({
+	  displayName: "GripArrayItem",
+
+	  propTypes: {
+	    delim: React.PropTypes.string
+	  },
+
+	  render: function () {
+	    let Rep = React.createFactory(__webpack_require__(3));
+
+	    return span({}, Rep(Object.assign({}, this.props, {
+	      mode: MODE.TINY
+	    })), this.props.delim);
+	  }
+	}));
+
+	function supportsObject(grip, type) {
+	  if (!isGrip(grip)) {
+	    return false;
+	  }
+
+	  return grip.preview && (grip.preview.kind == "ArrayLike" || type === "DocumentFragment");
+	}
+
+	module.exports = {
+	  rep: GripArray,
+	  supportsObject: supportsObject
+	};
+
+/***/ },
+/* 35 */
+/***/ function(module, exports, __webpack_require__) {
+
+	const React = __webpack_require__(1);
+	const { isGrip } = __webpack_require__(4);
+	const Caption = React.createFactory(__webpack_require__(11));
+	const PropRep = React.createFactory(__webpack_require__(13));
+	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.
+	 */
+	const GripMap = React.createClass({
+	  displayName: "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]))
+	  },
+
+	  getTitle: function (object) {
+	    let title = object && object.class ? object.class : "Map";
+	    if (this.props.objectLink) {
+	      return this.props.objectLink({
+	        object: object
+	      }, title);
+	    }
+	    return title;
+	  },
+
+	  safeEntriesIterator: function (object, max) {
+	    max = typeof max === "undefined" ? 3 : max;
+	    try {
+	      return this.entriesIterator(object, max);
+	    } catch (err) {
+	      console.error(err);
+	    }
+	    return [];
+	  },
+
+	  entriesIterator: function (object, max) {
+	    // Entry filter. Show only interesting entries to the user.
+	    let isInterestingEntry = this.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 = this.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(this.getEntriesIndexes(mapEntries, max - indexes.length, (t, value, name) => {
+	        return !isInterestingEntry(t, value, name);
+	      }));
+	    }
+
+	    let entries = this.getEntries(mapEntries, indexes);
+	    if (entries.length < mapEntries.length) {
+	      // There are some undisplayed entries. Then display "more…".
+	      let objectLink = this.props.objectLink || span;
+
+	      entries.push(Caption({
+	        key: "more",
+	        object: objectLink({
+	          object: object
+	        }, `${ mapEntries.length - max } more…`)
+	      }));
+	    }
+
+	    return entries;
+	  },
+
+	  /**
+	   * Get entries ordered by index.
+	   *
+	   * @param {Array} entries Entries array.
+	   * @param {Array} indexes Indexes of entries.
+	   * @return {Array} Array of PropRep.
+	   */
+	  getEntries: function (entries, indexes) {
+	    // 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({
+	        // key,
+	        name: key,
+	        equal: ": ",
+	        object: value,
+	        // Do not add a trailing comma on the last entry
+	        // if there won't be a "more..." item.
+	        delim: i < indexes.length - 1 || indexes.length < entries.length ? ", " : "",
+	        mode: MODE.TINY,
+	        objectLink: this.props.objectLink
+	      });
+	    });
+	  },
+
+	  /**
+	   * 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.
+	   */
+	  getEntriesIndexes: function (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;
+	    }, []);
+	  },
+
+	  render: function () {
+	    let object = this.props.object;
+	    let props = this.safeEntriesIterator(object, this.props.mode === MODE.LONG ? 10 : 3);
+
+	    let objectLink = this.props.objectLink || span;
+	    if (this.props.mode === MODE.TINY) {
+	      return span({ className: "objectBox objectBox-object" }, this.getTitle(object), objectLink({
+	        className: "objectLeftBrace",
+	        object: object
+	      }, ""));
+	    }
+
+	    return span({ className: "objectBox objectBox-object" }, this.getTitle(object), objectLink({
+	      className: "objectLeftBrace",
+	      object: object
+	    }, " { "), props, objectLink({
+	      className: "objectRightBrace",
+	      object: object
+	    }, " }"));
+	  }
+	});
+
+	function supportsObject(grip, type) {
+	  if (!isGrip(grip)) {
+	    return false;
+	  }
+	  return grip.preview && grip.preview.kind == "MapLike";
+	}
+
+	module.exports = {
+	  rep: GripMap,
+	  supportsObject: supportsObject
+	};
+
+/***/ }
+/******/ ])
+});
+;
+//# sourceMappingURL=reps.js.map
\ No newline at end of file
--- a/devtools/client/webconsole/net/components/net-info-body.js
+++ b/devtools/client/webconsole/net/components/net-info-body.js
@@ -1,15 +1,15 @@
 /* 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/. */
 "use strict";
 
 const React = require("devtools/client/shared/vendor/react");
-const { createFactories } = require("devtools/client/shared/components/reps/rep-utils");
+const { createFactories } = require("devtools/client/shared/components/reps/load-reps");
 const { Tabs, TabPanel } = createFactories(require("devtools/client/shared/components/tabs/tabs"));
 
 // Network
 const HeadersTab = React.createFactory(require("./headers-tab"));
 const ResponseTab = React.createFactory(require("./response-tab"));
 const ParamsTab = React.createFactory(require("./params-tab"));
 const CookiesTab = React.createFactory(require("./cookies-tab"));
 const PostTab = React.createFactory(require("./post-tab"));
--- a/devtools/client/webconsole/net/components/post-tab.js
+++ b/devtools/client/webconsole/net/components/post-tab.js
@@ -1,20 +1,19 @@
 /* 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/. */
 "use strict";
 
 const React = require("devtools/client/shared/vendor/react");
 
-// Reps
-const { createFactories, parseURLEncodedText } = require("devtools/client/shared/components/reps/rep-utils");
 const TreeView = React.createFactory(require("devtools/client/shared/components/tree/tree-view"));
-const { Rep } = createFactories(require("devtools/client/shared/components/reps/rep"));
-const { MODE } = require("devtools/client/shared/components/reps/constants");
+
+const { REPS, MODE, parseURLEncodedText } = require("devtools/client/shared/components/reps/load-reps");
+const Rep = React.createFactory(REPS.Rep);
 
 // Network
 const NetInfoParams = React.createFactory(require("./net-info-params"));
 const NetInfoGroupList = React.createFactory(require("./net-info-group-list"));
 const Spinner = React.createFactory(require("./spinner"));
 const SizeLimit = React.createFactory(require("./size-limit"));
 const NetUtils = require("../utils/net");
 const Json = require("../utils/json");
--- a/devtools/client/webconsole/net/components/response-tab.js
+++ b/devtools/client/webconsole/net/components/response-tab.js
@@ -1,20 +1,19 @@
 /* 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/. */
 "use strict";
 
 const React = require("devtools/client/shared/vendor/react");
 
 // Reps
-const { createFactories } = require("devtools/client/shared/components/reps/rep-utils");
 const TreeView = React.createFactory(require("devtools/client/shared/components/tree/tree-view"));
-const { Rep } = createFactories(require("devtools/client/shared/components/reps/rep"));
-const { MODE } = require("devtools/client/shared/components/reps/constants");
+const { REPS, MODE } = require("devtools/client/shared/components/reps/load-reps");
+const Rep = React.createFactory(REPS.Rep);
 
 // Network
 const SizeLimit = React.createFactory(require("./size-limit"));
 const NetInfoGroupList = React.createFactory(require("./net-info-group-list"));
 const Spinner = React.createFactory(require("./spinner"));
 const Json = require("../utils/json");
 const NetUtils = require("../utils/net");
 
--- a/devtools/client/webconsole/net/main.js
+++ b/devtools/client/webconsole/net/main.js
@@ -21,17 +21,17 @@ const { loadSheet } = require("sdk/style
 // Localization
 const {LocalizationHelper} = require("devtools/shared/l10n");
 const L10N = new LocalizationHelper("devtools/client/locales/netmonitor.properties");
 
 // Stylesheets
 var styleSheets = [
   "resource://devtools/client/jsonview/css/toolbar.css",
   "resource://devtools/client/shared/components/tree/tree-view.css",
-  "resource://devtools/client/shared/components/reps/reps.css",
+  "resource://devtools/client/shared/components/reps.css",
   "resource://devtools/client/webconsole/net/net-request.css",
   "resource://devtools/client/webconsole/net/components/size-limit.css",
   "resource://devtools/client/webconsole/net/components/net-info-body.css",
   "resource://devtools/client/webconsole/net/components/net-info-group.css",
   "resource://devtools/client/webconsole/net/components/net-info-params.css",
   "resource://devtools/client/webconsole/net/components/response-tab.css"
 ];
 
--- a/devtools/client/webconsole/net/net-request.js
+++ b/devtools/client/webconsole/net/net-request.js
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 // React
 const React = require("devtools/client/shared/vendor/react");
 const ReactDOM = require("devtools/client/shared/vendor/react-dom");
 
 // Reps
-const { parseURLParams } = require("devtools/client/shared/components/reps/rep-utils");
+const { parseURLParams } = require("devtools/client/shared/components/reps/load-reps");
 
 // Network
 const { cancelEvent, isLeftClick } = require("./utils/events");
 const NetInfoBody = React.createFactory(require("./components/net-info-body"));
 const DataProvider = require("./data-provider");
 
 // Constants
 const XHTML_NS = "http://www.w3.org/1999/xhtml";
--- a/devtools/client/webconsole/new-console-output/components/console-table.js
+++ b/devtools/client/webconsole/new-console-output/components/console-table.js
@@ -6,18 +6,18 @@
 const {
   createClass,
   createFactory,
   DOM: dom,
   PropTypes
 } = require("devtools/client/shared/vendor/react");
 const { ObjectClient } = require("devtools/shared/client/main");
 const actions = require("devtools/client/webconsole/new-console-output/actions/messages");
-const {l10n} = require("devtools/client/webconsole/new-console-output/utils/messages");
-const { MODE } = require("devtools/client/shared/components/reps/constants");
+const { l10n } = require("devtools/client/webconsole/new-console-output/utils/messages");
+const { MODE } = require("devtools/client/shared/components/reps/load-reps");
 const GripMessageBody = createFactory(require("devtools/client/webconsole/new-console-output/components/grip-message-body"));
 
 const TABLE_ROW_MAX_ITEMS = 1000;
 const TABLE_COLUMN_MAX_ITEMS = 10;
 
 const ConsoleTable = createClass({
 
   displayName: "ConsoleTable",
--- a/devtools/client/webconsole/new-console-output/components/grip-message-body.js
+++ b/devtools/client/webconsole/new-console-output/components/grip-message-body.js
@@ -12,22 +12,23 @@ if (typeof define === "undefined") {
   require("amd-loader");
 }
 
 // React
 const {
   createFactory,
   PropTypes
 } = require("devtools/client/shared/vendor/react");
-const { createFactories } = require("devtools/client/shared/components/reps/rep-utils");
-const { Rep } = createFactories(require("devtools/client/shared/components/reps/rep"));
-const StringRep = createFactories(require("devtools/client/shared/components/reps/string").StringRep).rep;
+
 const VariablesViewLink = createFactory(require("devtools/client/webconsole/new-console-output/components/variables-view-link"));
-const { Grip } = require("devtools/client/shared/components/reps/grip");
-const { MODE } = require("devtools/client/shared/components/reps/constants");
+
+const { REPS, MODE, createFactories } = require("devtools/client/shared/components/reps/load-reps");
+const Rep = createFactory(REPS.Rep);
+const Grip = REPS.Grip;
+const StringRep = createFactories(REPS.StringRep).rep;
 
 GripMessageBody.displayName = "GripMessageBody";
 
 GripMessageBody.propTypes = {
   grip: PropTypes.oneOfType([
     PropTypes.string,
     PropTypes.number,
     PropTypes.object,