Bug 1325401 - Add a reps bundle, disabled by default;r=jlast
authorJulian Descottes <jdescottes@mozilla.com>
Wed, 18 Jan 2017 14:38:10 +0100
changeset 377193 50aca7a3d25305d62c4933e9951811f5740e8fa3
parent 377192 84a59e9496ed33e1c4a78705fcadac4a7d73181c
child 377194 03792b9efb644ad2497921c434c4362561bf478e
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjlast
bugs1325401
milestone53.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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,