merge mozilla-inbound to mozilla-central. r=merge a=merge
authorSebastian Hengst <archaeopteryx@coole-files.de>
Sat, 22 Jul 2017 11:38:42 +0200
changeset 419068 a599289ac64ba1d52a1552e33150342746e3e61b
parent 419027 7e496e6bac00d2acbf3dcd5615c13d4ac489724e (current diff)
parent 419067 66f0d5a2c077325dcd716a2a0bc6192bc4fc9fae (diff)
child 419069 7ce557b85b611536b69539a7c18d4834ffc92eea
child 419074 41566ef5a640836daf4b6041796e8f95b8b8f8f8
child 419108 1173ebb5a3f073e3dc8e157d7e20fe010a4ebbb0
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone56.0a1
first release with
nightly linux32
a599289ac64b / 56.0a1 / 20170722100652 / files
nightly linux64
a599289ac64b / 56.0a1 / 20170722100652 / files
nightly mac
a599289ac64b / 56.0a1 / 20170722100334 / files
nightly win32
a599289ac64b / 56.0a1 / 20170722030204 / files
nightly win64
a599289ac64b / 56.0a1 / 20170722030204 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central. r=merge a=merge MozReview-Commit-ID: 4EWdTlEncz7
layout/inspector/inDOMUtils.cpp
taskcluster/ci/test/test-platforms.yml
taskcluster/ci/test/test-sets.yml
taskcluster/ci/test/tests.yml
--- a/devtools/client/debugger/new/debugger.css
+++ b/devtools/client/debugger/new/debugger.css
@@ -351,21 +351,23 @@ body {
 ::-webkit-scrollbar-thumb {
   border-radius: 8px;
   background: rgba(113, 113, 113, 0.5);
 }
 
 :root.theme-dark .CodeMirror-scrollbar-filler {
   background: transparent;
 }
-:root.theme-light, :root .theme-light {
+:root.theme-light,
+:root .theme-light {
   --search-overlays-semitransparent: rgba(221, 225, 228, 0.66);
 }
 
-:root.theme-dark, :root .theme-dark {
+:root.theme-dark,
+:root .theme-dark {
   --search-overlays-semitransparent: rgba(42, 46, 56, 0.66);
 }
 .debugger {
   display: flex;
   flex: 1;
   height: 100%;
 }
 
@@ -456,31 +458,32 @@ menuseparator {
   height: 100%;
   z-index: 999;
 }
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* 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/. */
 
-.theme-dark, .theme-light {
+.theme-dark,
+.theme-light {
   --number-color: var(--theme-highlight-green);
   --string-color: var(--theme-highlight-orange);
   --null-color: var(--theme-comment);
   --object-color: var(--theme-body-color);
   --caption-color: var(--theme-highlight-blue);
   --location-color: var(--theme-content-color1);
   --source-link-color: var(--theme-highlight-blue);
   --node-color: var(--theme-highlight-bluegrey);
   --reference-color: var(--theme-highlight-purple);
 }
 
 .theme-firebug {
   --number-color: #000088;
-  --string-color: #FF0000;
+  --string-color: #ff0000;
   --null-color: #787878;
   --object-color: DarkGreen;
   --caption-color: #444444;
   --location-color: #555555;
   --source-link-color: blue;
   --node-color: rgb(0, 0, 136);
   --reference-color: rgb(102, 102, 255);
 }
@@ -498,42 +501,50 @@ menuseparator {
 }
 
 .objectBox-object {
   font-weight: bold;
   color: var(--object-color);
   white-space: pre-wrap;
 }
 
-.objectBox-string, .objectBox-text, .objectLink-textNode, .objectBox-table {
+.objectBox-string,
+.objectBox-text,
+.objectLink-textNode,
+.objectBox-table {
   white-space: pre-wrap;
 }
 
 .objectBox-number,
 .objectLink-styleRule,
 .objectLink-element,
 .objectLink-textNode,
 .objectBox-array > .length {
   color: var(--number-color);
 }
 
 .objectBox-string {
   color: var(--string-color);
 }
 
-.objectLink-function, .objectBox-stackTrace, .objectLink-profile {
+.objectLink-function,
+.objectBox-stackTrace,
+.objectLink-profile {
   color: var(--object-color);
 }
 
 .objectLink-Location {
   font-style: italic;
   color: var(--location-color);
 }
 
-.objectBox-null, .objectBox-undefined, .objectBox-hint, .logRowHint {
+.objectBox-null,
+.objectBox-undefined,
+.objectBox-hint,
+.logRowHint {
   font-style: italic;
   color: var(--null-color);
 }
 
 .objectLink-sourceLink {
   position: absolute;
   right: 4px;
   top: 2px;
@@ -567,26 +578,31 @@ menuseparator {
 }
 
 .objectLink-object .nodeName {
   font-weight: normal;
 }
 
 /******************************************************************************/
 
-.objectLeftBrace, .objectRightBrace, .arrayLeftBracket, .arrayRightBracket {
+.objectLeftBrace,
+.objectRightBrace,
+.arrayLeftBracket,
+.arrayRightBracket {
   cursor: pointer;
   font-weight: bold;
 }
 
-.objectLeftBrace, .arrayLeftBracket {
+.objectLeftBrace,
+.arrayLeftBracket {
   margin-right: 4px;
 }
 
-.objectRightBrace, .arrayRightBracket {
+.objectRightBrace,
+.arrayRightBracket {
   margin-left: 4px;
 }
 
 /******************************************************************************/
 /* Cycle reference*/
 
 .objectLink-Reference {
   font-weight: bold;
@@ -608,22 +624,24 @@ menuseparator {
 
 .theme-dark .objectBox-null,
 .theme-dark .objectBox-undefined,
 .theme-light .objectBox-null,
 .theme-light .objectBox-undefined {
   font-style: normal;
 }
 
-.theme-dark .objectBox-object, .theme-light .objectBox-object {
+.theme-dark .objectBox-object,
+.theme-light .objectBox-object {
   font-weight: normal;
   white-space: pre-wrap;
 }
 
-.theme-dark .caption, .theme-light .caption {
+.theme-dark .caption,
+.theme-light .caption {
   font-weight: normal;
 }
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* 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/. */
 
 .split-box {
@@ -723,39 +741,58 @@ menuseparator {
 .searchinput-container {
   display: flex;
   border-bottom: 1px solid var(--theme-splitter-color);
 }
 
 .theme-dark .result-list li .subtitle {
   color: var(--theme-comment-alt);
 }
-.arrow, .folder, .domain, .file, .worker, .refresh, .add-button {
+.arrow,
+.folder,
+.domain,
+.file,
+.worker,
+.refresh,
+.add-button {
   fill: var(--theme-splitter-color);
 }
 
-.worker, .folder {
+.worker,
+.folder {
   position: relative;
   top: 2px;
 }
 
-.domain, .file, .worker, .refresh, .add-button {
+.domain,
+.file,
+.worker,
+.refresh,
+.add-button {
   position: relative;
   top: 1px;
 }
 
-.domain svg, .folder svg, .worker svg, .refresh svg, .add-button svg {
+.domain svg,
+.folder svg,
+.worker svg,
+.refresh svg,
+.add-button svg {
   width: 15px;
 }
 
 .file svg {
   width: 13px;
 }
 
-.file svg, .domain svg, .folder svg, .refresh svg, .worker svg {
+.file svg,
+.domain svg,
+.folder svg,
+.refresh svg,
+.worker svg {
   margin-inline-end: 5px;
 }
 
 .arrow svg {
   fill: var(--theme-splitter-color);
   margin-top: 3px;
   transition: transform 0.25s ease;
   width: 10px;
@@ -774,42 +811,63 @@ html[dir="rtl"] .arrow svg {
 /* TODO (Amit): html is just for specificity. keep it like this? */
 html .arrow.expanded svg {
   transform: rotate(0deg);
 }
 
 .arrow.hidden {
   visibility: hidden;
 }
-.autocomplete {
-  flex: 1;
-  width: 100%;
-}
-
-.autocomplete .no-result-msg {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 100%;
-  height: 100%;
-  color: var(--theme-graphs-full-red);
-  font-size: 24px;
-  padding: 4px;
-  word-break: break-all;
-}
-
-.autocomplete .no-result-msg .sad-face {
-  width: 24px;
-  margin: 0 4px;
-  line-height: 0;
-  flex-shrink: 0;
-}
-
-.autocomplete .no-result-msg .sad-face svg {
-  fill: var(--theme-graphs-full-red);
+.managed-tree .tree {
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  -o-user-select: none;
+  user-select: none;
+
+  white-space: nowrap;
+  overflow: auto;
+  min-width: 100%;
+}
+
+.managed-tree .tree button {
+  display: block;
+}
+
+.managed-tree .tree .node {
+  padding: 2px 3px 2px 3px;
+  position: relative;
+  cursor: pointer;
+}
+
+.managed-tree .tree .node.focused {
+  color: white;
+  background-color: var(--theme-selection-background);
+  padding-bottom: 2px;
+}
+
+.theme-dark .managed-tree .tree .node.focused {
+  background-color: var(--theme-selection-background-semitransparent);
+  padding-bottom: 2px;
+}
+
+html:not([dir="rtl"]) .managed-tree .tree .node > div {
+  margin-left: 10px;
+}
+
+html[dir="rtl"] .managed-tree .tree .node > div {
+  margin-right: 10px;
+}
+
+.managed-tree .tree .node.focused svg {
+  fill: white;
+}
+
+.managed-tree .tree-node button {
+  position: fixed;
 }
 .close-btn path {
   fill: var(--theme-comment-alt);
 }
 
 .close-btn .close {
   cursor: pointer;
   width: 14px;
@@ -890,27 +948,30 @@ html .arrow.expanded svg {
   width: calc(100% - 38px);
   flex: 1;
 }
 
 .theme-dark .search-field input {
   color: var(--theme-body-color-inactive);
 }
 
-.search-field i.magnifying-glass, .search-field i.sad-face {
+.search-field i.magnifying-glass,
+.search-field i.sad-face {
   padding: 6px;
   width: 24px;
 }
 
-.search-field.big i.magnifying-glass, .search-field.big i.sad-face {
+.search-field.big i.magnifying-glass,
+.search-field.big i.sad-face {
   padding: 14px;
   width: 40px;
 }
 
-.search-field .magnifying-glass path, .search-field .magnifying-glass ellipse {
+.search-field .magnifying-glass path,
+.search-field .magnifying-glass ellipse {
   stroke: var(--theme-splitter-color);
 }
 
 .search-field input::placeholder {
   color: var(--theme-body-color-inactive);
 }
 
 .search-field input:focus {
@@ -953,19 +1014,107 @@ html .arrow.expanded svg {
 
 .search-field .search-nav-buttons .nav-btn:active path {
   fill: var(--theme-comment-alt);
 }
 
 .search-field .search-nav-buttons .nav-btn path {
   fill: var(--theme-comment);
 }
+.project-text-search {
+  flex-grow: 1;
+}
+
+.project-text-search .result {
+  display: flex;
+  cursor: default;
+  margin-bottom: 1px;
+  padding: 4px 0 4px 30px;
+}
+
+.project-text-search .matches-summary {
+  margin-left: 2px;
+}
+
+.project-text-search .result.focused {
+  background-color: #eeeeee;
+}
+
+.project-text-search .result .query-match {
+  background-color: var(--theme-selection-background);
+  color: white;
+  padding: 1px 4px;
+  margin: 0 2px 0 2px;
+  border-radius: 2px;
+}
+
+.project-text-search .result.focused .line-number {
+  font-weight: bolder;
+}
+
+.project-text-search .result .line-number {
+  margin-right: 1em;
+  width: 2em;
+}
+
+.project-text-search .file-result {
+  font-weight: bold;
+  line-height: 20px;
+  cursor: default;
+  margin: 2px 20px 2px 0;
+  padding: 3px 0 3px 5px;
+}
+
+.project-text-search .file-result .arrow {
+  margin: 2px 0 2px 0;
+}
+
+.project-text-search .file-result.focused {
+  background-color: #eeeeee;
+}
+
+.project-text-search .line-match {
+  display: "flex";
+  grow: 1;
+}
+
+.project-text-search .search-field {
+  display: flex;
+  align-self: stretch;
+  flex-grow: 1;
+}
+.autocomplete {
+  flex: 1;
+  width: 100%;
+}
+
+.autocomplete .no-result-msg {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  height: 100%;
+  color: var(--theme-graphs-full-red);
+  font-size: 24px;
+  padding: 4px;
+  word-break: break-all;
+}
+
+.autocomplete .no-result-msg .sad-face {
+  width: 24px;
+  margin: 0 4px;
+  line-height: 0;
+  flex-shrink: 0;
+}
+
+.autocomplete .no-result-msg .sad-face svg {
+  fill: var(--theme-graphs-full-red);
+}
 .result-list {
   list-style: none;
-  background-color: var(--theme-toolbar-background);
   margin: 0px;
   padding: 0px;
   overflow: auto;
   width: calc(100% - 1px); /* 1px fixes the hidden right border */
 }
 
 .result-list.big {
   max-height: calc(100% - 32px);
@@ -973,17 +1122,16 @@ html .arrow.expanded svg {
 
 .result-list * {
   -moz-user-select: none;
   user-select: none;
 }
 
 .result-list li {
   color: var(--theme-body-color);
-  background-color: var(--theme-tab-toolbar-background);
   padding: 4px 13px;
   display: flex;
   justify-content: space-between;
   border: 1px solid transparent;
 }
 
 .result-list.big li {
   padding: 10px;
@@ -995,22 +1143,22 @@ html .arrow.expanded svg {
   background: var(--theme-tab-toolbar-background);
   cursor: pointer;
 }
 
 .result-list li.selected {
   border-color: var(--theme-selection-background);
 }
 
-.search-bar .result-list li.selected {
+.result-list.small li.selected {
   background-color: var(--theme-selection-background);
   color: white;
 }
 
-.theme-dark .search-bar .result-list li.selected {
+.theme-dark  .result-list.small li.selected {
   background-color: var(--theme-body-background);
 }
 
 .result-list li .title {
   line-height: 1.5em;
   word-break: break-all;
 }
 
@@ -1037,92 +1185,16 @@ html .arrow.expanded svg {
 
 .search-bar .result-list {
   border-bottom: 1px solid var(--theme-splitter-color);
 }
 
 .theme-dark .result-list {
   background-color: var(--theme-body-background);
 }
-.tree {
-  -webkit-user-select: none;
-  -moz-user-select: none;
-  -ms-user-select: none;
-  -o-user-select: none;
-  user-select: none;
-
-  white-space: nowrap;
-  overflow: auto;
-  min-width: 100%;
-}
-
-.tree button {
-  display: block;
-}
-
-.tree .node {
-  padding: 2px 5px;
-  position: relative;
-  cursor: pointer;
-}
-
-.tree .node.focused {
-  color: white;
-  background-color: var(--theme-selection-background);
-}
-
-.theme-dark .tree .node.focused {
-  background-color: var(--theme-selection-background-semitransparent);
-}
-
-html:not([dir="rtl"]) .tree .node > div {
-  margin-left: 10px;
-}
-
-html[dir="rtl"] .tree .node > div {
-  margin-right: 10px;
-}
-
-.tree .node.focused svg {
-  fill: white;
-}
-
-.tree-node button {
-  position: fixed;
-}
-.project-text-search {
-  flex-grow: 1;
-}
-
-.project-text-search .result {
-  display: flex;
-  margin-left: 20px;
-}
-
-.project-text-search .file-result {
-  font-weight: bold;
-  margin-top: 20px;
-  line-height: 20px;
-}
-
-.project-text-search .line-match {
-  font-family: monospace;
-  display: "flex";
-  grow: 1;
-}
-
-.project-text-search .result .line-number {
-  padding-right: 5px;
-}
-
-.project-text-search .search-field {
-  display: flex;
-  align-self: stretch;
-  flex-grow: 1;
-}
 .sources-panel {
   flex: 1;
   display: flex;
   flex-direction: column;
   overflow: hidden;
   position: relative;
 }
 
@@ -1160,33 +1232,44 @@ html[dir="rtl"] .tree .node > div {
   white-space: nowrap;
   padding-inline-end: 10px;
   cursor: pointer;
 }
 
 .sources-list {
   flex: 1;
   display: flex;
-  overflow: hidden;
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+
+.sources-list .managed-tree {
+  flex: 1;
+  display: flex;
+  overflow-x: hidden;
+  overflow-y: auto;
 }
 
 .theme-dark .sources-list .tree .node:not(.focused) svg {
   fill: var(--theme-comment);
 }
 
 .theme-dark .source-list .tree .node.focused {
   background-color: var(--theme-tab-toolbar-background);
 }
 
 .no-sources-message {
   font-size: 12px;
   color: var(--theme-comment-alt);
   font-weight: lighter;
   padding-top: 5px;
-  text-align: center;
+  flex-grow: 1;
+  display: flex;
+  justify-content: center;
+  align-items: center;
 }
 
 .sources-panel .source-footer {
   position: relative;
 }
 
 .sources-panel .outline {
   display: flex;
@@ -1301,33 +1384,37 @@ html[dir="rtl"] .tree .node > div {
   font-size: 14px;
   color: var(--theme-conditional-breakpoint-color);
   line-height: 30px;
 }
 
 .conditional-breakpoint-panel input:focus {
   outline-width: 0;
 }
-.toggle-button-start, .toggle-button-end {
+.toggle-button-start,
+.toggle-button-end {
   transform: translate(0, 2px);
   transition: transform 0.25s ease-in-out;
   cursor: pointer;
   padding: 5px 2px;
 }
 
-.toggle-button-start.vertical, .toggle-button-end.vertical {
+.toggle-button-start.vertical,
+.toggle-button-end.vertical {
   padding: 4px 2px;
 }
 
-.toggle-button-start svg, .toggle-button-end svg {
+.toggle-button-start svg,
+.toggle-button-end svg {
   width: 16px;
   fill: var(--theme-comment);
 }
 
-.theme-dark .toggle-button-start svg, .theme-dark .toggle-button-end svg {
+.theme-dark .toggle-button-start svg,
+.theme-dark .toggle-button-end svg {
   fill: var(--theme-comment-alt);
 }
 
 .toggle-button-end {
   margin-inline-end: 5px;
   margin-inline-start: auto;
 }
 
@@ -1339,17 +1426,18 @@ html:not([dir="rtl"]) .toggle-button-end
 html[dir="rtl"] .toggle-button-start svg {
   transform: rotate(180deg);
 }
 
 html .toggle-button-end.vertical svg {
   transform: rotate(-90deg);
 }
 
-.toggle-button-start.collapsed, .toggle-button-end.collapsed {
+.toggle-button-start.collapsed,
+.toggle-button-end.collapsed {
   transform: rotate(180deg);
 }
 .source-footer {
   background: var(--theme-toolbar-background);
   border-top: 1px solid var(--theme-splitter-color);
   position: absolute;
   display: flex;
   bottom: 0;
@@ -1545,24 +1633,279 @@ html .toggle-button-end.vertical svg {
 
 .theme-dark .search-bottom-bar .search-type-toggles .search-type-btn.active {
   color: white;
 }
 
 .search-bar .result-list {
   max-height: 230px;
 }
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+.theme-dark,
+.theme-light {
+  --number-color: var(--theme-highlight-green);
+  --string-color: var(--theme-highlight-orange);
+  --null-color: var(--theme-comment);
+  --object-color: var(--theme-body-color);
+  --caption-color: var(--theme-highlight-blue);
+  --location-color: var(--theme-content-color1);
+  --source-link-color: var(--theme-highlight-blue);
+  --node-color: var(--theme-highlight-bluegrey);
+  --reference-color: var(--theme-highlight-purple);
+}
+
+.theme-firebug {
+  --number-color: #000088;
+  --string-color: #FF0000;
+  --null-color: #787878;
+  --object-color: DarkGreen;
+  --caption-color: #444444;
+  --location-color: #555555;
+  --source-link-color: blue;
+  --node-color: rgb(0, 0, 136);
+  --reference-color: rgb(102, 102, 255);
+}
+
+/******************************************************************************/
+
+.inline {
+  display: inline;
+  white-space: normal;
+}
+
+.objectBox-object {
+  font-weight: bold;
+  color: var(--object-color);
+  white-space: pre-wrap;
+}
+
+.objectBox-string,
+.objectBox-symbol,
+.objectBox-text,
+.objectBox-textNode,
+.objectBox-table {
+  white-space: pre-wrap;
+}
+
+.objectBox-number,
+.objectBox-styleRule,
+.objectBox-element,
+.objectBox-textNode,
+.objectBox-array > .length {
+  color: var(--number-color);
+}
+
+.objectBox-textNode,
+.objectBox-string,
+.objectBox-symbol {
+  color: var(--string-color);
+}
+
+.objectBox-function,
+.objectBox-stackTrace,
+.objectBox-profile {
+  color: var(--object-color);
+}
+
+.objectBox-Location {
+  font-style: italic;
+  color: var(--location-color);
+}
+
+.objectBox-null,
+.objectBox-undefined,
+.objectBox-hint,
+.logRowHint {
+  font-style: italic;
+  color: var(--null-color);
+}
+
+.objectBox-sourceLink {
+  position: absolute;
+  right: 4px;
+  top: 2px;
+  padding-left: 8px;
+  font-weight: bold;
+  color: var(--source-link-color);
+}
+
+.objectBox-failure {
+  color: var(--string-color);
+  border-width: 1px;
+  border-style: solid;
+  border-radius: 2px;
+  font-size: 0.8em;
+  padding: 0 2px;
+}
+
+/******************************************************************************/
+
+.objectBox-event,
+.objectBox-eventLog,
+.objectBox-regexp,
+.objectBox-object,
+.objectBox-Date {
+  font-weight: bold;
+  color: var(--object-color);
+  white-space: pre-wrap;
+}
+
+/******************************************************************************/
+
+.objectBox-object .nodeName,
+.objectBox-NamedNodeMap .nodeName,
+.objectBox-NamedNodeMap .objectEqual,
+.objectBox-Attr .attrEqual,
+.objectBox-Attr .attrTitle {
+  color: var(--node-color);
+}
+
+.objectBox-object .nodeName {
+  font-weight: normal;
+}
+
+/******************************************************************************/
+
+.objectLeftBrace,
+.objectRightBrace,
+.arrayLeftBracket,
+.arrayRightBracket {
+  color: var(--theme-highlight-blue);
+}
+
+/******************************************************************************/
+/* Cycle reference*/
+
+.objectBox-Reference {
+  font-weight: bold;
+  color: var(--reference-color);
+}
+
+[class*="objectBox-"] > .objectTitle {
+  color: var(--theme-highlight-blue);
+  font-style: italic;
+}
+
+.caption {
+  font-weight: bold;
+  color:  var(--caption-color);
+}
+
+/******************************************************************************/
+/* Themes */
+
+.theme-dark .objectBox-null,
+.theme-dark .objectBox-undefined,
+.theme-light .objectBox-null,
+.theme-light .objectBox-undefined {
+  font-style: normal;
+}
+
+.theme-dark .objectBox-object,
+.theme-light .objectBox-object {
+  font-weight: normal;
+  white-space: pre-wrap;
+}
+
+.theme-dark .caption,
+.theme-light .caption {
+  font-weight: normal;
+}
+
+/******************************************************************************/
+/* Open DOMNode in inspector button */
+
+.open-inspector svg {
+  fill: rgb(215, 215, 215);
+  height: 16px;
+  width: 16px;
+  margin-left: .25em;
+  cursor: pointer;
+  vertical-align: middle;
+}
+
+.objectBox-node:hover .open-inspector svg,
+.objectBox-textNode:hover .open-inspector svg,
+.open-inspector svg:hover {
+  fill: rgb(65, 175, 230);
+}
+/* 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/. */
+
+.tree {
+  overflow: auto;
+  display: inline-block;
+}
+
+.tree.nowrap {
+  white-space: nowrap;
+}
+
+.tree.noselect {
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  -o-user-select: none;
+  user-select: none;
+}
+
+.tree button {
+  display: block;
+}
+
+.tree .node {
+  padding: 0 0.25em;
+  position: relative;
+  cursor: pointer;
+}
+
+.tree .node.focused {
+  color: white;
+  background-color: var(--theme-selection-background);
+}
+
+.arrow svg {
+  fill: var(--theme-splitter-color);
+  transition: transform 0.125s ease;
+  width: 10px;
+  margin-inline-end: 5px;
+  transform: rotate(-90deg);
+}
+
+html[dir="rtl"] .arrow svg,
+.arrow svg:dir(rtl),
+.arrow svg:-moz-locale-dir(rtl) {
+  transform: rotate(90deg);
+}
+
+.arrow.expanded.expanded svg {
+  transform: rotate(0deg);
+}
+
+.object-label {
+  color: var(--theme-highlight-blue);
+}
 .object-value .unavailable {
   color: var(--theme-comment);
 }
 .bracket-arrow {
   position: absolute;
 }
 
-.bracket-arrow::before, .bracket-arrow::after {
+.bracket-arrow:hover {
+  cursor: pointer;
+}
+
+.bracket-arrow::before,
+.bracket-arrow::after {
   content: '';
   height: 0;
   width: 0;
   position: absolute;
   border: 7px solid transparent;
 }
 
 .bracket-arrow.up::before {
@@ -1586,17 +1929,17 @@ html .toggle-button-end.vertical svg {
 }
 
 .theme-dark .bracket-arrow.down::before {
   border-top-color: var(--theme-body-color);
 }
 
 .bracket-arrow.down::after {
   border-bottom-color: transparent;
-  border-top-color: var(--theme-toolbar-background);
+  border-top-color: var(--theme-body-background);
   top: -1px;
 }
 .popover {
   position: fixed;
   z-index: 100;
 }
 
 .popover .gap {
@@ -1628,20 +1971,31 @@ html .toggle-button-end.vertical svg {
   color: var(--theme-highlight-blue);
   text-decoration: underline;
 }
 
 .popover .preview .header .link:hover {
   cursor: pointer;
 }
 
-.selection, .debug-expression.selection {
+.selection,
+.debug-expression.selection {
   background-color: var(--theme-highlight-yellow);
 }
 
+.theme-dark .selection,
+.theme-dark .debug-expression.selection {
+  background-color: #743884;
+}
+
+.theme-dark .cm-s-mozilla .selection,
+.theme-dark .cm-s-mozilla .debug-expression.selection {
+  color: #e7ebee;
+}
+
 .selection:hover {
   cursor: pointer;
 }
 
 .popover .preview .function-signature {
   padding-top: 10px;
 }
 
@@ -1705,45 +2059,94 @@ html .toggle-button-end.vertical svg {
   width: calc(100% - 4em);
 }
 
 .add-to-expression-bar .expression-to-save-button {
   font-size: 14px;
   color: var(--theme-comment);
   cursor: pointer;
 }
+.call-site {
+  background: #f0f9ff;
+  cursor: pointer;
+  position: relative;
+}
+
+.call-site::before {
+  content: "";
+  position: absolute;
+  width: 100%;
+  height: calc(100% - 2px);
+  border-bottom: 2px solid #aed3ef;
+}
+
+.call-site-bp {
+  cursor: pointer;
+  position: relative;
+}
+
+.debug-expression.call-site-bp,
+.call-site-bp {
+  background-color: #fce7e7;
+}
+
+.call-site-bp::before {
+  content: "";
+  position: absolute;
+  width: 100%;
+  height: calc(100% - 2px);
+  border-bottom: 2px solid red;
+}
+
+.theme-dark .call-site {
+  background-color: #4b5462;
+}
+
+.theme-dark .call-site::before {
+  border-bottom-color: #5f78a4;
+}
+
+.theme-dark .call-site-bp {
+  background-color: #4b3f3f;
+}
+
+.theme-dark .call-site-bp::before {
+  border-bottom-color: #dd4d4d;
+}
 .editor-wrapper {
   --debug-line-border: rgb(145, 188, 219);
   --debug-expression-background: rgba(202, 227, 255, 0.5);
   --editor-searchbar-height: 27px;
   --editor-second-searchbar-height: 27px;
 }
 
 .theme-dark .editor-wrapper {
-  --debug-expression-background: rgb(73, 82, 103);
-  --debug-line-border: rgb(119, 134, 162);
+  --debug-expression-background: #54617e;
+  --debug-line-border: #7786a2;
 }
 
 .editor-wrapper .CodeMirror-linewidget {
   margin-right: -7px;
 }
 
 .theme-dark {
   --theme-conditional-breakpoint-color: #9fa4a9;
 }
 
 .theme-light {
   --theme-conditional-breakpoint-color: #ccd1d5;
 }
 
-.paused .in-scope .CodeMirror-line, .paused .in-scope .CodeMirror-linenumber {
+.paused .in-scope .CodeMirror-line,
+.paused .in-scope .CodeMirror-linenumber {
   opacity: 1;
 }
 
-.paused .CodeMirror-line, .paused .CodeMirror-linenumber {
+.paused .CodeMirror-line,
+.paused .CodeMirror-linenumber {
   opacity: 0.7;
 }
 
 /**
  * There's a known codemirror flex issue with chrome that this addresses.
  * BUG https://github.com/devtools-html/debugger.html/issues/63
  */
 .editor-wrapper {
@@ -1860,17 +2263,16 @@ html[dir="rtl"] .editor-mount {
 
 /* move the breakpoint below the other gutter elements */
 .new-breakpoint .CodeMirror-gutter-elt:nth-child(2) {
   z-index: 0;
 }
 
 .editor-wrapper .CodeMirror-line {
   font-size: 11px;
-  line-height: 14px;
 }
 
 .theme-dark .editor-wrapper .CodeMirror-line .cm-comment {
   color: var(--theme-content-color3);
 }
 
 .debug-expression {
   background-color: var(--debug-expression-background);
@@ -2048,17 +2450,18 @@ html .breakpoints-list .breakpoint.pause
   padding-bottom: 4px;
 }
 
 .breakpoints-list .pause-indicator {
   flex: 0 1 content;
   order: 3;
 }
 
-:root.theme-light .breakpoint-snippet, :root.theme-firebug .breakpoint-snippet {
+:root.theme-light .breakpoint-snippet,
+:root.theme-firebug .breakpoint-snippet {
   color: var(--theme-comment);
 }
 
 :root.theme-dark .breakpoint-snippet {
   color: var(--theme-body-color);
   opacity: 0.6;
 }
 
@@ -2161,17 +2564,18 @@ html .breakpoints-list .breakpoint.pause
   overflow-x: scroll;
   color: var(--theme-content-color2);
   max-width: 50% !important;
 }
 
 .expression-error {
   color: var(--theme-highlight-red);
 }
-.frames ul .frames-group .group, .frames ul .frames-group .group .location {
+.frames ul .frames-group .group,
+.frames ul .frames-group .group .location {
   font-weight: 500;
 }
 
 .frames ul .frames-group.expanded .group,
 .frames ul .frames-group.expanded .group .location {
   color: var(--theme-highlight-blue);
 }
 
@@ -2247,37 +2651,40 @@ html .breakpoints-list .breakpoint.pause
   font-weight: lighter;
   display: flex;
   justify-content: space-between;
   flex-direction: row;
   align-items: center;
   margin: 0;
 }
 
-:root.theme-light .frames .location, :root.theme-firebug .frames .location {
+:root.theme-light .frames .location,
+:root.theme-firebug .frames .location {
   color: var(--theme-comment);
 }
 
 :root.theme-dark .frames .location {
   color: var(--theme-body-color);
   opacity: 0.6;
 }
 
 .frames .title {
   text-overflow: ellipsis;
   overflow: hidden;
   margin-right: 1em;
 }
 
-.frames ul li:hover, .frames ul li:focus {
+.frames ul li:hover,
+.frames ul li:focus {
   background-color: var(--theme-toolbar-background-alt);
   outline: none;
 }
 
-.theme-dark .frames ul li:hover, .theme-dark .frames ul li:focus {
+.theme-dark .frames ul li:hover,
+.theme-dark .frames ul li:focus {
   background-color: var(--theme-tab-toolbar-background);
 }
 
 .frames ul li.selected {
   background-color: var(--theme-selection-background);
   color: white;
 }
 
@@ -2389,17 +2796,18 @@ html .breakpoints-list .breakpoint.pause
 .accordion ._header {
   display: flex;
 }
 
 .accordion ._header:hover {
   background-color: var(--theme-toolbar-background-hover);
 }
 
-.accordion ._header button svg, .accordion ._header:hover button svg {
+.accordion ._header button svg,
+.accordion ._header:hover button svg {
   fill: currentColor;
   height: 16px;
 }
 
 .accordion ._content {
   border-bottom: 1px solid var(--theme-splitter-color);
   font-size: 12px;
 }
@@ -2528,38 +2936,31 @@ html .command-bar > button:disabled {
 .objectLink-regexp,
 .objectLink-object,
 .objectLink-Date,
 .theme-dark .objectBox-object,
 .theme-light .objectBox-object {
   white-space: nowrap;
 }
 
-.scopes-list .tree-node {
-  overflow: hidden;
+.scopes-pane {
+  overflow: auto;
 }
 
 .scopes-list .function-signature {
   display: inline-block;
 }
 .secondary-panes {
   display: flex;
   flex-direction: column;
   flex: 1;
   white-space: nowrap;
 }
 
-.secondary-panes * {
-  -moz-user-select: none;
-  user-select: none;
-}
-
 .secondary-panes .accordion {
-  overflow-y: auto;
-  overflow-x: hidden;
   flex: 1 0 auto;
 }
 
 .pane {
   color: var(--theme-body-color);
 }
 
 .pane .pane-info {
@@ -2655,34 +3056,36 @@ html .welcomebox .toggle-button-end.coll
 
 .source-tab.active {
   color: var(--theme-body-color);
   background-color: var(--theme-body-background);
   border-color: var(--theme-splitter-color);
   border-bottom-color: transparent;
 }
 
-.source-tab.active path, .source-tab:hover path {
+.source-tab.active path,
+.source-tab:hover path {
   fill: var(--theme-body-color);
 }
 
 .source-tab .prettyPrint {
   line-height: 0;
 }
 
 .source-tab .prettyPrint svg {
   height: 12px;
   width: 12px;
 }
 
 .source-tab .prettyPrint path {
   fill: var(--theme-textbox-box-shadow);
 }
 
-.source-tab .blackBox, .source-tab .prettyPrint {
+.source-tab .blackBox,
+.source-tab .prettyPrint {
   line-height: 0;
   align-self: center;
 }
 
 .source-tab .blackBox svg {
   height: 12px;
   width: 12px;
 }
@@ -2774,8 +3177,50 @@ html[dir="rtl"] .dropdown {
   position: fixed;
   width: 100%;
   height: 100%;
   background: transparent;
   z-index: 999;
   left: 0;
   top: 0;
 }
+.symbol-modal-wrapper {
+  position: fixed;
+  width: 100%;
+  height: 100%;
+  z-index: 9;
+}
+
+.symbol-modal {
+  position: absolute;
+  left: calc(50% - 250px);
+  z-index: 10;
+  width: 500px;
+  height: 230px;
+  background-color: var(--theme-codemirror-gutter-background);
+  box-shadow: 2px 4px 6px #dde1e4;
+  top: 30px;
+}
+
+.symbol-modal .input-wrapper {
+  display: -webkit-box;
+  display: -ms-flexbox;
+  display: flex;
+  -webkit-box-pack: center;
+  -ms-flex-pack: center;
+  justify-content: center;
+}
+
+.symbol-modal .close-btn {
+  padding: 6px;
+}
+
+.symbol-modal .result-list {
+  height: calc(100% - 28px);
+  overflow-y: auto;
+}
+
+@media (max-width: 520px) {
+  .symbol-modal {
+    width: 80%;
+    left: 10%;
+  }
+}
--- a/devtools/client/debugger/new/debugger.js
+++ b/devtools/client/debugger/new/debugger.js
@@ -3266,17 +3266,17 @@ return /******/ (function(modules) { // 
 
 	  return function connectClients(_x) {
 	    return _ref3.apply(this, arguments);
 	  };
 	})();
 
 	var getTabs = (() => {
 	  var _ref4 = _asyncToGenerator(function* (actions) {
-	    var firefoxTabs = yield firefox.getTabs();
+	    var firefoxTabs = yield firefox.connectClient();
 	    var chromeTabs = yield chrome.connectClient();
 	    var nodeTabs = yield chrome.connectNodeClient();
 
 	    actions.clearTabs();
 
 	    actions.newTabs(firefoxTabs);
 	    actions.newTabs(chromeTabs);
 	    actions.newTabs(nodeTabs);
@@ -3341,17 +3341,17 @@ return /******/ (function(modules) { // 
 
 	var _require5 = __webpack_require__(828),
 	    setConfig = _require5.setConfig,
 	    getValue = _require5.getValue,
 	    isDevelopment = _require5.isDevelopment;
 
 	var L10N = __webpack_require__(185);
 
-	var _require6 = __webpack_require__(966),
+	var _require6 = __webpack_require__(1130),
 	    showMenu = _require6.showMenu,
 	    buildMenu = _require6.buildMenu;
 
 	setConfig(({"environment":"firefox-panel","logging":false,"clientLogging":false,"firefox":{"mcPath":"./firefox"},"workers":{"parserURL":"resource://devtools/client/debugger/new/parser-worker.js","prettyPrintURL":"resource://devtools/client/debugger/new/pretty-print-worker.js","searchURL":"resource://devtools/client/debugger/new/search-worker.js"},"features":{"blackbox":{"enabled":true},"chromeScopes":{"enabled":false},"eventListeners":{"enabled":false},"codeCoverage":{"enabled":false},"codeFolding":{"enabled":false},"searchNav":{"enabled":true},"collapseFrame":{"enabled":true}}}));
 
 	// Set various flags before requiring app code.
 	if (getValue("logging.client")) {
 	  // DevToolsUtils.dumpn.wantLogging = true;
@@ -11690,17 +11690,17 @@ return /******/ (function(modules) { // 
 
 	/* This Source Code Form is subject to the terms of the Mozilla Public
 	 * License, v. 2.0. If a copy of the MPL was not distributed with this
 	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 	var React = __webpack_require__(2);
 	var dom = React.DOM;
 
-	var _require = __webpack_require__(966),
+	var _require = __webpack_require__(1130),
 	    showMenu = _require.showMenu,
 	    buildMenu = _require.buildMenu;
 
 	var Settings = React.createClass({
 	  displayName: "Settings",
 
 	  propTypes: {
 	    config: React.PropTypes.object.isRequired,
@@ -13337,26 +13337,29 @@ return /******/ (function(modules) { // 
 	function executeSoon(fn) {
 	  setTimeout(fn, 0);
 	}
 
 	exports.default = _assert2.default;
 
 /***/ },
 /* 223 */
-/***/ function(module, exports) {
+/***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
 	exports.default = assert;
+
+	var _devtoolsConfig = __webpack_require__(828);
+
 	function assert(condition, message) {
-	  if (!condition) {
+	  if ((0, _devtoolsConfig.isDevelopment)() && !condition) {
 	    throw new Error(`Assertion failure: ${message}`);
 	  }
 	}
 
 /***/ },
 /* 224 */
 /***/ function(module, exports) {
 
@@ -13413,17 +13416,17 @@ return /******/ (function(modules) { // 
 	  pref("devtools.debugger.tabs", "[]");
 	  pref("devtools.debugger.ui.framework-grouping-on", true);
 	  pref("devtools.debugger.pending-selected-location", "{}");
 	  pref("devtools.debugger.pending-breakpoints", "{}");
 	  pref("devtools.debugger.expressions", "[]");
 	  pref("devtools.debugger.file-search-case-sensitive", false);
 	  pref("devtools.debugger.file-search-whole-word", false);
 	  pref("devtools.debugger.file-search-regex-match", false);
-	  pref("devtools.debugger.prefs-schema-version", "1.0.0");
+	  pref("devtools.debugger.prefs-schema-version", "1.0.1");
 	}
 
 	const prefs = new PrefsHelper("devtools", {
 	  clientSourceMapsEnabled: ["Bool", "debugger.client-source-maps-enabled"],
 	  pauseOnExceptions: ["Bool", "debugger.pause-on-exceptions"],
 	  ignoreCaughtExceptions: ["Bool", "debugger.ignore-caught-exceptions"],
 	  callStackVisible: ["Bool", "debugger.call-stack-visible"],
 	  scopesVisible: ["Bool", "debugger.scopes-visible"],
@@ -13470,16 +13473,20 @@ return /******/ (function(modules) { // 
 	var _sources = __webpack_require__(232);
 
 	var _sources2 = _interopRequireDefault(_sources);
 
 	var _breakpoints = __webpack_require__(236);
 
 	var _breakpoints2 = _interopRequireDefault(_breakpoints);
 
+	var _pendingBreakpoints = __webpack_require__(1133);
+
+	var _pendingBreakpoints2 = _interopRequireDefault(_pendingBreakpoints);
+
 	var _asyncRequests = __webpack_require__(238);
 
 	var _asyncRequests2 = _interopRequireDefault(_asyncRequests);
 
 	var _pause = __webpack_require__(239);
 
 	var _pause2 = _interopRequireDefault(_pause);
 
@@ -13492,29 +13499,32 @@ return /******/ (function(modules) { // 
 	var _ast2 = _interopRequireDefault(_ast);
 
 	var _coverage = __webpack_require__(241);
 
 	var _coverage2 = _interopRequireDefault(_coverage);
 
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
+	/* 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/. */
+
 	exports.default = {
 	  expressions: _expressions2.default,
 	  eventListeners: _eventListeners2.default,
 	  sources: _sources2.default,
 	  breakpoints: _breakpoints2.default,
+	  pendingBreakpoints: _pendingBreakpoints2.default,
 	  asyncRequests: _asyncRequests2.default,
 	  pause: _pause2.default,
 	  ui: _ui2.default,
 	  ast: _ast2.default,
 	  coverage: _coverage2.default
-	}; /* 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/. */
+	};
 
 /***/ },
 /* 228 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
@@ -13725,17 +13735,17 @@ return /******/ (function(modules) { // 
 /* 232 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
-	exports.getSelectedSourceText = exports.getSelectedSource = exports.getSelectedLocation = exports.getSourcesForTabs = exports.getSourceTabs = exports.getSources = undefined;
+	exports.getSelectedSourceText = exports.getSelectedSource = exports.getSelectedLocation = exports.getSourcesForTabs = exports.getSearchTabs = exports.getSourceTabs = exports.getSources = undefined;
 	exports.initialState = initialState;
 	exports.removeSourceFromTabList = removeSourceFromTabList;
 	exports.removeSourcesFromTabList = removeSourcesFromTabList;
 	exports.getNewSelectedSourceId = getNewSelectedSourceId;
 	exports.getSource = getSource;
 	exports.getSourceByURL = getSourceByURL;
 	exports.getPendingSelectedLocation = getPendingSelectedLocation;
 	exports.getPrettySource = getPrettySource;
@@ -13808,35 +13818,38 @@ return /******/ (function(modules) { // 
 	        line: action.line,
 	        url: action.source.url
 	      };
 
 	      _prefs.prefs.pendingSelectedLocation = location;
 	      return state.set("selectedLocation", {
 	        sourceId: action.source.id,
 	        line: action.line
-	      }).set("pendingSelectedLocation", location).merge({
-	        tabs: updateTabList({ sources: state }, action.source.url)
-	      });
+	      }).set("pendingSelectedLocation", location);
 
 	    case "CLEAR_SELECTED_SOURCE":
 	      location = { url: "" };
 	      _prefs.prefs.pendingSelectedLocation = location;
 
 	      return state.set("selectedLocation", { sourceId: "" }).set("pendingSelectedLocation", location);
 
 	    case "SELECT_SOURCE_URL":
 	      location = {
 	        url: action.url,
 	        line: action.line
 	      };
 
 	      _prefs.prefs.pendingSelectedLocation = location;
 	      return state.set("pendingSelectedLocation", location);
 
+	    case "ADD_TAB":
+	      return state.merge({
+	        tabs: updateTabList({ sources: state }, action.source.url)
+	      });
+
 	    case "MOVE_TAB":
 	      return state.merge({
 	        tabs: updateTabList({ sources: state }, action.url, action.tabIndex)
 	      });
 
 	    case "CLOSE_TAB":
 	      _prefs.prefs.tabs = action.tabs;
 	      return state.merge({ tabs: action.tabs });
@@ -13868,27 +13881,28 @@ return /******/ (function(modules) { // 
 	      return initialState().set("pendingSelectedLocation", { url: _url });
 	  }
 
 	  return state;
 	}
 
 	function getTextPropsFromAction(action) {
 	  var source = action.source;
-	  var sourceText = action.value;
+	  var value = action.value;
+
 
 	  if (action.status === "start") {
 	    return { id: source.id, loading: true };
 	  } else if (action.status === "error") {
 	    return { id: source.id, error: action.error, loading: false };
 	  }
 	  return {
-	    text: sourceText.text,
+	    text: value.text,
 	    id: source.id,
-	    contentType: sourceText.contentType,
+	    contentType: value.contentType,
 	    loading: false
 	  };
 	}
 
 	// TODO: Action is coerced to `any` unfortunately because how we type
 	// asynchronous actions is wrong. The `value` may be null for the
 	// "start" and "error" states but we don't type it like that. We need
 	// to rethink how we type async actions.
@@ -14036,16 +14050,18 @@ return /******/ (function(modules) { // 
 	}
 
 	var getSources = exports.getSources = (0, _reselect.createSelector)(getSourcesState, sources => sources.sources);
 
 	var getTabs = (0, _reselect.createSelector)(getSourcesState, sources => sources.tabs);
 
 	var getSourceTabs = exports.getSourceTabs = (0, _reselect.createSelector)(getTabs, getSources, (tabs, sources) => tabs.filter(tab => getSourceByUrlInSources(sources, tab)));
 
+	var getSearchTabs = exports.getSearchTabs = (0, _reselect.createSelector)(getTabs, getSources, (tabs, sources) => tabs.filter(tab => !getSourceByUrlInSources(sources, tab)));
+
 	var getSourcesForTabs = exports.getSourcesForTabs = (0, _reselect.createSelector)(getSourceTabs, getSources, (tabs, sources) => {
 	  return tabs.map(tab => getSourceByUrlInSources(sources, tab)).filter(source => source);
 	});
 
 	var getSelectedLocation = exports.getSelectedLocation = (0, _reselect.createSelector)(getSourcesState, sources => sources.selectedLocation);
 
 	var getSelectedSource = exports.getSelectedSource = (0, _reselect.createSelector)(getSelectedLocation, getSources, (selectedLocation, sources) => {
 	  if (!selectedLocation) {
@@ -14066,35 +14082,30 @@ return /******/ (function(modules) { // 
 /* 233 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
-	exports.getMode = exports.getFilenameFromURL = exports.getFilename = exports.getRawSourceURL = exports.getPrettySourceURL = exports.isPretty = exports.isJavaScript = undefined;
+	exports.getMode = exports.getSourcePath = exports.getFilenameFromURL = exports.getFilename = exports.getRawSourceURL = exports.getPrettySourceURL = exports.isPretty = exports.isJavaScript = undefined;
 
 	var _utils = __webpack_require__(234);
 
 	var _path = __webpack_require__(235);
 
+	var _url = __webpack_require__(334);
+
 	/**
 	 * Trims the query part or reference identifier of a url string, if necessary.
 	 *
 	 * @memberof utils/source
 	 * @static
 	 */
-
-
-	/**
-	 * Utils for working with Source URLs
-	 * @module utils/source
-	 */
-
 	function trimUrlQuery(url) {
 	  var length = url.length;
 	  var q1 = url.indexOf("?");
 	  var q2 = url.indexOf("&");
 	  var q3 = url.indexOf("#");
 	  var q = Math.min(q1 != -1 ? q1 : length, q2 != -1 ? q2 : length, q3 != -1 ? q3 : length);
 
 	  return url.slice(0, q);
@@ -14105,16 +14116,23 @@ return /******/ (function(modules) { // 
 	 * javascript files.
 	 *
 	 * @return boolean
 	 *         True if the source is likely javascript.
 	 *
 	 * @memberof utils/source
 	 * @static
 	 */
+
+
+	/**
+	 * Utils for working with Source URLs
+	 * @module utils/source
+	 */
+
 	function isJavaScript(url) {
 	  var contentType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "";
 
 	  return url && /\.(jsm|js)?$/.test(trimUrlQuery(url)) || contentType.includes("javascript");
 	}
 
 	/**
 	 * @memberof utils/source
@@ -14175,66 +14193,88 @@ return /******/ (function(modules) { // 
 	  "text/typescript-jsx": {
 	    name: "jsx",
 	    base: { name: "javascript", typescript: true }
 	  },
 	  "text/jsx": "jsx",
 	  "text/x-elm": "elm",
 	  "text/x-clojure": "clojure",
 	  "text/wasm": { name: "text" },
-	  html: { name: "htmlmixed" }
-	};
+	  "text/html": { name: "htmlmixed" }
+	};
+
+	function getSourcePath(source) {
+	  if (!source.url) {
+	    return "";
+	  }
+
+	  var _parseURL = (0, _url.parse)(source.url),
+	      path = _parseURL.path,
+	      href = _parseURL.href;
+	  // for URLs like "about:home" the path is null so we pass the full href
+
+
+	  return path || href;
+	}
 
 	/**
 	 *
 	 * Returns Code Mirror mode for source content type
 	 * @param contentType
 	 * @return String
 	 * @memberof utils/source
 	 * @static
 	 */
 
 	function getMode(source) {
-	  if (!source.text) {
-	    return { name: "text" };
-	  }
-
-	  if (!source.contentType) {
-	    // Use HTML mode for files in which the first non whitespace
-	    // character is `<` regardless of extension.
-	    var name = source.text.match(/^\s*</) ? "htmlmixed" : "text";
-	    return { name };
-	  }
-
 	  var contentType = source.contentType,
 	      text = source.text;
 
+
+	  if (!text) {
+	    return { name: "text" };
+	  }
+
+	  // Use HTML mode for files in which the first non whitespace
+	  // character is `<` regardless of extension.
+	  var isHTMLLike = text.match(/^\s*</);
+	  if (!contentType) {
+	    if (isHTMLLike) {
+	      return { name: "htmlmixed" };
+	    }
+	    return { name: "text" };
+	  }
+
 	  // //  or /*  */
-
 	  if (text.match(/^\s*(\/\/ @flow|\/\* @flow \*\/)/)) {
 	    return contentTypeModeMap["text/typescript"];
 	  }
 
-	  if (/script|elm|jsx|clojure|wasm/.test(contentType)) {
+	  if (/script|elm|jsx|clojure|wasm|html/.test(contentType)) {
 	    if (contentType in contentTypeModeMap) {
 	      return contentTypeModeMap[contentType];
 	    }
 
 	    return contentTypeModeMap["text/javascript"];
 	  }
 
+	  if (isHTMLLike) {
+	    return { name: "htmlmixed" };
+	  }
+
 	  return { name: "text" };
 	}
 
 	exports.isJavaScript = isJavaScript;
 	exports.isPretty = isPretty;
 	exports.getPrettySourceURL = getPrettySourceURL;
 	exports.getRawSourceURL = getRawSourceURL;
 	exports.getFilename = getFilename;
 	exports.getFilenameFromURL = getFilenameFromURL;
+	exports.getSourcePath = getSourcePath;
 	exports.getMode = getMode;
 
 /***/ },
 /* 234 */
 /***/ function(module, exports) {
 
 	"use strict";
 
@@ -14365,383 +14405,175 @@ return /******/ (function(modules) { // 
 /* 236 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
-
-	var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-	/* 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/. */
-
-	/**
-	 * Breakpoints reducer
-	 * @module reducers/breakpoints
-	 */
-
 	exports.initialState = initialState;
-	exports.makePendingBreakpoint = makePendingBreakpoint;
+	exports.getBreakpoints = getBreakpoints;
 	exports.getBreakpoint = getBreakpoint;
-	exports.getBreakpoints = getBreakpoints;
-	exports.getBreakpointsForSource = getBreakpointsForSource;
 	exports.getBreakpointsDisabled = getBreakpointsDisabled;
 	exports.getBreakpointsLoading = getBreakpointsLoading;
-	exports.getPendingBreakpoints = getPendingBreakpoints;
-
-	var _fromJS = __webpack_require__(237);
-
-	var _fromJS2 = _interopRequireDefault(_fromJS);
+	exports.getBreakpointsForSource = getBreakpointsForSource;
 
 	var _immutable = __webpack_require__(146);
 
 	var I = _interopRequireWildcard(_immutable);
 
 	var _makeRecord = __webpack_require__(230);
 
 	var _makeRecord2 = _interopRequireDefault(_makeRecord);
 
-	var _prefs = __webpack_require__(226);
-
-	var _breakpoint = __webpack_require__(1057);
+	var _devtoolsSourceMap = __webpack_require__(898);
+
+	var _breakpoint2 = __webpack_require__(1057);
+
+	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 	function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
 
-	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+	/* 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/. */
+
+	/**
+	 * Breakpoints reducer
+	 * @module reducers/breakpoints
+	 */
 
 	function initialState() {
 	  return (0, _makeRecord2.default)({
 	    breakpoints: I.Map(),
-	    pendingBreakpoints: restorePendingBreakpoints(),
 	    breakpointsDisabled: false
 	  })();
 	}
 
 	function update() {
 	  var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialState();
 	  var action = arguments[1];
 
 	  switch (action.type) {
 	    case "ADD_BREAKPOINT":
 	      {
-	        var newState = addBreakpoint(state, action);
-	        setPendingBreakpoints(newState);
-	        return newState;
+	        return addBreakpoint(state, action);
 	      }
 
 	    case "SYNC_BREAKPOINT":
 	      {
-	        var _newState = syncBreakpoint(state, action);
-	        setPendingBreakpoints(_newState);
-	        return _newState;
+	        return addBreakpoint(state, action);
 	      }
 
 	    case "ENABLE_BREAKPOINT":
 	      {
-	        var _newState2 = enableBreakpoint(state, action);
-	        setPendingBreakpoints(_newState2);
-	        return _newState2;
+	        return addBreakpoint(state, action);
+	      }
+
+	    case "DISABLE_BREAKPOINT":
+	      {
+	        return updateBreakpoint(state, action);
+	      }
+
+	    case "SET_BREAKPOINT_CONDITION":
+	      {
+	        return updateBreakpoint(state, action);
 	      }
 
 	    case "REMOVE_BREAKPOINT":
 	      {
-	        var _newState3 = removeBreakpoint(state, action);
-	        setPendingBreakpoints(_newState3);
-	        return _newState3;
-	      }
-
-	    case "DISABLE_BREAKPOINT":
-	      {
-	        var _newState4 = disableBreakpoint(state, action);
-	        setPendingBreakpoints(_newState4);
-	        return _newState4;
-	      }
-
-	    case "TOGGLE_BREAKPOINTS":
-	      {
-	        if (action.status === "start") {
-	          return state.set("breakpointsDisabled", action.shouldDisableBreakpoints);
-	        }
-	        break;
-	      }
-
-	    case "SET_BREAKPOINT_CONDITION":
-	      {
-	        var _newState5 = setCondition(state, action);
-	        setPendingBreakpoints(_newState5);
-	        return _newState5;
+	        return removeBreakpoint(state, action);
 	      }
 	  }
 
 	  return state;
 	}
 
 	function addBreakpoint(state, action) {
-	  var id = (0, _breakpoint.makeLocationId)(action.breakpoint.location);
 	  if (action.status === "start") {
-	    var updatedState = state.setIn(["breakpoints", id], _extends({}, action.breakpoint, {
-	      loading: true,
-	      condition: (0, _breakpoint.firstString)(action.condition, action.breakpoint.condition)
-	    })).set("breakpointsDisabled", false);
-
-	    return updatedState;
-	  }
-
+	    var breakpoint = action.breakpoint;
+
+	    var locationId = (0, _breakpoint2.makeLocationId)(breakpoint.location);
+	    return state.setIn(["breakpoints", locationId], breakpoint);
+	  }
+
+	  // when the action completes, we can commit the breakpoint
 	  if (action.status === "done") {
 	    var _action$value = action.value,
-	        breakpointId = _action$value.id,
-	        actualLocation = _action$value.actualLocation,
-	        generatedLocation = _action$value.generatedLocation;
-
-	    var location = action.breakpoint.location;
-
-	    // If the breakpoint moved, update the map
-	    if ((0, _breakpoint.locationMoved)(location, actualLocation)) {
-	      state = slideBreakpoint(state, action);
-	      location = actualLocation;
-	    }
-
-	    var locationId = (0, _breakpoint.makeLocationId)(location);
-	    var bp = state.breakpoints.get(locationId) || action.breakpoint;
-	    var updatedBreakpoint = _extends({}, bp, {
-	      id: breakpointId,
-	      loading: false,
-	      generatedLocation,
-	      text: ""
-	    });
-	    var _updatedState = state.setIn(["breakpoints", locationId], updatedBreakpoint);
-
-	    return updatePendingBreakpoint(_updatedState, updatedBreakpoint);
-	  }
-
+	        _breakpoint = _action$value.breakpoint,
+	        previousLocation = _action$value.previousLocation;
+
+	    var _locationId = (0, _breakpoint2.makeLocationId)(_breakpoint.location);
+
+	    if (previousLocation) {
+	      return state.deleteIn(["breakpoints", (0, _breakpoint2.makeLocationId)(previousLocation)]).setIn(["breakpoints", _locationId], _breakpoint);
+	    }
+
+	    return state.setIn(["breakpoints", _locationId], _breakpoint);
+	  }
+
+	  // Remove the optimistic update
 	  if (action.status === "error") {
-	    // Remove the optimistic update
-	    return state.deleteIn(["breakpoints", id]);
-	  }
-	}
-
-	function syncBreakpoint(state, action) {
-	  if (action.status === "start") {
-	    // add a breakpoint, so we always have something to work with
-	    return optimisticlyAddBreakpoint(state, action.breakpoint);
-	  }
-	  if (action.status === "done") {
-	    // when the action completes, we can commit the breakpoint
-	    var breakpoint = action.breakpoint,
-	        _action$value2 = action.value,
-	        actualLocation = _action$value2.actualLocation,
-	        generatedLocation = _action$value2.generatedLocation;
-
-	    var sameLocation = !(0, _breakpoint.locationMoved)(breakpoint.location, actualLocation);
-
-	    // if the breakpoint is the same as the optimistic breakpoint, we can commit
-	    // to the optimistic value.
-	    if (sameLocation) {
-	      return commitBreakpoint(state, breakpoint, action.value);
-	    }
-
-	    // if the breakpoint is not the same, we will use the actual location sent
-	    // by the server, and correct the breakpoint with that new information.
-	    // Correcting a breakpoint deletes both the pending breakpoint and the
-	    // optimistic breakpoint. Correcting will commit the corrected value
-	    var overrides = { location: actualLocation, generatedLocation };
-	    var updatedState = correctBreakpoint(state, breakpoint, overrides);
-	    var id = (0, _breakpoint.makeLocationId)(actualLocation);
-
-	    // once the corrected breakpoint is added and commited, we can update the
-	    // pending breakpoints with that information.
-	    var correctedBreakpoint = updatedState.breakpoints.get(id);
-	    return updatePendingBreakpoint(updatedState, correctedBreakpoint);
-	  }
-
-	  if (action.status === "error") {
-	    // Remove the optimistic update and pending breakpoint
-	    return deleteBreakpoint(state, action.breakpoint.location);
-	  }
-	}
-
-	function enableBreakpoint(state, action) {
-	  if (action.status != "done") {
-	    return state;
-	  }
-
-	  var id = (0, _breakpoint.makeLocationId)(action.breakpoint.location);
-	  var bp = state.breakpoints.get(id);
-	  var updatedBreakpoint = _extends({}, bp, {
-	    id: action.value.id,
-	    loading: false,
-	    disabled: false
-	  });
-	  var updatedState = state.setIn(["breakpoints", id], updatedBreakpoint);
-	  return updatePendingBreakpoint(updatedState, updatedBreakpoint);
-	}
-
-	function disableBreakpoint(state, action) {
-	  if (action.status != "done") {
-	    return state;
-	  }
-	  var id = (0, _breakpoint.makeLocationId)(action.breakpoint.location);
-	  var bp = state.breakpoints.get(id);
-	  var breakpoint = _extends({}, bp, {
-	    loading: false,
-	    disabled: true
-	  });
-	  var updatedState = state.setIn(["breakpoints", id], breakpoint);
-	  return updatePendingBreakpoint(updatedState, breakpoint);
-	}
-
-	function deleteBreakpoint(state, location) {
-	  var id = (0, _breakpoint.makeLocationId)(location);
-	  var pendingId = (0, _breakpoint.makePendingLocationId)(location);
-
-	  return state.deleteIn(["breakpoints", id]).deleteIn(["pendingBreakpoints", pendingId]);
+	    var _locationId2 = (0, _breakpoint2.makeLocationId)(action.breakpoint.location);
+	    return state.deleteIn(["breakpoints", _locationId2]);
+	  }
+
+	  return state;
+	}
+
+	function updateBreakpoint(state, action) {
+	  var breakpoint = action.breakpoint;
+
+	  var locationId = (0, _breakpoint2.makeLocationId)(breakpoint.location);
+	  return state.setIn(["breakpoints", locationId], breakpoint);
 	}
 
 	function removeBreakpoint(state, action) {
-	  if (action.status != "done") {
-	    return state;
-	  }
-
-	  var updatedState = deleteBreakpoint(state, action.breakpoint.location);
-
-	  return updatedState.set("breakpointsDisabled", (0, _breakpoint.allBreakpointsDisabled)(updatedState));
-	}
-
-	function setCondition(state, action) {
-	  var id = (0, _breakpoint.makeLocationId)(action.breakpoint.location);
-
-	  if (action.status === "start") {
-	    var bp = state.breakpoints.get(id);
-	    return state.setIn(["breakpoints", id], _extends({}, bp, {
-	      loading: true,
-	      condition: action.condition
-	    }));
-	  }
-
-	  if (action.status === "done") {
-	    var _bp = state.breakpoints.get(id);
-	    var updatedBreakpoint = _extends({}, _bp, { loading: false });
-	    var updatedState = state.setIn(["breakpoints", id], updatedBreakpoint);
-
-	    return updatePendingBreakpoint(updatedState, updatedBreakpoint);
-	  }
-
-	  if (action.status === "error") {
-	    return state.deleteIn(["breakpoints", id]);
-	  }
-	}
-
-	// Syncing Methods
-	function optimisticlyAddBreakpoint(state, breakpoint) {
-	  var id = (0, _breakpoint.makeLocationId)(breakpoint.location);
-	  var updateOpts = {
-	    loading: true
-	  };
-
-	  return state.setIn(["breakpoints", id], _extends({}, breakpoint, updateOpts));
-	}
-
-	function commitBreakpoint(state, breakpoint) {
-	  var overrides = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
-
-	  // A commited breakpoint is no longer loading, and acts like a normal
-	  // breakpoint
-	  var location = overrides.location || breakpoint.location;
-	  var id = (0, _breakpoint.makeLocationId)(location);
-	  var updatedOpts = _extends({}, overrides, { loading: false });
-	  var updatedBreakpoint = _extends({}, breakpoint, updatedOpts);
-
-	  return state.setIn(["breakpoints", id], updatedBreakpoint);
-	}
-
-	function correctBreakpoint(state, breakpoint, overrides) {
-	  var intermState = deleteBreakpoint(state, breakpoint.location);
-	  var newLocationId = (0, _breakpoint.makeLocationId)(overrides.location);
-	  var newProperties = _extends({ id: newLocationId }, overrides);
-
-	  return commitBreakpoint(intermState, breakpoint, newProperties);
-	}
-
-	// TODO: remove this in favor of the correct/commit breakpoint pattern
-	function slideBreakpoint(state, action) {
-	  var _action$value3 = action.value,
-	      actualLocation = _action$value3.actualLocation,
-	      id = _action$value3.id;
 	  var breakpoint = action.breakpoint;
 
-	  var currentBp = state.breakpoints.get(id) || (0, _fromJS2.default)(breakpoint);
-
-	  var locationId = (0, _breakpoint.makeLocationId)(breakpoint.location);
-	  var movedLocationId = (0, _breakpoint.makeLocationId)(actualLocation);
-	  var updatedState = state.deleteIn(["breakpoints", locationId]);
-
-	  return updatedState.setIn(["breakpoints", movedLocationId], _extends({}, currentBp, {
-	    location: actualLocation
-	  }));
-	}
-
-	function makePendingBreakpoint(bp) {
-	  var _bp$location = bp.location,
-	      sourceUrl = _bp$location.sourceUrl,
-	      line = _bp$location.line,
-	      column = _bp$location.column,
-	      condition = bp.condition,
-	      disabled = bp.disabled,
-	      generatedLocation = bp.generatedLocation;
-
-
-	  var location = { sourceUrl, line, column };
-	  return { condition, disabled, generatedLocation, location };
-	}
-
-	function setPendingBreakpoints(state) {
-	  _prefs.prefs.pendingBreakpoints = state.pendingBreakpoints;
-	}
-
-	function updatePendingBreakpoint(state, breakpoint) {
-	  var id = (0, _breakpoint.makePendingLocationId)(breakpoint.location);
-	  return state.setIn(["pendingBreakpoints", id], makePendingBreakpoint(breakpoint));
-	}
-
-	function restorePendingBreakpoints() {
-	  return I.Map(_prefs.prefs.pendingBreakpoints);
+	  var id = (0, _breakpoint2.makeLocationId)(breakpoint.location);
+	  return state.deleteIn(["breakpoints", id]);
 	}
 
 	// Selectors
-
-	function getBreakpoint(state, location) {
-	  return state.breakpoints.breakpoints.get((0, _breakpoint.makeLocationId)(location));
-	}
+	// TODO: these functions should be moved out of the reducer
 
 	function getBreakpoints(state) {
 	  return state.breakpoints.breakpoints;
 	}
 
-	function getBreakpointsForSource(state, sourceId) {
-	  return state.breakpoints.breakpoints.filter(bp => {
-	    return bp.location.sourceId === sourceId;
-	  });
+	function getBreakpoint(state, location) {
+	  var breakpoints = getBreakpoints(state);
+	  return breakpoints.get((0, _breakpoint2.makeLocationId)(location));
 	}
 
 	function getBreakpointsDisabled(state) {
-	  return state.breakpoints.get("breakpointsDisabled");
+	  return state.breakpoints.breakpoints.every(x => x.disabled);
 	}
 
 	function getBreakpointsLoading(state) {
 	  var breakpoints = getBreakpoints(state);
 	  var isLoading = !!breakpoints.valueSeq().filter(bp => bp.loading).first();
 
 	  return breakpoints.size > 0 && isLoading;
 	}
 
-	function getPendingBreakpoints(state) {
-	  return state.breakpoints.pendingBreakpoints;
+	function getBreakpointsForSource(state, sourceId) {
+	  if (!sourceId) {
+	    return I.Map();
+	  }
+
+	  var isGeneratedSource = (0, _devtoolsSourceMap.isGeneratedId)(sourceId);
+	  var breakpoints = getBreakpoints(state);
+
+	  return breakpoints.filter(bp => {
+	    var location = isGeneratedSource ? bp.generatedLocation || bp.location : bp.location;
+	    return location.sourceId === sourceId;
+	  });
 	}
 
 	exports.default = update;
 
 /***/ },
 /* 237 */
 /***/ function(module, exports, __webpack_require__) {
 
@@ -15120,20 +14952,20 @@ return /******/ (function(modules) { // 
 /* 240 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
-	exports.getSymbolSearchState = exports.getFileSearchState = exports.getProjectSearchState = exports.State = undefined;
+	exports.State = undefined;
+	exports.getActiveSearchState = getActiveSearchState;
 	exports.getFileSearchQueryState = getFileSearchQueryState;
 	exports.getFileSearchModifierState = getFileSearchModifierState;
-	exports.getSymbolSearchResults = getSymbolSearchResults;
 	exports.getSearchResults = getSearchResults;
 	exports.getFrameworkGroupingState = getFrameworkGroupingState;
 	exports.getSymbolSearchType = getSymbolSearchType;
 	exports.getShownSource = getShownSource;
 	exports.getPaneCollapse = getPaneCollapse;
 	exports.getHighlightedLineRange = getHighlightedLineRange;
 
 	var _makeRecord = __webpack_require__(230);
@@ -15145,79 +14977,63 @@ return /******/ (function(modules) { // 
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 	/**
 	 * UI reducer
 	 * @module reducers/ui
 	 */
 
 	var State = exports.State = (0, _makeRecord2.default)({
-	  fileSearchOn: false,
+	  activeSearch: null,
 	  fileSearchQuery: "",
 	  fileSearchModifiers: (0, _makeRecord2.default)({
 	    caseSensitive: _prefs.prefs.fileSearchCaseSensitive,
 	    wholeWord: _prefs.prefs.fileSearchWholeWord,
 	    regexMatch: _prefs.prefs.fileSearchRegexMatch
 	  })(),
-	  projectSearchOn: false,
-	  symbolSearchOn: false,
 	  symbolSearchType: "functions",
-	  symbolSearchResults: [],
 	  searchResults: {
+	    matches: [],
+	    matchIndex: -1,
 	    index: -1,
 	    count: 0
 	  },
 	  shownSource: "",
 	  startPanelCollapsed: _prefs.prefs.startPanelCollapsed,
 	  endPanelCollapsed: _prefs.prefs.endPanelCollapsed,
 	  frameworkGroupingOn: _prefs.prefs.frameworkGroupingOn,
 	  highlightedLineRange: undefined
 	});
 
 	function update() {
 	  var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : State();
 	  var action = arguments[1];
 
 	  switch (action.type) {
-	    case "TOGGLE_PROJECT_SEARCH":
+	    case "TOGGLE_ACTIVE_SEARCH":
 	      {
-	        return state.set("projectSearchOn", action.value);
+	        return state.set("activeSearch", action.value);
 	      }
 
 	    case "TOGGLE_FRAMEWORK_GROUPING":
 	      {
 	        _prefs.prefs.frameworkGroupingOn = action.value;
 	        return state.set("frameworkGroupingOn", action.value);
 	      }
 
-	    case "TOGGLE_FILE_SEARCH":
-	      {
-	        return state.set("fileSearchOn", action.value);
-	      }
-
-	    case "TOGGLE_SYMBOL_SEARCH":
-	      {
-	        return state.set("symbolSearchOn", action.value);
-	      }
-
 	    case "UPDATE_FILE_SEARCH_QUERY":
 	      {
 	        return state.set("fileSearchQuery", action.query);
 	      }
 
 	    case "UPDATE_SEARCH_RESULTS":
 	      {
 	        return state.set("searchResults", action.results);
 	      }
 
-	    case "UPDATE_SYMBOL_SEARCH_RESULTS":
-	      {
-	        return state.set("symbolSearchResults", action.results);
-	      }
-
 	    case "TOGGLE_FILE_SEARCH_MODIFIER":
 	      {
 	        var actionVal = !state.getIn(["fileSearchModifiers", action.modifier]);
 
 	        if (action.modifier == "caseSensitive") {
 	          _prefs.prefs.fileSearchCaseSensitive = actionVal;
 	        }
 
@@ -15274,49 +15090,40 @@ return /******/ (function(modules) { // 
 	      {
 	        return state;
 	      }
 	  }
 	}
 
 	// NOTE: we'd like to have the app state fully typed
 	// https://github.com/devtools-html/debugger.html/blob/master/src/reducers/sources.js#L179-L185
-
-	function getSearchState(field, state) {
-	  return state.ui.get(field);
+	function getActiveSearchState(state) {
+	  return state.ui.get("activeSearch");
 	}
 
 	function getFileSearchQueryState(state) {
 	  return state.ui.get("fileSearchQuery");
 	}
 
 	function getFileSearchModifierState(state) {
 	  return state.ui.get("fileSearchModifiers");
 	}
 
-	function getSymbolSearchResults(state) {
-	  return state.ui.get("symbolSearchResults");
-	}
-
 	function getSearchResults(state) {
 	  return state.ui.get("searchResults");
 	}
 
 	function getFrameworkGroupingState(state) {
 	  return state.ui.get("frameworkGroupingOn");
 	}
 
 	function getSymbolSearchType(state) {
 	  return state.ui.get("symbolSearchType");
 	}
 
-	var getProjectSearchState = exports.getProjectSearchState = getSearchState.bind(null, "projectSearchOn");
-	var getFileSearchState = exports.getFileSearchState = getSearchState.bind(null, "fileSearchOn");
-	var getSymbolSearchState = exports.getSymbolSearchState = getSearchState.bind(null, "symbolSearchOn");
-
 	function getShownSource(state) {
 	  return state.ui.get("shownSource");
 	}
 
 	function getPaneCollapse(state, position) {
 	  if (position == "start") {
 	    return state.ui.get("startPanelCollapsed");
 	  }
@@ -15414,101 +15221,57 @@ return /******/ (function(modules) { // 
 	var _pause = __webpack_require__(239);
 
 	var pause = _interopRequireWildcard(_pause);
 
 	var _breakpoints = __webpack_require__(236);
 
 	var breakpoints = _interopRequireWildcard(_breakpoints);
 
+	var _pendingBreakpoints = __webpack_require__(1133);
+
+	var pendingBreakpoints = _interopRequireWildcard(_pendingBreakpoints);
+
 	var _eventListeners = __webpack_require__(231);
 
 	var eventListeners = _interopRequireWildcard(_eventListeners);
 
 	var _ui = __webpack_require__(240);
 
 	var ui = _interopRequireWildcard(_ui);
 
 	var _ast = __webpack_require__(1058);
 
 	var ast = _interopRequireWildcard(_ast);
 
 	var _coverage = __webpack_require__(241);
 
 	var coverage = _interopRequireWildcard(_coverage);
 
+	var _breakpointAtLocation = __webpack_require__(1134);
+
+	var _breakpointAtLocation2 = _interopRequireDefault(_breakpointAtLocation);
+
+	var _linesInScope = __webpack_require__(1124);
+
+	var _linesInScope2 = _interopRequireDefault(_linesInScope);
+
+	var _visibleBreakpoints = __webpack_require__(1135);
+
+	var _visibleBreakpoints2 = _interopRequireDefault(_visibleBreakpoints);
+
+	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
 	function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
 
 	/**
 	 * @param object - location
 	 */
 
-	module.exports = {
-	  getSource: sources.getSource,
-	  getNewSelectedSourceId: sources.getNewSelectedSourceId,
-	  removeSourceFromTabList: sources.removeSourceFromTabList,
-	  removeSourcesFromTabList: sources.removeSourcesFromTabList,
-	  getSourceByURL: sources.getSourceByURL,
-	  getSourceInSources: sources.getSourceInSources,
-	  getSources: sources.getSources,
-	  getSourceTabs: sources.getSourceTabs,
-	  getSourcesForTabs: sources.getSourcesForTabs,
-	  getSelectedSource: sources.getSelectedSource,
-	  getSelectedSourceText: sources.getSelectedSourceText,
-	  getSelectedLocation: sources.getSelectedLocation,
-	  getPendingSelectedLocation: sources.getPendingSelectedLocation,
-	  getPrettySource: sources.getPrettySource,
-
-	  getBreakpoint: breakpoints.getBreakpoint,
-	  getBreakpoints: breakpoints.getBreakpoints,
-	  getPendingBreakpoints: breakpoints.getPendingBreakpoints,
-	  getBreakpointsForSource: breakpoints.getBreakpointsForSource,
-	  getBreakpointsDisabled: breakpoints.getBreakpointsDisabled,
-	  getBreakpointsLoading: breakpoints.getBreakpointsLoading,
-
-	  getPause: pause.getPause,
-	  getChromeScopes: pause.getChromeScopes,
-	  getLoadedObjects: pause.getLoadedObjects,
-	  getLoadedObject: pause.getLoadedObject,
-	  getFrameScopes: pause.getFrameScopes,
-	  getObjectProperties: pause.getObjectProperties,
-	  getIsWaitingOnBreak: pause.getIsWaitingOnBreak,
-	  getShouldPauseOnExceptions: pause.getShouldPauseOnExceptions,
-	  getShouldIgnoreCaughtExceptions: pause.getShouldIgnoreCaughtExceptions,
-	  getFrames: pause.getFrames,
-	  getSelectedFrame: pause.getSelectedFrame,
-	  getDebuggeeUrl: pause.getDebuggeeUrl,
-
-	  getHitCountForSource: coverage.getHitCountForSource,
-	  getCoverageEnabled: coverage.getCoverageEnabled,
-
-	  getEventListeners: eventListeners.getEventListeners,
-
-	  getProjectSearchState: ui.getProjectSearchState,
-	  getFileSearchState: ui.getFileSearchState,
-	  getFileSearchQueryState: ui.getFileSearchQueryState,
-	  getFileSearchModifierState: ui.getFileSearchModifierState,
-	  getSymbolSearchResults: ui.getSymbolSearchResults,
-	  getSearchResults: ui.getSearchResults,
-	  getFrameworkGroupingState: ui.getFrameworkGroupingState,
-	  getSymbolSearchState: ui.getSymbolSearchState,
-	  getSymbolSearchType: ui.getSymbolSearchType,
-	  getShownSource: ui.getShownSource,
-	  getPaneCollapse: ui.getPaneCollapse,
-
-	  getExpressions: expressions.getExpressions,
-	  getVisibleExpressions: expressions.getVisibleExpressions,
-	  getExpression: expressions.getExpression,
-	  getHighlightedLineRange: ui.getHighlightedLineRange,
-
-	  getSymbols: ast.getSymbols,
-	  hasSymbols: ast.hasSymbols,
-	  getOutOfScopeLocations: ast.getOutOfScopeLocations,
-	  getSelection: ast.getSelection
-	};
+	module.exports = Object.assign({}, expressions, sources, pause, breakpoints, pendingBreakpoints, eventListeners, ui, ast, coverage, { getBreakpointAtLocation: _breakpointAtLocation2.default, getInScopeLines: _linesInScope2.default, getVisibleBreakpoints: _visibleBreakpoints2.default });
 
 /***/ },
 /* 243 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
@@ -15538,23 +15301,23 @@ return /******/ (function(modules) { // 
 	__webpack_require__(327);
 
 	__webpack_require__(331);
 
 	var _devtoolsSplitter = __webpack_require__(910);
 
 	var _devtoolsSplitter2 = _interopRequireDefault(_devtoolsSplitter);
 
-	var _ProjectSearch2 = __webpack_require__(1060);
+	var _ProjectSearch2 = __webpack_require__(1139);
 
 	var _ProjectSearch3 = _interopRequireDefault(_ProjectSearch2);
 
-	var _Sources2 = __webpack_require__(388);
-
-	var _Sources3 = _interopRequireDefault(_Sources2);
+	var _PrimaryPanes2 = __webpack_require__(1142);
+
+	var _PrimaryPanes3 = _interopRequireDefault(_PrimaryPanes2);
 
 	var _Editor2 = __webpack_require__(426);
 
 	var _Editor3 = _interopRequireDefault(_Editor2);
 
 	var _SecondaryPanes2 = __webpack_require__(718);
 
 	var _SecondaryPanes3 = _interopRequireDefault(_SecondaryPanes2);
@@ -15562,36 +15325,42 @@ return /******/ (function(modules) { // 
 	var _WelcomeBox2 = __webpack_require__(747);
 
 	var _WelcomeBox3 = _interopRequireDefault(_WelcomeBox2);
 
 	var _Tabs = __webpack_require__(750);
 
 	var _Tabs2 = _interopRequireDefault(_Tabs);
 
+	var _SymbolModal2 = __webpack_require__(1170);
+
+	var _SymbolModal3 = _interopRequireDefault(_SymbolModal2);
+
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 	var shortcuts = new _devtoolsModules.KeyShortcuts({ window });
 
 	var verticalLayoutBreakpoint = window.matchMedia("(min-width: 800px)");
 
 	var SplitBox = (0, _react.createFactory)(_devtoolsSplitter2.default);
 
 	var ProjectSearch = (0, _react.createFactory)(_ProjectSearch3.default);
 
-	var Sources = (0, _react.createFactory)(_Sources3.default);
+	var PrimaryPanes = (0, _react.createFactory)(_PrimaryPanes3.default);
 
 	var Editor = (0, _react.createFactory)(_Editor3.default);
 
 	var SecondaryPanes = (0, _react.createFactory)(_SecondaryPanes3.default);
 
 	var WelcomeBox = (0, _react.createFactory)(_WelcomeBox3.default);
 
 	var EditorTabs = (0, _react.createFactory)(_Tabs2.default);
 
+	var SymbolModal = (0, _react.createFactory)(_SymbolModal3.default);
+
 	class App extends _react.Component {
 
 	  constructor(props) {
 	    super(props);
 	    this.state = {
 	      horizontal: verticalLayoutBreakpoint.matches,
 	      startPanelSize: 0,
 	      endPanelSize: 0
@@ -15643,72 +15412,77 @@ return /******/ (function(modules) { // 
 	    var _props2 = this.props,
 	        startPanelCollapsed = _props2.startPanelCollapsed,
 	        endPanelCollapsed = _props2.endPanelCollapsed;
 	    var horizontal = this.state.horizontal;
 
 
 	    var overflowX = endPanelCollapsed ? "hidden" : "auto";
 
-	    return _react.DOM.div({ className: "debugger" }, SplitBox({
+	    return SplitBox({
 	      style: { width: "100vw" },
 	      initialSize: "250px",
 	      minSize: 10,
 	      maxSize: "50%",
 	      splitterSize: 1,
 	      onResizeEnd: size => this.setState({ startPanelSize: size }),
-	      startPanel: Sources({ horizontal }),
+	      startPanel: PrimaryPanes({ horizontal }),
 	      startPanelCollapsed,
 	      endPanel: SplitBox({
 	        style: { overflowX },
 	        initialSize: "300px",
 	        minSize: 10,
 	        maxSize: "80%",
 	        splitterSize: 1,
 	        onResizeEnd: size => this.setState({ endPanelSize: size }),
 	        endPanelControl: true,
 	        startPanel: this.renderEditorPane(),
 	        endPanel: SecondaryPanes({ horizontal }),
 	        endPanelCollapsed,
 	        vert: horizontal
 	      })
-	    }));
+	    });
 	  }
 
 	  renderVerticalLayout() {
 	    var _props3 = this.props,
 	        startPanelCollapsed = _props3.startPanelCollapsed,
 	        endPanelCollapsed = _props3.endPanelCollapsed;
 	    var horizontal = this.state.horizontal;
 
 
-	    return _react.DOM.div({ className: "debugger" }, SplitBox({
+	    return SplitBox({
 	      style: { width: "100vw" },
 	      initialSize: "300px",
 	      minSize: 30,
 	      maxSize: "99%",
 	      splitterSize: 1,
 	      vert: horizontal,
 	      startPanel: SplitBox({
 	        style: { width: "100vw" },
 	        initialSize: "250px",
 	        minSize: 10,
 	        maxSize: "40%",
 	        splitterSize: 1,
 	        startPanelCollapsed,
-	        startPanel: Sources({ horizontal }),
+	        startPanel: PrimaryPanes({ horizontal }),
 	        endPanel: this.renderEditorPane()
 	      }),
 	      endPanel: SecondaryPanes({ horizontal }),
 	      endPanelCollapsed
-	    }));
+	    });
 	  }
 
 	  render() {
-	    return this.state.horizontal ? this.renderHorizontalLayout() : this.renderVerticalLayout();
+	    var _props4 = this.props,
+	        selectSource = _props4.selectSource,
+	        selectedSource = _props4.selectedSource;
+
+
+	    return _react.DOM.div({ className: "debugger" }, this.state.horizontal ? this.renderHorizontalLayout() : this.renderVerticalLayout(), SymbolModal({ selectSource, selectedSource }));
 	  }
 	}
 
 	App.displayName = "App";
 
 	App.childContextTypes = { shortcuts: _react.PropTypes.object };
 
 	exports.default = (0, _reactRedux.connect)(state => ({
@@ -15775,227 +15549,78 @@ return /******/ (function(modules) { // 
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
 
 	var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
 
 	var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-	var _getGeneratedLocation = (() => {
-	  var _ref = _asyncToGenerator(function* (source, sourceMaps, location) {
-	    if (!sourceMaps.isOriginalId(location.sourceId)) {
-	      return location;
-	    }
-
-	    return yield sourceMaps.getGeneratedLocation(location, source.toJS());
-	  });
-
-	  return function _getGeneratedLocation(_x2, _x3, _x4) {
-	    return _ref.apply(this, arguments);
-	  };
-	})();
-
-	var _formatClientBreakpoint = (() => {
-	  var _ref2 = _asyncToGenerator(function* (clientBreakpoint, sourceMaps, location) {
-	    var clientOriginalLocation = yield sourceMaps.getOriginalLocation(clientBreakpoint.actualLocation);
-
-	    // make sure that we are re-adding the same type of breakpoint. Column
-	    // or line
-	    var actualLocation = (0, _breakpoint.equalizeLocationColumn)(clientOriginalLocation, location);
-
-	    // the generatedLocation might have slid, so now we can adjust it
-	    var generatedLocation = clientBreakpoint.actualLocation;
-
-	    var id = clientBreakpoint.id,
-	        hitCount = clientBreakpoint.hitCount;
-
-	    return { id, actualLocation, hitCount, generatedLocation };
-	  });
-
-	  return function _formatClientBreakpoint(_x5, _x6, _x7) {
-	    return _ref2.apply(this, arguments);
-	  };
-	})();
-
-	// we have three forms of syncing: disabled syncing, existing server syncing
-	// and adding a new breakpoint
-
-
-	var syncClientBreakpoint = (() => {
-	  var _ref3 = _asyncToGenerator(function* (sourceId, client, sourceMaps, pendingBreakpoint) {
-	    var generatedSourceId = sourceMaps.isOriginalId(sourceId) ? (0, _devtoolsSourceMap.originalToGeneratedId)(sourceId) : sourceId;
-
-	    // this is the generatedLocation of the pending breakpoint, with
-	    // the source id updated to reflect the new connection
-	    var oldGeneratedLocation = _extends({}, pendingBreakpoint.generatedLocation, {
-	      sourceId: generatedSourceId
-	    });
-
-	    /** ******* CASE 1: Disabled ***********/
-	    // early return if breakpoint is disabled, send overrides to update
-	    // the id as expected
-	    if (pendingBreakpoint.disabled) {
-	      return {
-	        id: generatedSourceId,
-	        actualLocation: _extends({}, pendingBreakpoint.location, { id: sourceId }),
-	        generatedLocation: oldGeneratedLocation
-	      };
-	    }
-
-	    /** ******* CASE 2: Merge Server Breakpoint ***********/
-	    // early return if breakpoint exists on the server, send overrides
-	    // to update the id as expected
-	    var existingClient = client.getBreakpointByLocation(oldGeneratedLocation);
-
-	    if (existingClient) {
-	      return _formatClientBreakpoint(existingClient, sourceMaps, pendingBreakpoint.location);
-	    }
-
-	    /** ******* CASE 3: Add New Breakpoint ***********/
-	    // If we are not disabled, set the breakpoint on the server and get
-	    // that info so we can set it on our breakpoints.
-	    var clientBreakpoint = yield client.setBreakpoint(oldGeneratedLocation, pendingBreakpoint.condition, sourceMaps.isOriginalId(sourceId));
-
-	    return _formatClientBreakpoint(clientBreakpoint, sourceMaps, pendingBreakpoint.location);
-	  });
-
-	  return function syncClientBreakpoint(_x8, _x9, _x10, _x11) {
-	    return _ref3.apply(this, arguments);
-	  };
-	})();
-
-	var addClientBreakpoint = (() => {
-	  var _ref4 = _asyncToGenerator(function* (state, client, sourceMaps, breakpoint) {
-	    var location = breakpoint.location;
-	    var source = (0, _selectors.getSource)(state, location.sourceId);
-	    var generatedLocation = yield _getGeneratedLocation(source, sourceMaps, location);
-
-	    var clientBreakpoint = yield client.setBreakpoint(generatedLocation, breakpoint.condition, sourceMaps.isOriginalId(breakpoint.location.sourceId));
-
-	    var actualLocation = yield sourceMaps.getOriginalLocation(clientBreakpoint.actualLocation);
-
-	    var id = clientBreakpoint.id,
-	        hitCount = clientBreakpoint.hitCount;
-
-	    return {
-	      id,
-	      actualLocation,
-	      hitCount,
-	      generatedLocation: clientBreakpoint.actualLocation
-	    };
-	  });
-
-	  return function addClientBreakpoint(_x12, _x13, _x14, _x15) {
-	    return _ref4.apply(this, arguments);
-	  };
-	})();
-
-	/**
-	 * Enabling a breakpoint
-	 * will reuse the existing breakpoint information that is stored.
-	 *
-	 * @memberof actions/breakpoints
-	 * @static
-	 * @param {Location} $1.location Location  value
-	 */
-
-
-	exports.enableBreakpoint = enableBreakpoint;
-	exports.syncBreakpoint = syncBreakpoint;
-	exports.addBreakpoint = addBreakpoint;
-	exports.disableBreakpoint = disableBreakpoint;
-	exports.removeBreakpoint = removeBreakpoint;
-	exports.toggleAllBreakpoints = toggleAllBreakpoints;
-	exports.setBreakpointCondition = setBreakpointCondition;
-
-	var _promise = __webpack_require__(193);
-
-	var _selectors = __webpack_require__(242);
-
-	var _devtoolsSourceMap = __webpack_require__(898);
-
-	var _breakpoint = __webpack_require__(1057);
-
-	function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
 	/* This Source Code Form is subject to the terms of the Mozilla Public
 	 * License, v. 2.0. If a copy of the MPL was not distributed with this
 	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 	/**
 	 * Redux actions for breakpoints
 	 * @module actions/breakpoints
 	 */
 
-	function _breakpointExists(state, location) {
-	  var currentBp = (0, _selectors.getBreakpoint)(state, location);
-	  return currentBp && !currentBp.disabled;
-	}
-
-	function _createBreakpoint(location) {
-	  var overrides = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
-	  var condition = overrides.condition,
-	      disabled = overrides.disabled,
-	      generatedLocation = overrides.generatedLocation;
-
-	  var properties = {
-	    condition: condition || null,
-	    disabled: disabled || false,
-	    generatedLocation,
-	    location
-	  };
-
-	  return properties;
-	}
-
-	function enableBreakpoint(location) {
-	  return (_ref5) => {
-	    var dispatch = _ref5.dispatch,
-	        getState = _ref5.getState,
-	        client = _ref5.client,
-	        sourceMaps = _ref5.sourceMaps;
-
-	    var breakpoint = (0, _selectors.getBreakpoint)(getState(), location);
-	    if (!breakpoint) {
-	      throw new Error("attempted to enable a breakpoint that does not exist");
-	    }
-
-	    return dispatch({
-	      type: "ENABLE_BREAKPOINT",
-	      breakpoint,
-	      [_promise.PROMISE]: addClientBreakpoint(getState(), client, sourceMaps, breakpoint)
-	    });
-	  };
-	}
+	// this will need to be changed so that addCLientBreakpoint is removed
+
+
+	exports.syncBreakpoint = syncBreakpoint;
+	exports.addBreakpoint = addBreakpoint;
+	exports.removeBreakpoint = removeBreakpoint;
+	exports.enableBreakpoint = enableBreakpoint;
+	exports.disableBreakpoint = disableBreakpoint;
+	exports.toggleAllBreakpoints = toggleAllBreakpoints;
+	exports.setBreakpointCondition = setBreakpointCondition;
+	exports.toggleBreakpoint = toggleBreakpoint;
+	exports.toggleDisabledBreakpoint = toggleDisabledBreakpoint;
+
+	var _promise = __webpack_require__(193);
+
+	var _selectors = __webpack_require__(242);
+
+	var _breakpoint = __webpack_require__(1057);
+
+	var _addBreakpoint = __webpack_require__(1136);
+
+	var _addBreakpoint2 = _interopRequireDefault(_addBreakpoint);
+
+	var _syncBreakpoint = __webpack_require__(1137);
+
+	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+	function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
 
 	/**
 	 * Syncing a breakpoint add breakpoint information that is stored, and
 	 * contact the server for more data.
 	 *
 	 * @memberof actions/breakpoints
 	 * @static
 	 * @param {String} $1.sourceId String  value
 	 * @param {PendingBreakpoint} $1.location PendingBreakpoint  value
 	 */
 	function syncBreakpoint(sourceId, pendingBreakpoint) {
-	  return (_ref6) => {
-	    var dispatch = _ref6.dispatch,
-	        getState = _ref6.getState,
-	        client = _ref6.client,
-	        sourceMaps = _ref6.sourceMaps;
+	  return (_ref) => {
+	    var dispatch = _ref.dispatch,
+	        getState = _ref.getState,
+	        client = _ref.client,
+	        sourceMaps = _ref.sourceMaps;
 	    var _pendingBreakpoint$lo = pendingBreakpoint.location,
 	        line = _pendingBreakpoint$lo.line,
 	        sourceUrl = _pendingBreakpoint$lo.sourceUrl,
 	        column = _pendingBreakpoint$lo.column;
 
 	    var location = { sourceId, sourceUrl, line, column };
-	    var breakpoint = _createBreakpoint(location, pendingBreakpoint);
-
-	    var syncPromise = syncClientBreakpoint(sourceId, client, sourceMaps, pendingBreakpoint);
+	    var breakpoint = (0, _breakpoint.createBreakpoint)(location, pendingBreakpoint);
+
+	    var syncPromise = (0, _syncBreakpoint.syncClientBreakpoint)(sourceId, client, sourceMaps, pendingBreakpoint);
 
 	    return dispatch({
 	      type: "SYNC_BREAKPOINT",
 	      breakpoint,
 	      [_promise.PROMISE]: syncPromise
 	    });
 	  };
 	}
@@ -16003,184 +15628,286 @@ return /******/ (function(modules) { // 
 	/**
 	 * Add a new breakpoint
 	 *
 	 * @memberof actions/breakpoints
 	 * @static
 	 * @param {String} $1.condition Conditional breakpoint condition value
 	 * @param {Boolean} $1.disabled Disable value for breakpoint value
 	 */
-	function addBreakpoint(location) {
-	  var _ref7 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
-	      condition = _ref7.condition;
-
-	  return (_ref8) => {
-	    var dispatch = _ref8.dispatch,
-	        getState = _ref8.getState,
-	        client = _ref8.client,
-	        sourceMaps = _ref8.sourceMaps;
-
-	    if (_breakpointExists(getState(), location)) {
-	      return Promise.resolve();
-	    }
-
-	    var breakpoint = _createBreakpoint(location, { condition });
-	    return dispatch({
-	      type: "ADD_BREAKPOINT",
-	      breakpoint,
-	      condition: condition,
-	      [_promise.PROMISE]: addClientBreakpoint(getState(), client, sourceMaps, breakpoint)
-	    });
-	  };
-	}
-
-	/**
-	 * Disable a single breakpoint
-	 *
-	 * @memberof actions/breakpoints
-	 * @static
-	 */
-	function disableBreakpoint(location) {
-	  return (_ref9) => {
-	    var dispatch = _ref9.dispatch,
-	        getState = _ref9.getState,
-	        client = _ref9.client;
-
-	    var bp = (0, _selectors.getBreakpoint)(getState(), location);
-	    if (!bp) {
-	      throw new Error("attempt to disable a breakpoint that does not exist");
-	    }
-	    if (bp.loading) {
-	      // TODO(jwl): make this wait until the breakpoint is saved if it
-	      // is still loading
-	      throw new Error("attempt to disable unsaved breakpoint");
-	    }
-
-	    var action = {
-	      type: "DISABLE_BREAKPOINT",
-	      breakpoint: bp,
-	      disabled: true,
-	      [_promise.PROMISE]: client.removeBreakpoint(bp)
-	    };
-
-	    return dispatch(action);
+
+	function addBreakpoint(location, condition) {
+	  var breakpoint = (0, _breakpoint.createBreakpoint)(location, { condition });
+	  return (_ref2) => {
+	    var dispatch = _ref2.dispatch,
+	        getState = _ref2.getState,
+	        sourceMaps = _ref2.sourceMaps,
+	        client = _ref2.client;
+
+	    var action = { type: "ADD_BREAKPOINT", breakpoint };
+	    var promise = (0, _addBreakpoint2.default)(getState, client, sourceMaps, action);
+	    return dispatch(_extends({}, action, { [_promise.PROMISE]: promise }));
 	  };
 	}
 
 	/**
 	 * Remove a single breakpoint
 	 *
 	 * @memberof actions/breakpoints
 	 * @static
 	 */
 	function removeBreakpoint(location) {
-	  return (_ref10) => {
-	    var dispatch = _ref10.dispatch,
-	        getState = _ref10.getState,
-	        client = _ref10.client;
+	  return (_ref3) => {
+	    var dispatch = _ref3.dispatch,
+	        getState = _ref3.getState,
+	        client = _ref3.client;
 
 	    var bp = (0, _selectors.getBreakpoint)(getState(), location);
 	    if (!bp) {
 	      throw new Error("attempt to remove breakpoint that does not exist");
 	    }
+
 	    if (bp.loading) {
 	      // TODO(jwl): make this wait until the breakpoint is saved if it
 	      // is still loading
 	      throw new Error("attempt to remove unsaved breakpoint");
 	    }
 
-	    var action = {
-	      type: "REMOVE_BREAKPOINT",
-	      breakpoint: bp
-	    };
-
 	    // If the breakpoint is already disabled, we don't need to communicate
 	    // with the server. We just need to dispatch an action
 	    // simulating a successful server request
 	    if (bp.disabled) {
-	      return dispatch(Object.assign({}, action, { status: "done" }));
-	    }
-
-	    return dispatch(Object.assign({}, action, {
+	      return dispatch({
+	        type: "REMOVE_BREAKPOINT",
+	        breakpoint: bp,
+	        status: "done"
+	      });
+	    }
+
+	    return dispatch({
+	      type: "REMOVE_BREAKPOINT",
+	      breakpoint: bp,
 	      [_promise.PROMISE]: client.removeBreakpoint(bp)
-	    }));
-	  };
+	    });
+	  };
+	}
+
+	/**
+	 * Enabling a breakpoint
+	 * will reuse the existing breakpoint information that is stored.
+	 *
+	 * @memberof actions/breakpoints
+	 * @static
+	 * @param {Location} $1.location Location  value
+	 */
+	function enableBreakpoint(location) {
+	  return (() => {
+	    var _ref4 = _asyncToGenerator(function* (_ref5) {
+	      var dispatch = _ref5.dispatch,
+	          getState = _ref5.getState,
+	          client = _ref5.client,
+	          sourceMaps = _ref5.sourceMaps;
+
+	      var breakpoint = (0, _selectors.getBreakpoint)(getState(), location);
+	      if (!breakpoint) {
+	        throw new Error("attempted to enable a breakpoint that does not exist");
+	      }
+
+	      var action = { type: "ENABLE_BREAKPOINT", breakpoint };
+	      var promise = (0, _addBreakpoint2.default)(getState, client, sourceMaps, action);
+	      return dispatch({
+	        type: "ENABLE_BREAKPOINT",
+	        breakpoint,
+	        [_promise.PROMISE]: promise
+	      });
+	    });
+
+	    return function (_x) {
+	      return _ref4.apply(this, arguments);
+	    };
+	  })();
+	}
+
+	/**
+	 * Disable a single breakpoint
+	 *
+	 * @memberof actions/breakpoints
+	 * @static
+	 */
+	function disableBreakpoint(location) {
+	  return (() => {
+	    var _ref6 = _asyncToGenerator(function* (_ref7) {
+	      var dispatch = _ref7.dispatch,
+	          getState = _ref7.getState,
+	          client = _ref7.client;
+
+	      var bp = (0, _selectors.getBreakpoint)(getState(), location);
+
+	      if (!bp) {
+	        throw new Error("attempt to disable a breakpoint that does not exist");
+	      }
+
+	      if (bp.loading) {
+	        // TODO(jwl): make this wait until the breakpoint is saved if it
+	        // is still loading
+	        throw new Error("attempt to disable unsaved breakpoint");
+	      }
+
+	      yield client.removeBreakpoint(bp);
+	      var newBreakpoint = _extends({}, bp, { disabled: true });
+
+	      return dispatch({
+	        type: "DISABLE_BREAKPOINT",
+	        breakpoint: newBreakpoint
+	      });
+	    });
+
+	    return function (_x2) {
+	      return _ref6.apply(this, arguments);
+	    };
+	  })();
 	}
 
 	/**
 	 * Toggle All Breakpoints
 	 *
 	 * @memberof actions/breakpoints
 	 * @static
 	 */
 	function toggleAllBreakpoints(shouldDisableBreakpoints) {
-	  return (_ref11) => {
-	    var dispatch = _ref11.dispatch,
-	        getState = _ref11.getState;
-
-	    var breakpoints = (0, _selectors.getBreakpoints)(getState());
-	    return dispatch({
-	      type: "TOGGLE_BREAKPOINTS",
-	      shouldDisableBreakpoints,
-	      [_promise.PROMISE]: _asyncToGenerator(function* () {
-	        for (var _ref13 of breakpoints) {
-	          var _ref14 = _slicedToArray(_ref13, 2);
-
-	          var breakpoint = _ref14[1];
-
-	          if (shouldDisableBreakpoints) {
-	            yield dispatch(disableBreakpoint(breakpoint.location));
-	          } else {
-	            yield dispatch(enableBreakpoint(breakpoint.location));
-	          }
-	        }
-	      })()
-	    });
-	  };
+	  return (() => {
+	    var _ref8 = _asyncToGenerator(function* (_ref9) {
+	      var dispatch = _ref9.dispatch,
+	          getState = _ref9.getState;
+
+	      var breakpoints = (0, _selectors.getBreakpoints)(getState());
+	      for (var _ref10 of breakpoints) {
+	        var _ref11 = _slicedToArray(_ref10, 2);
+
+	        var breakpoint = _ref11[1];
+
+	        if (shouldDisableBreakpoints) {
+	          yield dispatch(disableBreakpoint(breakpoint.location));
+	        } else {
+	          yield dispatch(enableBreakpoint(breakpoint.location));
+	        }
+	      }
+	    });
+
+	    return function (_x3) {
+	      return _ref8.apply(this, arguments);
+	    };
+	  })();
 	}
 
 	/**
 	 * Update the condition of a breakpoint.
 	 *
 	 * @throws {Error} "not implemented"
 	 * @memberof actions/breakpoints
 	 * @static
 	 * @param {Location} location
 	 *        @see DebuggerController.Breakpoints.addBreakpoint
 	 * @param {string} condition
 	 *        The condition to set on the breakpoint
 	 * @param {Boolean} $1.disabled Disable value for breakpoint value
 	 */
 	function setBreakpointCondition(location) {
-	  var _ref15 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
-	      condition = _ref15.condition;
-
+	  var _ref12 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
+	      condition = _ref12.condition;
+
+	  return (() => {
+	    var _ref13 = _asyncToGenerator(function* (_ref14) {
+	      var dispatch = _ref14.dispatch,
+	          getState = _ref14.getState,
+	          client = _ref14.client,
+	          sourceMaps = _ref14.sourceMaps;
+
+	      var bp = (0, _selectors.getBreakpoint)(getState(), location);
+	      if (!bp) {
+	        return dispatch(addBreakpoint(location, condition));
+	      }
+
+	      if (bp.loading) {
+	        // TODO(jwl): when this function is called, make sure the action
+	        // creator waits for the breakpoint to exist
+	        throw new Error("breakpoint must be saved");
+	      }
+
+	      yield client.setBreakpointCondition(bp.id, location, condition, sourceMaps.isOriginalId(bp.location.sourceId));
+
+	      var newBreakpoint = _extends({}, bp, { condition });
+
+	      (0, _breakpoint.assertBreakpoint)(newBreakpoint);
+
+	      return dispatch({
+	        type: "SET_BREAKPOINT_CONDITION",
+	        breakpoint: newBreakpoint
+	      });
+	    });
+
+	    return function (_x5) {
+	      return _ref13.apply(this, arguments);
+	    };
+	  })();
+	}
+
+	function toggleBreakpoint(line, column) {
+	  return (_ref15) => {
+	    var dispatch = _ref15.dispatch,
+	        getState = _ref15.getState,
+	        client = _ref15.client,
+	        sourceMaps = _ref15.sourceMaps;
+
+	    var selectedSource = (0, _selectors.getSelectedSource)(getState());
+	    var bp = (0, _selectors.getBreakpointAtLocation)(getState(), { line, column });
+
+	    if (bp && bp.loading) {
+	      return;
+	    }
+
+	    if (bp) {
+	      // NOTE: it's possible the breakpoint has slid to a column
+	      return dispatch(removeBreakpoint({
+	        sourceId: bp.location.sourceId,
+	        sourceUrl: bp.location.sourceUrl,
+	        line: bp.location.line,
+	        column: column || bp.location.column
+	      }));
+	    }
+
+	    return dispatch(addBreakpoint({
+	      sourceId: selectedSource.get("id"),
+	      sourceUrl: selectedSource.get("url"),
+	      line: line,
+	      column: column
+	    }));
+	  };
+	}
+
+	function toggleDisabledBreakpoint(line, column) {
 	  return (_ref16) => {
 	    var dispatch = _ref16.dispatch,
 	        getState = _ref16.getState,
 	        client = _ref16.client,
 	        sourceMaps = _ref16.sourceMaps;
 
-	    var bp = (0, _selectors.getBreakpoint)(getState(), location);
+	    var bp = (0, _selectors.getBreakpointAtLocation)(getState(), { line, column });
+	    if (bp && bp.loading) {
+	      return;
+	    }
+
 	    if (!bp) {
-	      return dispatch(addBreakpoint(location, { condition }));
-	    }
-
-	    if (bp.loading) {
-	      // TODO(jwl): when this function is called, make sure the action
-	      // creator waits for the breakpoint to exist
-	      throw new Error("breakpoint must be saved");
-	    }
-
-	    return dispatch({
-	      type: "SET_BREAKPOINT_CONDITION",
-	      breakpoint: bp,
-	      condition: condition,
-	      [_promise.PROMISE]: client.setBreakpointCondition(bp.id, location, condition, sourceMaps.isOriginalId(bp.location.sourceId))
-	    });
+	      throw new Error("attempt to disable breakpoint that does not exist");
+	    }
+
+	    if (!bp.disabled) {
+	      return dispatch(disableBreakpoint(bp.location));
+	    }
+	    return dispatch(enableBreakpoint(bp.location));
 	  };
 	}
 
 /***/ },
 /* 246 */,
 /* 247 */,
 /* 248 */
 /***/ function(module, exports, __webpack_require__) {
@@ -16934,22 +16661,24 @@ return /******/ (function(modules) { // 
 	 */
 
 
 	exports.newSource = newSource;
 	exports.newSources = newSources;
 	exports.selectSourceURL = selectSourceURL;
 	exports.selectSource = selectSource;
 	exports.jumpToMappedLocation = jumpToMappedLocation;
+	exports.addTab = addTab;
 	exports.moveTab = moveTab;
 	exports.closeTab = closeTab;
 	exports.closeTabs = closeTabs;
 	exports.togglePrettyPrint = togglePrettyPrint;
 	exports.toggleBlackBox = toggleBlackBox;
 	exports.loadSourceText = loadSourceText;
+	exports.loadAllSources = loadAllSources;
 	exports.getTextForSources = getTextForSources;
 
 	var _defer = __webpack_require__(194);
 
 	var _defer2 = _interopRequireDefault(_defer);
 
 	var _promise = __webpack_require__(193);
 
@@ -17128,17 +16857,19 @@ return /******/ (function(modules) { // 
 	    }
 
 	    var source = (0, _selectors.getSource)(getState(), id);
 	    if (!source) {
 	      // If there is no source we deselect the current selected source
 	      return dispatch({ type: "CLEAR_SELECTED_SOURCE" });
 	    }
 
-	    dispatch({ type: "TOGGLE_PROJECT_SEARCH", value: false });
+	    dispatch({ type: "TOGGLE_ACTIVE_SEARCH", value: null });
+
+	    dispatch(addTab(source.toJS(), 0));
 
 	    return dispatch({
 	      type: "SELECT_SOURCE",
 	      source: source.toJS(),
 	      tabIndex: options.tabIndex,
 	      line: options.line,
 	      [_promise.PROMISE]: _asyncToGenerator(function* () {
 	        yield dispatch(loadSourceText(source.toJS()));
@@ -17176,16 +16907,24 @@ return /******/ (function(modules) { // 
 	    });
 
 	    return function (_x13) {
 	      return _ref12.apply(this, arguments);
 	    };
 	  })();
 	}
 
+	function addTab(source, tabIndex) {
+	  return {
+	    type: "ADD_TAB",
+	    source,
+	    tabIndex
+	  };
+	}
+
 	function moveTab(url, tabIndex) {
 	  return {
 	    type: "MOVE_TAB",
 	    url,
 	    tabIndex
 	  };
 	}
 
@@ -17337,71 +17076,96 @@ return /******/ (function(modules) { // 
 	        source: source,
 	        [_promise.PROMISE]: _asyncToGenerator(function* () {
 	          if (sourceMaps.isOriginalId(source.id)) {
 	            return yield sourceMaps.getOriginalSourceText(source);
 	          }
 
 	          var response = yield client.sourceContents(source.id);
 
-	          var sourceText = {
+	          return {
 	            id: source.id,
 	            text: response.source,
 	            contentType: response.contentType || "text/javascript"
 	          };
-
-	          return sourceText;
 	        })()
 	      });
 
 	      // get the symbols for the source as well
 	      return dispatch((0, _ast.setSymbols)(source.id));
 	    });
 
 	    return function (_x15) {
 	      return _ref21.apply(this, arguments);
 	    };
 	  })();
 	}
 
+	/**
+	  Load the text for all the avaliable sources
+	 * @memberof actions/sources
+	 * @static
+	 */
+	function loadAllSources() {
+	  return (() => {
+	    var _ref24 = _asyncToGenerator(function* (_ref25) {
+	      var dispatch = _ref25.dispatch,
+	          getState = _ref25.getState;
+
+	      var sources = (0, _selectors.getSources)(getState());
+	      for (var _ref26 of sources) {
+	        var _ref27 = _slicedToArray(_ref26, 2);
+
+	        var source = _ref27[1];
+
+	        yield dispatch(loadSourceText(source.toJS()));
+	      }
+	    });
+
+	    return function (_x16) {
+	      return _ref24.apply(this, arguments);
+	    };
+	  })();
+	}
+
 	// delay is in ms
 	var FETCH_SOURCE_RESPONSE_DELAY = 200;
 
 	/**
 	 * Starts fetching all the sources, silently.
 	 *
 	 * @memberof actions/sources
 	 * @static
 	 * @param array actors
 	 *        The urls for the sources to fetch. If fetching a source's text
 	 *        takes too long, it will be discarded.
 	 * @returns {Promise}
 	 *         A promise that is resolved after source texts have been fetched.
 	 */
 	function getTextForSources(actors) {
-	  return (_ref24) => {
-	    var dispatch = _ref24.dispatch,
-	        getState = _ref24.getState;
+	  return (_ref28) => {
+	    var dispatch = _ref28.dispatch,
+	        getState = _ref28.getState;
 
 	    var deferred = (0, _defer2.default)();
 	    var pending = new Set(actors);
 
 	    var fetched = [];
 
 	    // Can't use promise.all, because if one fetch operation is rejected, then
 	    // everything is considered rejected, thus no other subsequent source will
 	    // be getting fetched. We don't want that. Something like Q's allSettled
 	    // would work like a charm here.
 	    // Try to fetch as many sources as possible.
 
 	    var _loop = function (actor) {
 	      var source = (0, _selectors.getSource)(getState(), actor);
-	      dispatch(loadSourceText(source)).then((_ref31) => {
-	        var text = _ref31.text,
-	            contentType = _ref31.contentType;
+	      dispatch(loadSourceText(source)).then((_ref35) => {
+	        var text = _ref35.text,
+	            contentType = _ref35.contentType;
 
 	        onFetch([source, text, contentType]);
 	      }, err => {
 	        onError(source, err);
 	      });
 	    };
 
 	    for (var actor of actors) {
@@ -17412,21 +17176,21 @@ return /******/ (function(modules) { // 
 
 	    /* Called if fetching a source takes too long. */
 	    function onTimeout() {
 	      pending = new Set();
 	      maybeFinish();
 	    }
 
 	    /* Called if fetching a source finishes successfully. */
-	    function onFetch(_ref25) {
-	      var _ref26 = _slicedToArray(_ref25, 3),
-	          aSource = _ref26[0],
-	          aText = _ref26[1],
-	          aContentType = _ref26[2];
+	    function onFetch(_ref29) {
+	      var _ref30 = _slicedToArray(_ref29, 3),
+	          aSource = _ref30[0],
+	          aText = _ref30[1],
+	          aContentType = _ref30[2];
 
 	      // If fetching the source has previously timed out, discard it this time.
 	      if (!pending.has(aSource.actor)) {
 	        return;
 	      }
 	      pending.delete(aSource.actor);
 	      fetched.push([aSource.actor, aText, aContentType]);
 	      maybeFinish();
@@ -17440,22 +17204,22 @@ return /******/ (function(modules) { // 
 
 	    /* Called every time something interesting
 	     *  happens while fetching sources.
 	     */
 	    function maybeFinish() {
 	      if (pending.size == 0) {
 	        // Sort the fetched sources alphabetically by their url.
 	        if (deferred) {
-	          deferred.resolve(fetched.sort((_ref27, _ref28) => {
-	            var _ref30 = _slicedToArray(_ref27, 1),
-	                aFirst = _ref30[0];
-
-	            var _ref29 = _slicedToArray(_ref28, 1),
-	                aSecond = _ref29[0];
+	          deferred.resolve(fetched.sort((_ref31, _ref32) => {
+	            var _ref34 = _slicedToArray(_ref31, 1),
+	                aFirst = _ref34[0];
+
+	            var _ref33 = _slicedToArray(_ref32, 1),
+	                aSecond = _ref33[0];
 
 	            return aFirst > aSecond ? -1 : 1;
 	          }));
 	        }
 	      }
 	    }
 
 	    return deferred.promise;
@@ -17583,37 +17347,16 @@ return /******/ (function(modules) { // 
 	function shouldShowFooter(selectedSource, horizontal) {
 	  if (!horizontal) {
 	    return true;
 	  }
 
 	  return shouldShowPrettyPrint(selectedSource);
 	}
 
-	function breakpointAtLocation(breakpoints, _ref) {
-	  var line = _ref.line,
-	      _ref$column = _ref.column,
-	      column = _ref$column === undefined ? undefined : _ref$column;
-
-	  return breakpoints.find(bp => {
-	    var sameLine = bp.location.line === line + 1;
-	    if (!sameLine) {
-	      return false;
-	    }
-
-	    // NOTE: when column breakpoints are disabled we want to find
-	    // the first breakpoint
-	    if (!(0, _devtoolsConfig.isEnabled)("columnBreakpoints")) {
-	      return true;
-	    }
-
-	    return bp.location.column === column;
-	  });
-	}
-
 	function traverseResults(e, ctx, query, dir, modifiers) {
 	  e.stopPropagation();
 	  e.preventDefault();
 
 	  if (dir == "prev") {
 	    findPrev(ctx, query, true, modifiers);
 	  } else if (dir == "next") {
 	    findNext(ctx, query, true, modifiers);
@@ -17661,24 +17404,28 @@ return /******/ (function(modules) { // 
 	function markText(editor, className, location) {
 	  var start = location.start,
 	      end = location.end;
 
 
 	  return editor.codeMirror.markText({ ch: start.column, line: start.line - 1 }, { ch: end.column, line: end.line - 1 }, { className });
 	}
 
+	function lineAtHeight(editor, event) {
+	  return editor.codeMirror.lineAtHeight(event.clientY) + 1;
+	}
+
 	module.exports = Object.assign({}, expressionUtils, sourceDocumentUtils, sourceSearchUtils, _devtoolsSourceEditor.SourceEditorUtils, {
 	  createEditor,
 	  shouldShowPrettyPrint,
 	  shouldShowFooter,
-	  breakpointAtLocation,
 	  traverseResults,
 	  updateDocument,
-	  markText
+	  markText,
+	  lineAtHeight
 	});
 
 /***/ },
 /* 258 */,
 /* 259 */
 /***/ function(module, exports, __webpack_require__) {
 
 	var toString = __webpack_require__(108);
@@ -17712,23 +17459,27 @@ return /******/ (function(modules) { // 
 	    : string;
 	}
 
 	module.exports = escapeRegExp;
 
 
 /***/ },
 /* 260 */
-/***/ function(module, exports) {
-
-	"use strict";
-
-	Object.defineProperty(exports, "__esModule", {
-	  value: true
-	});
+/***/ function(module, exports, __webpack_require__) {
+
+	"use strict";
+
+	Object.defineProperty(exports, "__esModule", {
+	  value: true
+	});
+	exports.showSourceText = exports.clearDocuments = exports.removeDocument = exports.setDocument = exports.getDocument = undefined;
+
+	var _source = __webpack_require__(233);
+
 	var sourceDocs = {};
 
 	function getDocument(key) {
 	  return sourceDocs[key];
 	}
 
 	function setDocument(key, doc) {
 	  sourceDocs[key] = doc;
@@ -17737,33 +17488,61 @@ return /******/ (function(modules) { // 
 	function removeDocument(key) {
 	  delete sourceDocs[key];
 	}
 
 	function clearDocuments() {
 	  sourceDocs = {};
 	}
 
+	/**
+	 * Handle getting the source document or creating a new
+	 * document with the correct mode and text.
+	 */
+	function showSourceText(editor, source) {
+	  if (!source) {
+	    return;
+	  }
+
+	  var doc = getDocument(source.id);
+	  if (editor.codeMirror.doc === doc) {
+	    return;
+	  }
+
+	  if (doc) {
+	    editor.replaceDocument(doc);
+	    return doc;
+	  }
+
+	  doc = editor.createDocument();
+	  setDocument(source.id, doc);
+	  editor.replaceDocument(doc);
+
+	  editor.setText(source.text);
+	  editor.setMode((0, _source.getMode)(source));
+	}
+
 	exports.getDocument = getDocument;
 	exports.setDocument = setDocument;
 	exports.removeDocument = removeDocument;
 	exports.clearDocuments = clearDocuments;
+	exports.showSourceText = showSourceText;
 
 /***/ },
 /* 261 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
-	exports.getMatchIndex = exports.removeOverlay = exports.findPrev = exports.findNext = exports.find = exports.clearIndex = exports.buildQuery = undefined;
-
-	var _buildQuery = __webpack_require__(1116);
+	exports.getMatchIndex = exports.removeOverlay = exports.findPrev = exports.findNext = exports.find = exports.buildQuery = undefined;
+
+	var _buildQuery = __webpack_require__(1138);
 
 	var _buildQuery2 = _interopRequireDefault(_buildQuery);
 
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 	/**
 	 * @memberof utils/source-search
 	 * @static
@@ -17778,17 +17557,16 @@ return /******/ (function(modules) { // 
 	 * @static
 	 */
 
 
 	function SearchState() {
 	  this.posFrom = this.posTo = this.query = null;
 	  this.overlay = null;
 	  this.results = [];
-	  this.matchIndex = -1;
 	}
 
 	/**
 	 * @memberof utils/source-search
 	 * @static
 	 */
 	function getSearchState(cm, query, modifiers) {
 	  var state = cm.state.search || (cm.state.search = new SearchState());
@@ -17897,37 +17675,36 @@ return /******/ (function(modules) { // 
 	 * result.
 	 *
 	 * @memberof utils/source-search
 	 * @static
 	 */
 	function doSearch(ctx, rev, query, keepSelection, modifiers) {
 	  var cm = ctx.cm;
 
-	  var matchIndex = -1;
-
-	  cm.operation(function () {
+	  if (!cm) {
+	    return;
+	  }
+	  var defaultIndex = { line: -1, ch: -1 };
+
+	  return cm.operation(function () {
 	    if (!query || isWhitespace(query)) {
 	      return;
 	    }
 
 	    var state = getSearchState(cm, query, modifiers);
-	    var newQuery = state.query != query;
+	    var isNewQuery = state.query !== query;
 	    state.query = query;
 
 	    updateOverlay(cm, state, query, modifiers);
 	    updateCursor(cm, state, keepSelection);
-	    searchNext(ctx, rev, query, newQuery, modifiers);
-
-	    // NOTE: We would like to find the correct match index based on where the
-	    // match is in the document.
-	    state.matchIndex = matchIndex;
-	  });
-
-	  return matchIndex;
+	    var searchLocation = searchNext(ctx, rev, query, isNewQuery, modifiers);
+
+	    return searchLocation ? searchLocation.from : defaultIndex;
+	  });
 	}
 
 	function getCursorPos(newQuery, rev, state) {
 	  if (newQuery) {
 	    return rev ? state.posFrom : state.posTo;
 	  }
 
 	  return rev ? state.posTo : state.posFrom;
@@ -17998,17 +17775,16 @@ return /******/ (function(modules) { // 
 	 *
 	 * @memberof utils/source-search
 	 * @static
 	 */
 	function clearSearch(cm, query, modifiers) {
 	  var state = getSearchState(cm, query, modifiers);
 
 	  state.results = [];
-	  state.matchIndex = -1;
 
 	  if (!state.query) {
 	    return;
 	  }
 	  cm.removeOverlay(state.overlay);
 	  state.query = null;
 	}
 
@@ -18038,23 +17814,17 @@ return /******/ (function(modules) { // 
 	 *
 	 * @memberof utils/source-search
 	 * @static
 	 */
 	function findPrev(ctx, query, keepSelection, modifiers) {
 	  return doSearch(ctx, true, query, keepSelection, modifiers);
 	}
 
-	function clearIndex(ctx, query, modifiers) {
-	  var state = getSearchState(ctx.cm, query, modifiers);
-	  state.matchIndex = -1;
-	}
-
 	exports.buildQuery = _buildQuery2.default;
-	exports.clearIndex = clearIndex;
 	exports.find = find;
 	exports.findNext = findNext;
 	exports.findPrev = findPrev;
 	exports.removeOverlay = removeOverlay;
 	exports.getMatchIndex = getMatchIndex;
 
 /***/ },
 /* 262 */
@@ -20002,16 +19772,18 @@ return /******/ (function(modules) { // 
 	var _editor = __webpack_require__(257);
 
 	var _sources = __webpack_require__(232);
 
 	var _utils = __webpack_require__(234);
 
 	var _sources2 = __webpack_require__(254);
 
+	var _parser = __webpack_require__(827);
+
 	function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
 
 	/**
 	 * Redux actions for the navigation state
 	 * @module actions/navigation
 	 */
 
 	/**
@@ -20023,16 +19795,17 @@ return /******/ (function(modules) { // 
 	    var _ref = _asyncToGenerator(function* (_ref2) {
 	      var dispatch = _ref2.dispatch,
 	          getState = _ref2.getState,
 	          client = _ref2.client,
 	          sourceMaps = _ref2.sourceMaps;
 
 	      yield sourceMaps.clearSourceMaps();
 	      (0, _editor.clearDocuments)();
+	      (0, _parser.clearSymbols)();
 
 	      dispatch(navigate(event.url));
 	    });
 
 	    return function (_x) {
 	      return _ref.apply(this, arguments);
 	    };
 	  })();
@@ -20080,103 +19853,69 @@ return /******/ (function(modules) { // 
 /* 321 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
-	exports.toggleProjectSearch = toggleProjectSearch;
-	exports.toggleFileSearch = toggleFileSearch;
-	exports.toggleSymbolSearch = toggleSymbolSearch;
+	exports.closeActiveSearch = closeActiveSearch;
+	exports.setActiveSearch = setActiveSearch;
 	exports.toggleFrameworkGrouping = toggleFrameworkGrouping;
 	exports.setSelectedSymbolType = setSelectedSymbolType;
 	exports.setFileSearchQuery = setFileSearchQuery;
 	exports.updateSearchResults = updateSearchResults;
-	exports.updateSymbolSearchResults = updateSymbolSearchResults;
 	exports.toggleFileSearchModifier = toggleFileSearchModifier;
 	exports.showSource = showSource;
 	exports.togglePaneCollapse = togglePaneCollapse;
 	exports.highlightLineRange = highlightLineRange;
 	exports.clearHighlightLineRange = clearHighlightLineRange;
 
 	var _selectors = __webpack_require__(242);
 
-	function toggleProjectSearch(toggleValue) {
+	function closeActiveSearch() {
+	  return {
+	    type: "TOGGLE_ACTIVE_SEARCH",
+	    value: null
+	  };
+	}
+	function setActiveSearch(activeSearch) {
 	  return (_ref) => {
 	    var dispatch = _ref.dispatch,
 	        getState = _ref.getState;
 
-	    var projectSearchState = (0, _selectors.getProjectSearchState)(getState());
-	    if (toggleValue === undefined) {
-	      return dispatch({
-	        type: "TOGGLE_PROJECT_SEARCH",
-	        value: !projectSearchState
-	      });
-	    }
-
-	    if (projectSearchState == toggleValue) {
+	    var activeSearchState = (0, _selectors.getActiveSearchState)(getState());
+	    if (activeSearchState === activeSearch) {
 	      return;
 	    }
 
 	    dispatch({
-	      type: "TOGGLE_PROJECT_SEARCH",
-	      value: toggleValue
-	    });
-	  };
-	}
-
-	function toggleFileSearch(toggleValue) {
-	  return (_ref2) => {
-	    var dispatch = _ref2.dispatch,
-	        getState = _ref2.getState;
-
-	    if (toggleValue != null) {
-	      dispatch({
-	        type: "TOGGLE_FILE_SEARCH",
-	        value: toggleValue
-	      });
-	    } else {
-	      dispatch({
-	        type: "TOGGLE_FILE_SEARCH",
-	        value: !(0, _selectors.getFileSearchState)(getState())
-	      });
-	    }
-	  };
-	}
-
-	function toggleSymbolSearch(toggleValue) {
-	  return (_ref3) => {
-	    var dispatch = _ref3.dispatch,
-	        getState = _ref3.getState;
-
-	    dispatch({
-	      type: "TOGGLE_SYMBOL_SEARCH",
-	      value: toggleValue
+	      type: "TOGGLE_ACTIVE_SEARCH",
+	      value: activeSearch
 	    });
 	  };
 	}
 
 	function toggleFrameworkGrouping(toggleValue) {
-	  return (_ref4) => {
-	    var dispatch = _ref4.dispatch,
-	        getState = _ref4.getState;
+	  return (_ref2) => {
+	    var dispatch = _ref2.dispatch,
+	        getState = _ref2.getState;
 
 	    dispatch({
 	      type: "TOGGLE_FRAMEWORK_GROUPING",
 	      value: toggleValue
 	    });
 	  };
 	}
 
 	function setSelectedSymbolType(symbolType) {
-	  return (_ref5) => {
-	    var dispatch = _ref5.dispatch,
-	        getState = _ref5.getState;
+	  return (_ref3) => {
+	    var dispatch = _ref3.dispatch,
+	        getState = _ref3.getState;
 
 	    dispatch({
 	      type: "SET_SYMBOL_SEARCH_TYPE",
 	      symbolType
 	    });
 	  };
 	}
 
@@ -20189,31 +19928,24 @@ return /******/ (function(modules) { // 
 
 	function updateSearchResults(results) {
 	  return {
 	    type: "UPDATE_SEARCH_RESULTS",
 	    results
 	  };
 	}
 
-	function updateSymbolSearchResults(results) {
-	  return {
-	    type: "UPDATE_SYMBOL_SEARCH_RESULTS",
-	    results
-	  };
-	}
-
 	function toggleFileSearchModifier(modifier) {
 	  return { type: "TOGGLE_FILE_SEARCH_MODIFIER", modifier };
 	}
 
 	function showSource(sourceId) {
-	  return (_ref6) => {
-	    var dispatch = _ref6.dispatch,
-	        getState = _ref6.getState;
+	  return (_ref4) => {
+	    var dispatch = _ref4.dispatch,
+	        getState = _ref4.getState;
 
 	    var source = (0, _selectors.getSource)(getState(), sourceId);
 	    dispatch({
 	      type: "SHOW_SOURCE",
 	      sourceUrl: source.get("url")
 	    });
 	  };
 	}
@@ -22546,17 +22278,18 @@ return /******/ (function(modules) { // 
 	      }),
 	      onChange,
 	      onKeyDown,
 	      onKeyUp,
 	      onFocus,
 	      onBlur,
 	      placeholder,
 	      value: query,
-	      spellCheck: false
+	      spellCheck: false,
+	      ref: "input"
 	    }), _react.DOM.div({ className: "summary" }, query != "" ? summaryMsg : ""), this.renderNav(), (0, _Close2.default)({
 	      handleClick: handleClose,
 	      buttonClass: size
 	    }));
 	  }
 	}
 
 	SearchInput.defaultProps = {
@@ -22670,17 +22403,17 @@ return /******/ (function(modules) { // 
 	    return _react.DOM.ul({
 	      className: `result-list ${size}`
 	    }, items.map(this.renderListItem));
 	  }
 	}
 
 	exports.default = ResultList;
 	ResultList.defaultProps = {
-	  size: ""
+	  size: "small"
 	};
 
 /***/ },
 /* 384 */
 /***/ function(module, exports) {
 
 	// removed by extract-text-webpack-plugin
 
@@ -22688,149 +22421,17 @@ return /******/ (function(modules) { // 
 /* 385 */,
 /* 386 */
 /***/ function(module, exports) {
 
 	// removed by extract-text-webpack-plugin
 
 /***/ },
 /* 387 */,
-/* 388 */
-/***/ function(module, exports, __webpack_require__) {
-
-	"use strict";
-
-	Object.defineProperty(exports, "__esModule", {
-	  value: true
-	});
-
-	var _react = __webpack_require__(2);
-
-	var _reactImmutableProptypes = __webpack_require__(150);
-
-	var _reactImmutableProptypes2 = _interopRequireDefault(_reactImmutableProptypes);
-
-	var _redux = __webpack_require__(3);
-
-	var _reactRedux = __webpack_require__(151);
-
-	var _text = __webpack_require__(389);
-
-	var _actions = __webpack_require__(244);
-
-	var _actions2 = _interopRequireDefault(_actions);
-
-	var _selectors = __webpack_require__(242);
-
-	var _devtoolsConfig = __webpack_require__(828);
-
-	__webpack_require__(424);
-
-	var _classnames = __webpack_require__(175);
-
-	var _classnames2 = _interopRequireDefault(_classnames);
-
-	var _Outline2 = __webpack_require__(921);
-
-	var _Outline3 = _interopRequireDefault(_Outline2);
-
-	var _SourcesTree2 = __webpack_require__(390);
-
-	var _SourcesTree3 = _interopRequireDefault(_SourcesTree2);
-
-	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-	var Outline = (0, _react.createFactory)(_Outline3.default);
-
-	var SourcesTree = (0, _react.createFactory)(_SourcesTree3.default);
-
-	class Sources extends _react.Component {
-
-	  constructor(props) {
-	    super(props);
-	    this.state = { selectedPane: "sources" };
-
-	    this.renderShortcut = this.renderShortcut.bind(this);
-	    this.showPane = this.showPane.bind(this);
-	    this.renderFooter = this.renderFooter.bind(this);
-	  }
-
-	  showPane(selectedPane) {
-	    this.setState({ selectedPane });
-	  }
-
-	  renderOutlineTabs() {
-	    if (!(0, _devtoolsConfig.isEnabled)("outline")) {
-	      return;
-	    }
-
-	    return [_react.DOM.div({
-	      className: (0, _classnames2.default)("tab", {
-	        active: this.state.selectedPane === "sources"
-	      }),
-	      onClick: () => this.showPane("sources"),
-	      key: "sources-tab"
-	    }, "Sources View"), _react.DOM.div({
-	      className: (0, _classnames2.default)("tab", {
-	        active: this.state.selectedPane === "outline"
-	      }),
-	      onClick: () => this.showPane("outline"),
-	      key: "outline-tab"
-	    }, "Outline View")];
-	  }
-
-	  renderFooter() {
-	    return _react.DOM.div({
-	      className: "source-footer"
-	    }, this.renderOutlineTabs());
-	  }
-
-	  renderShortcut() {
-	    if (this.props.horizontal) {
-	      return _react.DOM.span({
-	        className: "sources-header-info",
-	        dir: "ltr",
-	        onClick: () => this.props.toggleProjectSearch()
-	      }, L10N.getFormatStr("sources.search", (0, _text.formatKeyShortcut)(L10N.getStr("sources.search.key2"))));
-	    }
-	  }
-
-	  renderHeader() {
-	    return _react.DOM.div({ className: "sources-header" }, this.renderShortcut());
-	  }
-
-	  render() {
-	    var selectedPane = this.state.selectedPane;
-	    var _props = this.props,
-	        sources = _props.sources,
-	        selectSource = _props.selectSource;
-
-
-	    return _react.DOM.div({ className: "sources-panel" }, this.renderHeader(), SourcesTree({
-	      sources,
-	      selectSource,
-	      isHidden: selectedPane === "outline"
-	    }), Outline({ selectSource, isHidden: selectedPane === "sources" }), this.renderFooter());
-	  }
-	}
-
-	Sources.propTypes = {
-	  sources: _reactImmutableProptypes2.default.map.isRequired,
-	  selectSource: _react.PropTypes.func.isRequired,
-	  horizontal: _react.PropTypes.bool.isRequired,
-	  toggleProjectSearch: _react.PropTypes.func.isRequired
-	};
-
-	Sources.displayName = "Sources";
-
-	exports.default = (0, _reactRedux.connect)(state => ({
-	  sources: (0, _selectors.getSources)(state)
-	}), dispatch => (0, _redux.bindActionCreators)(_actions2.default, dispatch))(Sources);
-
-/***/ },
+/* 388 */,
 /* 389 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
@@ -22865,310 +22466,17 @@ return /******/ (function(modules) { // 
 	    return shortcut.replace(/Shift\+/g, "\u21E7+").replace(/Command\+|Cmd\+/g, "\u2318+").replace(/CommandOrControl\+|CmdOrCtrl\+/g, "\u2318+").replace(/Alt\+/g, "\u2325+");
 	  }
 	  return shortcut.replace(/CommandOrControl\+|CmdOrCtrl\+/g, `${L10N.getStr("ctrl")}+`);
 	}
 
 	exports.formatKeyShortcut = formatKeyShortcut;
 
 /***/ },
-/* 390 */
-/***/ function(module, exports, __webpack_require__) {
-
-	"use strict";
-
-	Object.defineProperty(exports, "__esModule", {
-	  value: true
-	});
-
-	var _redux = __webpack_require__(3);
-
-	var _reactRedux = __webpack_require__(151);
-
-	var _react = __webpack_require__(2);
-
-	var _classnames = __webpack_require__(175);
-
-	var _classnames2 = _interopRequireDefault(_classnames);
-
-	var _reactImmutableProptypes = __webpack_require__(150);
-
-	var _reactImmutableProptypes2 = _interopRequireDefault(_reactImmutableProptypes);
-
-	var _immutable = __webpack_require__(146);
-
-	var _selectors = __webpack_require__(242);
-
-	var _sourcesTree = __webpack_require__(391);
-
-	var _ManagedTree2 = __webpack_require__(419);
-
-	var _ManagedTree3 = _interopRequireDefault(_ManagedTree2);
-
-	var _actions = __webpack_require__(244);
-
-	var _actions2 = _interopRequireDefault(_actions);
-
-	var _Svg = __webpack_require__(344);
-
-	var _Svg2 = _interopRequireDefault(_Svg);
-
-	var _devtoolsLaunchpad = __webpack_require__(131);
-
-	var _clipboard = __webpack_require__(423);
-
-	var _utils = __webpack_require__(234);
-
-	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-	var ManagedTree = (0, _react.createFactory)(_ManagedTree3.default);
-
-	class SourcesTree extends _react.Component {
-
-	  constructor(props) {
-	    super(props);
-	    this.state = (0, _sourcesTree.createTree)(this.props.sources, this.props.debuggeeUrl);
-
-	    this.focusItem = this.focusItem.bind(this);
-	    this.selectItem = this.selectItem.bind(this);
-	    this.getIcon = this.getIcon.bind(this);
-	    this.onContextMenu = this.onContextMenu.bind(this);
-	    this.renderItem = this.renderItem.bind(this);
-
-	    this.queueUpdate = (0, _utils.throttle)(function () {
-	      if (!this.mounted) {
-	        return;
-	      }
-
-	      this.forceUpdate();
-	    }, 50);
-	  }
-
-	  componentDidMount() {
-	    this.mounted = true;
-	  }
-
-	  componentWillUnMount() {
-	    this.mounted = false;
-	  }
-
-	  shouldComponentUpdate() {
-	    this.queueUpdate();
-	    return false;
-	  }
-
-	  componentWillReceiveProps(nextProps) {
-	    if (this.props.debuggeeUrl != nextProps.debuggeeUrl) {
-	      // Recreate tree because the sort order changed
-	      this.setState((0, _sourcesTree.createTree)(this.props.sources, nextProps.debuggeeUrl));
-	      return;
-	    }
-	    var selectedSource = this.props.selectedSource;
-
-	    if (nextProps.shownSource && nextProps.shownSource != this.props.shownSource) {
-	      var _listItems = (0, _sourcesTree.getDirectories)(nextProps.shownSource, this.state.sourceTree);
-
-	      if (_listItems && _listItems[0]) {
-	        this.selectItem(_listItems[0]);
-	      }
-
-	      return this.setState({ listItems: _listItems });
-	    }
-
-	    if (nextProps.selectedSource && nextProps.selectedSource != selectedSource) {
-	      var _highlightItems = (0, _sourcesTree.getDirectories)(nextProps.selectedSource.get("url"), this.state.sourceTree);
-
-	      return this.setState({ highlightItems: _highlightItems });
-	    }
-
-	    if (nextProps.sources === this.props.sources) {
-	      return;
-	    }
-
-	    if (nextProps.sources.size === 0) {
-	      // remove all sources
-	      this.setState((0, _sourcesTree.createTree)(nextProps.sources, this.props.debuggeeUrl));
-	      return;
-	    }
-
-	    // TODO: do not run this every time a source is clicked,
-	    // only when a new source is added
-	    var next = (0, _immutable.Set)(nextProps.sources.valueSeq());
-	    var prev = (0, _immutable.Set)(this.props.sources.valueSeq());
-	    var newSet = next.subtract(prev);
-
-	    var uncollapsedTree = this.state.uncollapsedTree;
-	    for (var source of newSet) {
-	      (0, _sourcesTree.addToTree)(uncollapsedTree, source, this.props.debuggeeUrl);
-	    }
-
-	    // TODO: recreating the tree every time messes with the expanded
-	    // state of ManagedTree, because it depends on item instances
-	    // being the same. The result is that if a source is added at a
-	    // later time, all expanded state is lost.
-	    var sourceTree = newSet.size > 0 ? (0, _sourcesTree.collapseTree)(uncollapsedTree) : this.state.sourceTree;
-
-	    this.setState({
-	      uncollapsedTree,
-	      sourceTree,
-	      parentMap: (0, _sourcesTree.createParentMap)(sourceTree)
-	    });
-	  }
-
-	  focusItem(item) {
-	    this.setState({ focusedItem: item });
-	  }
-
-	  selectItem(item) {
-	    if (!(0, _sourcesTree.nodeHasChildren)(item)) {
-	      this.props.selectSource(item.contents.get("id"));
-	    }
-	  }
-
-	  getIcon(item, depth) {
-	    if (depth === 0) {
-	      return (0, _Svg2.default)("domain");
-	    }
-
-	    if (!(0, _sourcesTree.nodeHasChildren)(item)) {
-	      return (0, _Svg2.default)("file");
-	    }
-
-	    return (0, _Svg2.default)("folder");
-	  }
-
-	  onContextMenu(event, item) {
-	    var copySourceUrlLabel = L10N.getStr("copySourceUrl");
-	    var copySourceUrlKey = L10N.getStr("copySourceUrl.accesskey");
-
-	    event.stopPropagation();
-	    event.preventDefault();
-
-	    var menuOptions = [];
-
-	    if (!(0, _sourcesTree.isDirectory)(item)) {
-	      var source = item.contents.get("url");
-	      var copySourceUrl = {
-	        id: "node-menu-copy-source",
-	        label: copySourceUrlLabel,
-	        accesskey: copySourceUrlKey,
-	        disabled: false,
-	        click: () => (0, _clipboard.copyToTheClipboard)(source)
-	      };
-
-	      menuOptions.push(copySourceUrl);
-	    }
-
-	    (0, _devtoolsLaunchpad.showMenu)(event, menuOptions);
-	  }
-
-	  renderItem(item, depth, focused, _, expanded, _ref) {
-	    var setExpanded = _ref.setExpanded;
-
-	    var arrow = (0, _Svg2.default)("arrow", {
-	      className: (0, _classnames2.default)({
-	        expanded: expanded,
-	        hidden: !(0, _sourcesTree.nodeHasChildren)(item)
-	      }),
-	      onClick: e => {
-	        e.stopPropagation();
-	        setExpanded(item, !expanded);
-	      }
-	    });
-
-	    var icon = this.getIcon(item, depth);
-	    var paddingDir = "paddingRight";
-	    if (document.body && document.body.parentElement) {
-	      paddingDir = document.body.parentElement.dir == "ltr" ? "paddingLeft" : "paddingRight";
-	    }
-
-	    return _react.DOM.div({
-	      className: (0, _classnames2.default)("node", { focused }),
-	      style: { [paddingDir]: `${depth * 15}px` },
-	      key: item.path,
-	      onClick: () => {
-	        this.selectItem(item);
-	        setExpanded(item, !expanded);
-	      },
-	      onContextMenu: e => this.onContextMenu(e, item)
-	    }, _react.DOM.div(null, arrow, icon, item.name));
-	  }
-
-	  render() {
-	    var isHidden = this.props.isHidden;
-	    var _state = this.state,
-	        focusedItem = _state.focusedItem,
-	        sourceTree = _state.sourceTree,
-	        parentMap = _state.parentMap,
-	        listItems = _state.listItems,
-	        highlightItems = _state.highlightItems;
-
-
-	    var isEmpty = sourceTree.contents.length === 0;
-
-	    var tree = ManagedTree({
-	      key: isEmpty ? "empty" : "full",
-	      getParent: item => {
-	        return parentMap.get(item);
-	      },
-	      getChildren: item => {
-	        if ((0, _sourcesTree.nodeHasChildren)(item)) {
-	          return item.contents;
-	        }
-	        return [];
-	      },
-	      getRoots: () => sourceTree.contents,
-	      getKey: (item, i) => item.path,
-	      itemHeight: 19,
-	      autoExpandDepth: 1,
-	      autoExpandAll: false,
-	      onFocus: this.focusItem,
-	      listItems,
-	      highlightItems,
-	      renderItem: this.renderItem
-	    });
-
-	    var noSourcesMessage = _react.DOM.div({
-	      className: "no-sources-message"
-	    }, L10N.getStr("sources.noSourcesAvailable"));
-
-	    if (isEmpty) {
-	      return noSourcesMessage;
-	    }
-	    return _react.DOM.div({
-	      className: (0, _classnames2.default)("sources-list", { hidden: isHidden }),
-	      onKeyDown: e => {
-	        if (e.keyCode === 13 && focusedItem) {
-	          this.selectItem(focusedItem);
-	        }
-	      }
-	    }, tree);
-	  }
-	}
-
-	SourcesTree.propTypes = {
-	  isHidden: _react.PropTypes.bool,
-	  sources: _reactImmutableProptypes2.default.map.isRequired,
-	  selectSource: _react.PropTypes.func.isRequired,
-	  shownSource: _react.PropTypes.string,
-	  selectedSource: _reactImmutableProptypes2.default.map,
-	  debuggeeUrl: _react.PropTypes.string.isRequired
-	};
-
-	SourcesTree.displayName = "SourcesTree";
-
-	exports.default = (0, _reactRedux.connect)(state => {
-	  return {
-	    shownSource: (0, _selectors.getShownSource)(state),
-	    selectedSource: (0, _selectors.getSelectedSource)(state),
-	    debuggeeUrl: (0, _selectors.getDebuggeeUrl)(state)
-	  };
-	}, dispatch => (0, _redux.bindActionCreators)(_actions2.default, dispatch))(SourcesTree);
-
-/***/ },
+/* 390 */,
 /* 391 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
@@ -24648,18 +23956,17 @@ return /******/ (function(modules) { // 
 	          args[_key] = arguments[_key];
 	        }
 
 	        return (_props = _this.props).renderItem.apply(_props, args.concat([{
 	          setExpanded: _this.setExpanded
 	        }]));
 	      }
 	    });
-
-	    return Tree(props);
+	    return _react.DOM.div({ className: "managed-tree" }, Tree(props));
 	  }
 	}
 
 	ManagedTree.displayName = "ManagedTree";
 
 	ManagedTree.propTypes = Object.assign({}, Tree.propTypes);
 
 	exports.default = ManagedTree;
@@ -24694,22 +24001,17 @@ return /******/ (function(modules) { // 
 	  document.addEventListener("copy", doCopy);
 	  document.execCommand("copy", false, null);
 	  document.removeEventListener("copy", doCopy);
 	}
 
 	exports.copyToTheClipboard = copyToTheClipboard;
 
 /***/ },
-/* 424 */
-/***/ function(module, exports) {
-
-	// removed by extract-text-webpack-plugin
-
-/***/ },
+/* 424 */,
 /* 425 */,
 /* 426 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
@@ -24724,50 +24026,40 @@ return /******/ (function(modules) { // 
 	var _reactImmutableProptypes = __webpack_require__(150);
 
 	var _reactImmutableProptypes2 = _interopRequireDefault(_reactImmutableProptypes);
 
 	var _redux = __webpack_require__(3);
 
 	var _reactRedux = __webpack_require__(151);
 
-	var _reselect = __webpack_require__(993);
-
 	var _classnames = __webpack_require__(175);
 
 	var _classnames2 = _interopRequireDefault(_classnames);
 
 	var _devtoolsConfig = __webpack_require__(828);
 
 	var _debounce = __webpack_require__(651);
 
 	var _debounce2 = _interopRequireDefault(_debounce);
 
-	var _source = __webpack_require__(233);
-
 	var _GutterMenu = __webpack_require__(655);
 
 	var _GutterMenu2 = _interopRequireDefault(_GutterMenu);
 
 	var _EditorMenu = __webpack_require__(656);
 
 	var _EditorMenu2 = _interopRequireDefault(_EditorMenu);
 
 	var _ConditionalPanel = __webpack_require__(711);
 
 	var _devtoolsLaunchpad = __webpack_require__(131);
 
 	var _selectors = __webpack_require__(242);
 
-	var _linesInScope = __webpack_require__(1124);
-
-	var _linesInScope2 = _interopRequireDefault(_linesInScope);
-
-	var _breakpoint = __webpack_require__(1057);
-
 	var _actions = __webpack_require__(244);
 
 	var _actions2 = _interopRequireDefault(_actions);
 
 	var _Footer2 = __webpack_require__(427);
 
 	var _Footer3 = _interopRequireDefault(_Footer2);
 
@@ -24778,28 +24070,28 @@ return /******/ (function(modules) { // 
 	var _HighlightLines2 = __webpack_require__(1025);
 
 	var _HighlightLines3 = _interopRequireDefault(_HighlightLines2);
 
 	var _Preview2 = __webpack_require__(657);
 
 	var _Preview3 = _interopRequireDefault(_Preview2);
 
-	var _Breakpoint2 = __webpack_require__(714);
-
-	var _Breakpoint3 = _interopRequireDefault(_Breakpoint2);
-
-	var _ColumnBreakpoint2 = __webpack_require__(1011);
-
-	var _ColumnBreakpoint3 = _interopRequireDefault(_ColumnBreakpoint2);
+	var _Breakpoints2 = __webpack_require__(1158);
+
+	var _Breakpoints3 = _interopRequireDefault(_Breakpoints2);
 
 	var _HitMarker2 = __webpack_require__(715);
 
 	var _HitMarker3 = _interopRequireDefault(_HitMarker2);
 
+	var _CallSites2 = __webpack_require__(1159);
+
+	var _CallSites3 = _interopRequireDefault(_CallSites2);
+
 	var _editor = __webpack_require__(257);
 
 	__webpack_require__(716);
 
 	__webpack_require__(1046);
 
 	var _devtoolsSourceEditor = __webpack_require__(994);
 
@@ -24808,90 +24100,86 @@ return /******/ (function(modules) { // 
 	var Footer = (0, _react.createFactory)(_Footer3.default);
 
 	var SearchBar = (0, _react.createFactory)(_SearchBar3.default);
 
 	var HighlightLines = (0, _react.createFactory)(_HighlightLines3.default);
 
 	var Preview = (0, _react.createFactory)(_Preview3.default);
 
-	var Breakpoint = (0, _react.createFactory)(_Breakpoint3.default);
-
-	var ColumnBreakpoint = (0, _react.createFactory)(_ColumnBreakpoint3.default);
+	var Breakpoints = (0, _react.createFactory)(_Breakpoints3.default);
 
 	var HitMarker = (0, _react.createFactory)(_HitMarker3.default);
 
+	var CallSites = (0, _react.createFactory)(_CallSites3.default);
+
 	var cssVars = {
 	  searchbarHeight: "var(--editor-searchbar-height)",
 	  secondSearchbarHeight: "var(--editor-second-searchbar-height)",
 	  footerHeight: "var(--editor-footer-height)"
 	};
 
 	class Editor extends _react.PureComponent {
 
 	  constructor() {
 	    super();
 
 	    this.cbPanel = null;
-	    this.editor = null;
 	    this.pendingJumpLine = null;
 	    this.lastJumpLine = null;
 
 	    this.state = {
-	      highlightedLineRange: null
+	      highlightedLineRange: null,
+	      editor: null
 	    };
 
 	    var self = this;
 	    self.closeConditionalPanel = this.closeConditionalPanel.bind(this);
 	    self.onEscape = this.onEscape.bind(this);
 	    self.onGutterClick = this.onGutterClick.bind(this);
 	    self.onGutterContextMenu = this.onGutterContextMenu.bind(this);
 	    self.onScroll = this.onScroll.bind(this);
 	    self.onSearchAgain = this.onSearchAgain.bind(this);
 	    self.onToggleBreakpoint = this.onToggleBreakpoint.bind(this);
-	    self.toggleBreakpoint = this.toggleBreakpoint.bind(this);
 	    self.onMouseOver = (0, _debounce2.default)(this.onMouseOver, 40);
-
-	    // eslint-disable-next-line max-len
-	    self.toggleBreakpointDisabledStatus = this.toggleBreakpointDisabledStatus.bind(this);
 	    self.toggleConditionalPanel = this.toggleConditionalPanel.bind(this);
 	  }
 
 	  componentWillReceiveProps(nextProps) {
 	    // This lifecycle method is responsible for updating the editor
 	    // text.
 	    var selectedSource = nextProps.selectedSource,
 	        selectedLocation = nextProps.selectedLocation;
 
 	    this.clearDebugLine(this.props.selectedFrame);
 
 	    if (nextProps.startPanelSize !== this.props.startPanelSize || nextProps.endPanelSize !== this.props.endPanelSize) {
-	      this.editor.codeMirror.setSize();
+	      this.state.editor.codeMirror.setSize();
 	    }
 
 	    if (!selectedSource) {
 	      if (this.props.selectedSource) {
 	        this.showMessage("");
 	      }
 	    } else if (selectedSource.get("loading")) {
 	      this.showMessage(L10N.getStr("loadingText"));
 	    } else if (selectedSource.get("error")) {
 	      this.showMessage(selectedSource.get("error"));
 	    } else if (this.props.selectedSource !== selectedSource) {
-	      this.showSourceText(selectedSource, selectedLocation);
+	      (0, _editor.showSourceText)(this.state.editor, selectedSource.toJS());
 	    }
 
 	    if (this.props.linesInScope !== nextProps.linesInScope) {
-	      this.editor.codeMirror.operation(() => {
-	        (0, _editor.clearLineClass)(this.editor.codeMirror, "in-scope");
+	      this.state.editor.codeMirror.operation(() => {
+	        (0, _editor.clearLineClass)(this.state.editor.codeMirror, "in-scope");
 	      });
 	    }
 
 	    this.setDebugLine(nextProps.selectedFrame, selectedLocation);
-	    (0, _editor.resizeBreakpointGutter)(this.editor.codeMirror);
+	    (0, _editor.resizeBreakpointGutter)(this.state.editor.codeMirror);
 	  }
 
 	  setupEditor() {
 	    var editor = (0, _editor.createEditor)();
 
 	    // disables the default search shortcuts
 	    editor._initShortcuts = () => {};
 
@@ -24908,17 +24196,16 @@ return /******/ (function(modules) { // 
 	    (0, _devtoolsLaunchpad.debugGlobal)("cm", codeMirror);
 
 	    codeMirror.on("gutterClick", this.onGutterClick);
 
 	    // Set code editor wrapper to be focusable
 	    codeMirrorWrapper.tabIndex = 0;
 	    codeMirrorWrapper.addEventListener("keydown", e => this.onKeyDown(e));
 	    codeMirrorWrapper.addEventListener("mouseover", e => this.onMouseOver(e));
-	    codeMirrorWrapper.addEventListener("click", e => this.onTokenClick(e));
 
 	    var toggleFoldMarkerVisibility = e => {
 	      if (node instanceof HTMLElement) {
 	        node.querySelectorAll(".CodeMirror-guttermarker-subtle").forEach(elem => {
 	          elem.classList.toggle("visible");
 	        });
 	      }
 	    };
@@ -24932,42 +24219,43 @@ return /******/ (function(modules) { // 
 
 	      codeMirror.on("contextmenu", (cm, event) => this.openMenu(event, cm));
 	    } else {
 	      codeMirrorWrapper.addEventListener("contextmenu", event => this.openMenu(event, codeMirror));
 	    }
 
 	    codeMirror.on("scroll", this.onScroll);
 
+	    this.setState({ editor });
 	    return editor;
 	  }
 
 	  componentDidMount() {
 	    this.cbPanel = null;
-	    this.editor = this.setupEditor();
+	    var editor = this.setupEditor();
 
 	    var selectedSource = this.props.selectedSource;
 	    var shortcuts = this.context.shortcuts;
 
 
 	    var searchAgainKey = L10N.getStr("sourceSearch.search.again.key2");
 	    var searchAgainPrevKey = L10N.getStr("sourceSearch.search.againPrev.key2");
 
 	    shortcuts.on("CmdOrCtrl+B", this.onToggleBreakpoint);
 	    shortcuts.on("CmdOrCtrl+Shift+B", this.onToggleBreakpoint);
 	    shortcuts.on("Esc", this.onEscape);
 	    shortcuts.on(searchAgainPrevKey, this.onSearchAgain);
 	    shortcuts.on(searchAgainKey, this.onSearchAgain);
 
-	    (0, _editor.updateDocument)(this.editor, selectedSource);
+	    (0, _editor.updateDocument)(editor, selectedSource);
 	  }
 
 	  componentWillUnmount() {
-	    this.editor.destroy();
-	    this.editor = null;
+	    this.state.editor.destroy();
+	    this.setState({ editor: null });
 
 	    var searchAgainKey = L10N.getStr("sourceSearch.search.again.key2");
 	    var searchAgainPrevKey = L10N.getStr("sourceSearch.search.againPrev.key2");
 	    var shortcuts = this.context.shortcuts;
 	    shortcuts.off("CmdOrCtrl+B");
 	    shortcuts.off("CmdOrCtrl+Shift+B");
 	    shortcuts.off(searchAgainPrevKey);
 	    shortcuts.off(searchAgainKey);
@@ -24999,29 +24287,29 @@ return /******/ (function(modules) { // 
 	    // loaded.
 	    if (selectedSource && selectedSource.has("text")) {
 	      this.highlightLine();
 	    }
 	  }
 
 	  onToggleBreakpoint(key, e) {
 	    e.preventDefault();
-	    var codeMirror = this.editor.codeMirror;
+	    var codeMirror = this.state.editor.codeMirror;
 
 	    var line = (0, _editor.getCursorLine)(codeMirror);
 
 	    if (e.shiftKey) {
-	      this.toggleConditionalPanel(line);
-	    } else {
-	      this.toggleBreakpoint(line);
+	      this.toggleConditionalPanel(line + 1);
+	    } else {
+	      this.props.toggleBreakpoint(line + 1);
 	    }
 	  }
 
 	  onKeyDown(e) {
-	    var codeMirror = this.editor.codeMirror;
+	    var codeMirror = this.state.editor.codeMirror;
 	    var key = e.key,
 	        target = e.target;
 
 	    var codeWrapper = codeMirror.getWrapperElement();
 	    var textArea = codeWrapper.querySelector("textArea");
 
 	    if (key === "Escape" && target == textArea) {
 	      e.stopPropagation();
@@ -25036,53 +24324,39 @@ return /******/ (function(modules) { // 
 
 	  /*
 	   * The default Esc command is overridden in the CodeMirror keymap to allow
 	   * the Esc keypress event to be catched by the toolbox and trigger the
 	   * split console. Restore it here, but preventDefault if and only if there
 	   * is a multiselection.
 	   */
 	  onEscape(key, e) {
-	    if (!this.editor) {
-	      return;
-	    }
-
-	    var codeMirror = this.editor.codeMirror;
+	    if (!this.state.editor) {
+	      return;
+	    }
+
+	    var codeMirror = this.state.editor.codeMirror;
 
 	    if (codeMirror.listSelections().length > 1) {
 	      codeMirror.execCommand("singleSelection");
 	      e.preventDefault();
 	    }
 	  }
 
 	  onScroll() {
 	    this.clearPreviewSelection();
 	  }
 
-	  onTokenClick(e) {
-	    var target = e.target;
-
-	    if (!(0, _devtoolsConfig.isEnabled)("columnBreakpoints") || !e.altKey || !target.parentElement.closest(".CodeMirror-line")) {
-	      return;
-	    }
-
-	    var _getTokenLocation = (0, _editor.getTokenLocation)(this.editor.codeMirror, target),
-	        line = _getTokenLocation.line,
-	        column = _getTokenLocation.column;
-
-	    this.toggleBreakpoint(line - 1, column - 1);
-	  }
-
 	  onSearchAgain(_, e) {
 	    var _props2 = this.props,
 	        query = _props2.query,
 	        searchModifiers = _props2.searchModifiers;
-	    var codeMirror = this.editor.editor.codeMirror;
-
-	    var ctx = { ed: this.editor, cm: codeMirror };
+	    var codeMirror = this.state.editor.editor.codeMirror;
+
+	    var ctx = { ed: this.state.editor, cm: codeMirror };
 
 	    var direction = e.shiftKey ? "prev" : "next";
 	    (0, _editor.traverseResults)(e, ctx, query, direction, searchModifiers.toJS());
 	  }
 
 	  clearPreviewSelection() {
 	    this.props.clearSelection();
 	  }
@@ -25106,196 +24380,130 @@ return /******/ (function(modules) { // 
 	      jumpToMappedLocation,
 	      addExpression,
 	      toggleBlackBox,
 	      onGutterContextMenu: this.onGutterContextMenu
 	    });
 	  }
 
 	  onGutterClick(cm, line, gutter, ev) {
-	    var selectedSource = this.props.selectedSource;
+	    var _props4 = this.props,
+	        selectedSource = _props4.selectedSource,
+	        toggleBreakpoint = _props4.toggleBreakpoint;
 
 	    // ignore right clicks in the gutter
 
 	    if (ev.ctrlKey && ev.button === 0 || ev.which === 3 || selectedSource && selectedSource.get("isBlackBoxed")) {
 	      return;
 	    }
 
 	    if (this.isCbPanelOpen()) {
 	      return this.closeConditionalPanel();
 	    }
 
 	    if (gutter !== "CodeMirror-foldgutter") {
-	      this.toggleBreakpoint(line);
+	      toggleBreakpoint(line + 1);
 	    }
 	  }
 
 	  onGutterContextMenu(event) {
-	    var selectedSource = this.props.selectedSource;
+	    var _props5 = this.props,
+	        selectedSource = _props5.selectedSource,
+	        breakpoints = _props5.breakpoints,
+	        toggleBreakpoint = _props5.toggleBreakpoint,
+	        toggleDisabledBreakpoint = _props5.toggleDisabledBreakpoint;
 
 
 	    if (selectedSource && selectedSource.get("isBlackBoxed")) {
 	      event.preventDefault();
 	      return;
 	    }
 
-	    var line = this.editor.codeMirror.lineAtHeight(event.clientY);
-	    var bp = (0, _editor.breakpointAtLocation)(this.props.breakpoints, { line });
+	    var line = (0, _editor.lineAtHeight)(this.state.editor, event);
+	    var breakpoint = breakpoints.find(bp => bp.location.line === line);
+
 	    (0, _GutterMenu2.default)({
 	      event,
 	      line,
-	      bp,
-	      toggleBreakpoint: this.toggleBreakpoint,
+	      breakpoint,
+	      toggleBreakpoint,
+	      toggleDisabledBreakpoint,
+
 	      showConditionalPanel: this.toggleConditionalPanel,
-	      toggleBreakpointDisabledStatus: this.toggleBreakpointDisabledStatus,
 	      isCbPanelOpen: this.isCbPanelOpen(),
 	      closeConditionalPanel: this.closeConditionalPanel
 	    });
 	  }
 
 	  onMouseOver(e) {
 	    var target = e.target;
 
 	    if (this.inSelectedFrameSource()) {
-	      (0, _editor.updateSelection)(target, this.editor, this.props);
+	      (0, _editor.updateSelection)(target, this.state.editor, this.props);
 	    }
 	  }
 
 	  toggleConditionalPanel(line) {
 	    if (this.isCbPanelOpen()) {
 	      return this.closeConditionalPanel();
 	    }
 
-	    var _props4 = this.props,
-	        selectedLocation = _props4.selectedLocation,
-	        setBreakpointCondition = _props4.setBreakpointCondition,
-	        breakpoints = _props4.breakpoints;
+	    var _props6 = this.props,
+	        selectedLocation = _props6.selectedLocation,
+	        setBreakpointCondition = _props6.setBreakpointCondition,
+	        breakpoints = _props6.breakpoints;
 
 	    var sourceId = selectedLocation ? selectedLocation.sourceId : "";
 
-	    var bp = (0, _editor.breakpointAtLocation)(breakpoints, { line });
-	    var location = { sourceId, line: line + 1 };
-	    var condition = bp ? bp.condition : "";
-
-	    var setBreakpoint = value => setBreakpointCondition(location, {
-	      condition: value,
-	      getTextForLine: l => (0, _editor.getTextForLine)(this.editor.codeMirror, l)
-	    });
+	    var breakpoint = breakpoints.find(bp => bp.location.line === line);
+	    var location = { sourceId, line };
+	    var condition = breakpoint ? breakpoint.condition : "";
 
 	    var panel = (0, _ConditionalPanel.renderConditionalPanel)({
 	      condition,
-	      setBreakpoint,
+	      setBreakpoint: value => setBreakpointCondition(location, { condition: value }),
 	      closePanel: this.closeConditionalPanel
 	    });
 
-	    this.cbPanel = this.editor.codeMirror.addLineWidget(line, panel, {
+	    this.cbPanel = this.state.editor.codeMirror.addLineWidget(line, panel, {
 	      coverGutter: true,
 	      noHScroll: false
 	    });
 	    this.cbPanel.node.querySelector("input").focus();
 	  }
 
 	  closeConditionalPanel() {
 	    this.cbPanel.clear();
 	    this.cbPanel = null;
 	  }
 
 	  isCbPanelOpen() {
 	    return !!this.cbPanel;
 	  }
 
-	  toggleBreakpoint(line) {
-	    var column = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
-	    var _props5 = this.props,
-	        selectedSource = _props5.selectedSource,
-	        selectedLocation = _props5.selectedLocation,
-	        breakpoints = _props5.breakpoints,
-	        addBreakpoint = _props5.addBreakpoint,
-	        removeBreakpoint = _props5.removeBreakpoint;
-
-	    var bp = (0, _editor.breakpointAtLocation)(breakpoints, { line, column });
-
-	    if (bp && bp.loading || !selectedLocation || !selectedSource) {
-	      return;
-	    }
-
-	    var sourceId = selectedLocation.sourceId;
-
-
-	    if (bp) {
-	      // NOTE: it's possible the breakpoint has slid to a column
-	      column = column || bp.location.column;
-	      removeBreakpoint({
-	        sourceId: sourceId,
-	        line: line + 1,
-	        column
-	      });
-	    } else {
-	      addBreakpoint({
-	        sourceId: sourceId,
-	        sourceUrl: selectedSource.get("url"),
-	        line: line + 1,
-	        column: column
-	      },
-	      // Pass in a function to get line text because the breakpoint
-	      // may slide and it needs to compute the value at the new
-	      // line.
-	      { getTextForLine: l => (0, _editor.getTextForLine)(this.editor.codeMirror, l) });
-	    }
-	  }
-
-	  toggleBreakpointDisabledStatus(line) {
-	    var bp = (0, _editor.breakpointAtLocation)(this.props.breakpoints, { line });
-	    var selectedLocation = this.props.selectedLocation;
-
-
-	    if (bp && bp.loading || !selectedLocation) {
-	      return;
-	    }
-
-	    var sourceId = selectedLocation.sourceId;
-
-
-	    if (!bp) {
-	      throw new Error("attempt to disable breakpoint that does not exist");
-	    }
-
-	    if (!bp.disabled) {
-	      this.props.disableBreakpoint({
-	        sourceId: sourceId,
-	        line: line + 1
-	      });
-	    } else {
-	      this.props.enableBreakpoint({
-	        sourceId: sourceId,
-	        line: line + 1
-	      });
-	    }
-	  }
-
 	  clearDebugLine(selectedFrame) {
 	    if (selectedFrame) {
 	      var line = selectedFrame.location.line;
 	      if (this.debugExpression) {
 	        this.debugExpression.clear();
 	      }
 
-	      this.editor.codeMirror.removeLineClass(line - 1, "line", "new-debug-line");
+	      this.state.editor.codeMirror.removeLineClass(line - 1, "line", "new-debug-line");
 	    }
 	  }
 
 	  setDebugLine(selectedFrame, selectedLocation) {
 	    if (selectedFrame && selectedLocation && selectedFrame.location.sourceId === selectedLocation.sourceId) {
 	      var _selectedFrame$locati = selectedFrame.location,
 	          line = _selectedFrame$locati.line,
 	          column = _selectedFrame$locati.column;
 
-	      this.editor.codeMirror.addLineClass(line - 1, "line", "new-debug-line");
-
-	      this.debugExpression = (0, _editor.markText)(this.editor, "debug-expression", {
+	      this.state.editor.codeMirror.addLineClass(line - 1, "line", "new-debug-line");
+
+	      this.debugExpression = (0, _editor.markText)(this.state.editor, "debug-expression", {
 	        start: { line, column },
 	        end: { line, column: null }
 	      });
 	    }
 	  }
 
 	  // If the location has changed and a specific line is requested,
 	  // move to that line and flash it.
@@ -25304,125 +24512,68 @@ return /******/ (function(modules) { // 
 	      return;
 	    }
 
 	    // Make sure to clean up after ourselves. Not only does this
 	    // cancel any existing animation, but it avoids it from
 	    // happening ever again (in case CodeMirror re-applies the
 	    // class, etc).
 	    if (this.lastJumpLine) {
-	      (0, _editor.clearLineClass)(this.editor.codeMirror, "highlight-line");
+	      (0, _editor.clearLineClass)(this.state.editor.codeMirror, "highlight-line");
 	    }
 
 	    var line = this.pendingJumpLine;
-	    this.editor.alignLine(line);
+	    this.state.editor.alignLine(line);
 
 	    // We only want to do the flashing animation if it's not a debug
 	    // line, which has it's own styling.
 	    // Also, if it the first time the debugger is being loaded, we don't want
 	    // to flash the previously saved selected line.
 	    if (this.lastJumpLine && (!this.props.selectedFrame || this.props.selectedFrame.location.line !== line)) {
-	      this.editor.codeMirror.addLineClass(line - 1, "line", "highlight-line");
+	      this.state.editor.codeMirror.addLineClass(line - 1, "line", "highlight-line");
 	    }
 
 	    this.lastJumpLine = line;
 	    this.pendingJumpLine = null;
 	  }
 
-	  setText(text) {
-	    if (!text || !this.editor) {
-	      return;
-	    }
-
-	    this.editor.setText(text);
-	  }
-
 	  showMessage(msg) {
-	    this.editor.replaceDocument(this.editor.createDocument());
-	    this.setText(msg);
-	    this.editor.setMode({ name: "text" });
-	  }
-
-	  /**
-	   * Handle getting the source document or creating a new
-	   * document with the correct mode and text.
-	   *
-	   */
-	  showSourceText(source, selectedLocation) {
-	    if (!selectedLocation) {
-	      return;
-	    }
-
-	    var doc = (0, _editor.getDocument)(selectedLocation.sourceId);
-	    if (doc) {
-	      this.editor.replaceDocument(doc);
-	      return doc;
-	    }
-
-	    doc = this.editor.createDocument();
-	    (0, _editor.setDocument)(selectedLocation.sourceId, doc);
-	    this.editor.replaceDocument(doc);
-
-	    this.setText(source.get("text"));
-	    this.editor.setMode((0, _source.getMode)(source.toJS()));
+	    this.state.editor.replaceDocument(this.state.editor.createDocument());
+	    this.state.editor.setText(msg);
+	    this.state.editor.setMode({ name: "text" });
 	  }
 
 	  renderHighlightLines() {
 	    var highlightedLineRange = this.props.highlightedLineRange;
 
 
 	    if (!highlightedLineRange) {
 	      return;
 	    }
 
 	    return HighlightLines({
-	      editor: this.editor,
+	      editor: this.state.editor,
 	      highlightedLineRange
 	    });
 	  }
 
-	  renderBreakpoints() {
-	    var _props6 = this.props,
-	        breakpoints = _props6.breakpoints,
-	        selectedSource = _props6.selectedSource;
-
-
-	    if (!selectedSource || selectedSource.get("loading") || !breakpoints || selectedSource && selectedSource.get("isBlackBoxed")) {
-	      return;
-	    }
-
-	    var breakpointMarkers = breakpoints.valueSeq().filter(b => (0, _devtoolsConfig.isEnabled)("columnBreakpoints") ? !b.location.column : true).map(bp => Breakpoint({
-	      key: (0, _breakpoint.makeLocationId)(bp.location),
-	      breakpoint: bp,
-	      editor: this.editor && this.editor.codeMirror
-	    }));
-
-	    var columnBreakpointBookmarks = breakpoints.valueSeq().filter(b => (0, _devtoolsConfig.isEnabled)("columnBreakpoints") ? b.location.column : false).map(bp => ColumnBreakpoint({
-	      key: (0, _breakpoint.makeLocationId)(bp.location),
-	      breakpoint: bp,
-	      editor: this.editor && this.editor.codeMirror
-	    }));
-
-	    return breakpointMarkers.concat(columnBreakpointBookmarks);
-	  }
-
 	  renderHitCounts() {
 	    var _props7 = this.props,
 	        hitCount = _props7.hitCount,
 	        selectedSource = _props7.selectedSource;
 
 
-	    if (!selectedSource || selectedSource.get("loading") || !hitCount || !this.editor) {
+	    if (!selectedSource || selectedSource.get("loading") || !hitCount || !this.state.editor) {
 	      return;
 	    }
 
 	    return hitCount.filter(marker => marker.get("count") > 0).map(marker => HitMarker({
 	      key: marker.get("line"),
 	      hitData: marker.toJS(),
-	      editor: this.editor.codeMirror
+	      editor: this.state.editor.codeMirror
 	    }));
 	  }
 
 	  getInlineEditorStyles() {
 	    var _props8 = this.props,
 	        selectedSource = _props8.selectedSource,
 	        horizontal = _props8.horizontal,
 	        searchOn = _props8.searchOn;
@@ -25444,17 +24595,17 @@ return /******/ (function(modules) { // 
 	    };
 	  }
 
 	  renderPreview() {
 	    var _props9 = this.props,
 	        selectedSource = _props9.selectedSource,
 	        selection = _props9.selection;
 
-	    if (!this.editor || !selectedSource) {
+	    if (!this.state.editor || !selectedSource) {
 	      return null;
 	    }
 
 	    if (!selection || selection.updating) {
 	      return;
 	    }
 
 	    var result = selection.result,
@@ -25464,46 +24615,55 @@ return /******/ (function(modules) { // 
 
 	    var value = result;
 	    if (typeof value == "undefined" || value.optimizedOut) {
 	      return;
 	    }
 
 	    return Preview({
 	      value,
-	      editor: this.editor,
+	      editor: this.state.editor,
 	      location: location,
 	      expression: expression,
 	      popoverPos: cursorPos,
 	      onClose: () => this.clearPreviewSelection()
 	    });
 	  }
 
 	  renderInScopeLines() {
 	    var linesInScope = this.props.linesInScope;
 
 	    if (!(0, _devtoolsConfig.isEnabled)("highlightScopeLines") || !linesInScope || !this.inSelectedFrameSource()) {
 	      return;
 	    }
 
-	    this.editor.codeMirror.operation(() => {
+	    this.state.editor.codeMirror.operation(() => {
 	      linesInScope.forEach(line => {
-	        this.editor.codeMirror.addLineClass(line - 1, "line", "in-scope");
+	        this.state.editor.codeMirror.addLineClass(line - 1, "line", "in-scope");
 	      });
 	    });
 	  }
 
 	  inSelectedFrameSource() {
 	    var _props10 = this.props,
 	        selectedLocation = _props10.selectedLocation,
 	        selectedFrame = _props10.selectedFrame;
 
 	    return selectedFrame && selectedLocation && selectedFrame.location.sourceId == selectedLocation.sourceId;
 	  }
 
+	  renderCallSites() {
+	    var editor = this.state.editor;
+
+	    if (!editor || !(0, _devtoolsConfig.isEnabled)("columnBreakpoints")) {
+	      return null;
+	    }
+	    return CallSites({ editor });
+	  }
+
 	  render() {
 	    var _props11 = this.props,
 	        selectSource = _props11.selectSource,
 	        selectedSource = _props11.selectedSource,
 	        highlightLineRange = _props11.highlightLineRange,
 	        clearHighlightLineRange = _props11.clearHighlightLineRange,
 	        coverageOn = _props11.coverageOn,
 	        pauseData = _props11.pauseData,
@@ -25511,32 +24671,32 @@ return /******/ (function(modules) { // 
 
 
 	    return _react.DOM.div({
 	      className: (0, _classnames2.default)("editor-wrapper", {
 	        "coverage-on": coverageOn,
 	        paused: !!pauseData && (0, _devtoolsConfig.isEnabled)("highlightScopeLines")
 	      })
 	    }, SearchBar({
-	      editor: this.editor,
+	      editor: this.state.editor,
 	      selectSource,
 	      selectedSource,
 	      highlightLineRange,
 	      clearHighlightLineRange
 	    }), _react.DOM.div({
 	      className: "editor-mount devtools-monospace",
 	      style: this.getInlineEditorStyles()
-	    }), this.renderHighlightLines(), this.renderBreakpoints(), this.renderInScopeLines(), this.renderHitCounts(), Footer({ editor: this.editor, horizontal }), this.renderPreview());
+	    }), this.renderHighlightLines(), this.renderInScopeLines(), this.renderHitCounts(), Footer({ editor: this.state.editor, horizontal }), this.renderPreview(), this.renderCallSites(), Breakpoints({ editor: this.state.editor }));
 	  }
 	}
 
 	Editor.displayName = "Editor";
 
 	Editor.propTypes = {
-	  breakpoints: _reactImmutableProptypes2.default.map.isRequired,
+	  breakpoints: _reactImmutableProptypes2.default.map,
 	  hitCount: _react.PropTypes.object,
 	  selectedLocation: _react.PropTypes.object,
 	  selectedSource: _reactImmutableProptypes2.default.map,
 	  highlightLineRange: _react.PropTypes.func,
 	  clearHighlightLineRange: _react.PropTypes.func,
 	  highlightedLineRange: _react.PropTypes.object,
 	  searchOn: _react.PropTypes.bool,
 	  addBreakpoint: _react.PropTypes.func.isRequired,
@@ -25546,59 +24706,56 @@ return /******/ (function(modules) { // 
 	  setBreakpointCondition: _react.PropTypes.func.isRequired,
 	  selectSource: _react.PropTypes.func,
 	  jumpToMappedLocation: _react.PropTypes.func,
 	  toggleBlackBox: _react.PropTypes.func,
 	  showSource: _react.PropTypes.func,
 	  coverageOn: _react.PropTypes.bool,
 	  pauseData: _react.PropTypes.object,
 	  selectedFrame: _react.PropTypes.object,
-	  getExpression: _react.PropTypes.func.isRequired,
 	  addExpression: _react.PropTypes.func.isRequired,
 	  horizontal: _react.PropTypes.bool,
 	  query: _react.PropTypes.string.isRequired,
 	  searchModifiers: _reactImmutableProptypes2.default.recordOf({
 	    caseSensitive: _react.PropTypes.bool.isRequired,
 	    regexMatch: _react.PropTypes.bool.isRequired,
 	    wholeWord: _react.PropTypes.bool.isRequired
 	  }).isRequired,
 	  selection: _react.PropTypes.object,
 	  startPanelSize: _react.PropTypes.number,
 	  endPanelSize: _react.PropTypes.number,
 	  clearSelection: _react.PropTypes.func.isRequired,
-	  linesInScope: _react.PropTypes.array
+	  linesInScope: _react.PropTypes.array,
+	  toggleBreakpoint: _react.PropTypes.func.isRequired,
+	  toggleDisabledBreakpoint: _react.PropTypes.func.isRequired
 	};
 
 	Editor.contextTypes = {
 	  shortcuts: _react.PropTypes.object
 	};
 
-	var expressionsSel = state => state.expressions.expressions;
-	var getExpressionSel = (0, _reselect.createSelector)(expressionsSel, expressions => input => expressions.find(exp => exp.input == input));
-
 	exports.default = (0, _reactRedux.connect)(state => {
 	  var selectedLocation = (0, _selectors.getSelectedLocation)(state);
 	  var sourceId = selectedLocation && selectedLocation.sourceId;
 	  var selectedSource = (0, _selectors.getSelectedSource)(state);
 
 	  return {
 	    selectedLocation,
 	    selectedSource,
 	    highlightedLineRange: (0, _selectors.getHighlightedLineRange)(state),
-	    searchOn: (0, _selectors.getFileSearchState)(state),
+	    searchOn: (0, _selectors.getActiveSearchState)(state) === "file",
 	    loadedObjects: (0, _selectors.getLoadedObjects)(state),
-	    breakpoints: (0, _selectors.getBreakpointsForSource)(state, sourceId || ""),
+	    breakpoints: (0, _selectors.getVisibleBreakpoints)(state),
 	    hitCount: (0, _selectors.getHitCountForSource)(state, sourceId),
 	    selectedFrame: (0, _selectors.getSelectedFrame)(state),
-	    getExpression: getExpressionSel(state),
 	    pauseData: (0, _selectors.getPause)(state),
 	    coverageOn: (0, _selectors.getCoverageEnabled)(state),
 	    query: (0, _selectors.getFileSearchQueryState)(state),
 	    searchModifiers: (0, _selectors.getFileSearchModifierState)(state),
-	    linesInScope: (0, _linesInScope2.default)(state),
+	    linesInScope: (0, _selectors.getInScopeLines)(state),
 	    selection: (0, _selectors.getSelection)(state)
 	  };
 	}, dispatch => (0, _redux.bindActionCreators)(_actions2.default, dispatch))(Editor);
 
 /***/ },
 /* 427 */
 /***/ function(module, exports, __webpack_require__) {
 
@@ -25863,18 +25020,16 @@ return /******/ (function(modules) { // 
 	var _react = __webpack_require__(2);
 
 	var _reactDom = __webpack_require__(31);
 
 	var _reactRedux = __webpack_require__(151);
 
 	var _redux = __webpack_require__(3);
 
-	var _fuzzaldrinPlus = __webpack_require__(161);
-
 	var _Svg = __webpack_require__(344);
 
 	var _Svg2 = _interopRequireDefault(_Svg);
 
 	var _actions = __webpack_require__(244);
 
 	var _actions2 = _interopRequireDefault(_actions);
 
@@ -25895,50 +25050,32 @@ return /******/ (function(modules) { // 
 	var _debounce2 = _interopRequireDefault(_debounce);
 
 	var _devtoolsSourceEditor = __webpack_require__(994);
 
 	var _SearchInput2 = __webpack_require__(377);
 
 	var _SearchInput3 = _interopRequireDefault(_SearchInput2);
 
-	var _ResultList2 = __webpack_require__(383);
-
-	var _ResultList3 = _interopRequireDefault(_ResultList2);
-
 	__webpack_require__(653);
 
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 	function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
 
 	var SearchInput = (0, _react.createFactory)(_SearchInput3.default);
 
-	var ResultList = (0, _react.createFactory)(_ResultList3.default);
-
-	function formatSymbol(symbol) {
-	  return {
-	    id: `${symbol.name}:${symbol.location.start.line}`,
-	    title: symbol.name,
-	    subtitle: `:${symbol.location.start.line}`,
-	    value: symbol.name,
-	    location: symbol.location
-	  };
-	}
-
 	function getShortcuts() {
 	  var searchAgainKey = L10N.getStr("sourceSearch.search.again.key2");
 	  var searchAgainPrevKey = L10N.getStr("sourceSearch.search.againPrev.key2");
-	  var fnSearchKey = L10N.getStr("symbolSearch.search.key2");
 	  var searchKey = L10N.getStr("sourceSearch.search.key2");
 
 	  return {
 	    shiftSearchAgainShortcut: searchAgainPrevKey,
 	    searchAgainShortcut: searchAgainKey,
-	    symbolSearchShortcut: fnSearchKey,
 	    searchShortcut: searchKey
 	  };
 	}
 
 	class SearchBar extends _react.Component {
 
 	  constructor(props) {
 	    super(props);
@@ -25948,91 +25085,69 @@ return /******/ (function(modules) { // 
 	      index: -1
 	    };
 
 	    var self = this;
 	    self.onEscape = this.onEscape.bind(this);
 	    self.clearSearch = this.clearSearch.bind(this);
 	    self.closeSearch = this.closeSearch.bind(this);
 	    self.toggleSearch = this.toggleSearch.bind(this);
-	    self.toggleSymbolSearch = this.toggleSymbolSearch.bind(this);
-	    self.toggleTextSearch = this.toggleTextSearch.bind(this);
 	    self.setSearchValue = this.setSearchValue.bind(this);
 	    self.selectSearchInput = this.selectSearchInput.bind(this);
 	    self.searchInput = this.searchInput.bind(this);
-	    self.updateSymbolSearchResults = this.updateSymbolSearchResults.bind(this);
 	    self.doSearch = this.doSearch.bind(this);
 	    self.searchContents = this.searchContents.bind(this);
-	    self.traverseSymbolResults = this.traverseSymbolResults.bind(this);
-	    self.traverseCodeResults = this.traverseCodeResults.bind(this);
 	    self.traverseResults = this.traverseResults.bind(this);
-	    self.selectResultItem = this.selectResultItem.bind(this);
-	    self.onSelectResultItem = this.onSelectResultItem.bind(this);
 	    self.onChange = this.onChange.bind(this);
 	    self.onKeyUp = this.onKeyUp.bind(this);
-	    self.onKeyDown = this.onKeyDown.bind(this);
 	    self.buildSummaryMsg = this.buildSummaryMsg.bind(this);
-	    self.buildPlaceHolder = this.buildPlaceHolder.bind(this);
 	    self.renderSearchModifiers = this.renderSearchModifiers.bind(this);
-	    self.renderSearchTypeToggle = this.renderSearchTypeToggle.bind(this);
-	    self.renderBottomBar = this.renderBottomBar.bind(this);
-	    self.renderResults = this.renderResults.bind(this);
 	  }
 
 	  componentWillUnmount() {
 	    var shortcuts = this.context.shortcuts;
 
 	    var _getShortcuts = getShortcuts(),
 	        searchShortcut = _getShortcuts.searchShortcut,
 	        searchAgainShortcut = _getShortcuts.searchAgainShortcut,
-	        shiftSearchAgainShortcut = _getShortcuts.shiftSearchAgainShortcut,
-	        symbolSearchShortcut = _getShortcuts.symbolSearchShortcut;
+	        shiftSearchAgainShortcut = _getShortcuts.shiftSearchAgainShortcut;
 
 	    shortcuts.off(searchShortcut);
 	    shortcuts.off("Escape");
 	    shortcuts.off(searchAgainShortcut);
 	    shortcuts.off(shiftSearchAgainShortcut);
-	    shortcuts.off(symbolSearchShortcut);
 	  }
 
 	  componentDidMount() {
 	    // overwrite searchContents with a debounced version to reduce the
 	    // frequency of queries which improves perf on large files
 	    // $FlowIgnore
 	    this.searchContents = (0, _debounce2.default)(this.searchContents, 100);
 
 	    var shortcuts = this.context.shortcuts;
 
 	    var _getShortcuts2 = getShortcuts(),
 	        searchShortcut = _getShortcuts2.searchShortcut,
 	        searchAgainShortcut = _getShortcuts2.searchAgainShortcut,
-	        shiftSearchAgainShortcut = _getShortcuts2.shiftSearchAgainShortcut,
-	        symbolSearchShortcut = _getShortcuts2.symbolSearchShortcut;
+	        shiftSearchAgainShortcut = _getShortcuts2.shiftSearchAgainShortcut;
 
 	    shortcuts.on(searchShortcut, (_, e) => this.toggleSearch(e));
 	    shortcuts.on("Escape", (_, e) => this.onEscape(e));
 
 	    shortcuts.on(shiftSearchAgainShortcut, (_, e) => this.traverseResults(e, true));
 
 	    shortcuts.on(searchAgainShortcut, (_, e) => this.traverseResults(e, false));
-
-	    shortcuts.on(symbolSearchShortcut, (_, e) => this.toggleSymbolSearch(e, {
-	      toggle: false,
-	      searchType: "functions"
-	    }));
 	  }
 
 	  componentDidUpdate(prevProps, prevState) {
 	    var _props = this.props,
 	        selectedSource = _props.selectedSource,
 	        query = _props.query,
 	        modifiers = _props.modifiers,
-	        searchOn = _props.searchOn,
-	        symbolSearchOn = _props.symbolSearchOn,
-	        selectedSymbolType = _props.selectedSymbolType;
+	        searchOn = _props.searchOn;
 
 	    var searchInput = this.searchInput();
 
 	    if (searchInput) {
 	      searchInput.focus();
 	    }
 
 	    if (this.refs.resultList && this.refs.resultList.refs) {
@@ -26041,20 +25156,17 @@ return /******/ (function(modules) { // 
 
 	    var hasLoaded = selectedSource && !selectedSource.get("loading");
 	    var wasLoading = prevProps.selectedSource && prevProps.selectedSource.get("loading");
 
 	    var doneLoading = wasLoading && hasLoaded;
 	    var changedFiles = selectedSource != prevProps.selectedSource && hasLoaded;
 	    var modifiersUpdated = modifiers && !modifiers.equals(prevProps.modifiers);
 
-	    var isOpen = searchOn || symbolSearchOn;
-	    var changedSearchType = selectedSymbolType != prevProps.selectedSymbolType || symbolSearchOn != prevProps.symbolSearchOn;
-
-	    if (isOpen && (doneLoading || changedFiles || modifiersUpdated || changedSearchType)) {
+	    if (searchOn && (doneLoading || changedFiles || modifiersUpdated)) {
 	      this.doSearch(query);
 	    }
 	  }
 
 	  onEscape(e) {
 	    this.closeSearch(e);
 	  }
 
@@ -26069,110 +25181,49 @@ return /******/ (function(modules) { // 
 	      (0, _editor.removeOverlay)(ctx, query, modifiers.toJS());
 	    }
 	  }
 
 	  closeSearch(e) {
 	    var _props3 = this.props,
 	        editor = _props3.editor,
 	        setFileSearchQuery = _props3.setFileSearchQuery,
-	        searchOn = _props3.searchOn,
-	        symbolSearchOn = _props3.symbolSearchOn;
-
-
-	    if (editor && (searchOn || symbolSearchOn)) {
+	        searchOn = _props3.searchOn;
+
+
+	    if (editor && searchOn) {
 	      setFileSearchQuery("");
 	      this.clearSearch();
-	      this.props.toggleFileSearch(false);
-	      this.props.toggleSymbolSearch(false);
-	      this.props.setSelectedSymbolType("functions");
+	      this.props.setActiveSearch();
 	      this.props.clearHighlightLineRange();
 	      e.stopPropagation();
 	      e.preventDefault();
 	    }
 	  }
 
 	  toggleSearch(e) {
 	    e.stopPropagation();
 	    e.preventDefault();
-	    var _props4 = this.props,
-	        editor = _props4.editor,
-	        symbolSearchOn = _props4.symbolSearchOn;
+	    var editor = this.props.editor;
 
 
 	    if (!this.props.searchOn) {
-	      this.props.toggleFileSearch();
-	    }
-
-	    if (symbolSearchOn) {
-	      this.clearSearch();
-	      this.props.toggleSymbolSearch(false);
-	      this.props.setSelectedSymbolType("functions");
+	      this.props.setActiveSearch("file");
 	    }
 
 	    if (this.props.searchOn && editor) {
 	      var selection = editor.codeMirror.getSelection();
 	      this.setSearchValue(selection);
 	      if (selection !== "") {
 	        this.doSearch(selection);
 	      }
 	      this.selectSearchInput();
 	    }
 	  }
 
-	  ignoreEvent(e) {
-	    if (e) {
-	      e.preventDefault();
-	      e.stopPropagation();
-	    }
-	  }
-
-	  toggleSymbolSearch(e) {
-	    var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
-	        toggle = _ref.toggle,
-	        searchType = _ref.searchType;
-
-	    var selectedSource = this.props.selectedSource;
-
-	    if (!selectedSource) {
-	      return;
-	    }
-	    this.ignoreEvent(e);
-
-	    if (this.props.symbolSearchOn) {
-	      if (toggle) {
-	        this.props.toggleSymbolSearch(false);
-	      } else {
-	        this.props.setSelectedSymbolType(searchType);
-	      }
-	      return;
-	    }
-
-	    this.clearSearch();
-	    this.props.toggleSymbolSearch(true);
-	    this.props.setSelectedSymbolType(searchType);
-	  }
-
-	  toggleTextSearch(e) {
-	    var selectedSource = this.props.selectedSource;
-
-	    this.ignoreEvent(e);
-
-	    if (!selectedSource) {
-	      return;
-	    }
-
-	    if (!this.props.searchOn) {
-	      this.props.toggleFileSearch();
-	    }
-
-	    this.clearSearch();
-	    this.props.toggleSymbolSearch(false);
-	  }
-
 	  setSearchValue(value) {
 	    var searchInput = this.searchInput();
 	    if (value == "" || !searchInput) {
 	      return;
 	    }
 
 	    searchInput.value = value;
 	  }
@@ -26191,443 +25242,193 @@ return /******/ (function(modules) { // 
 	      var input = node.querySelector("input");
 	      if (input instanceof HTMLInputElement) {
 	        return input;
 	      }
 	    }
 	    return null;
 	  }
 
-	  updateSymbolSearchResults(query) {
-	    var _props5 = this.props,
-	        selectedSource = _props5.selectedSource,
-	        updateSearchResults = _props5.updateSearchResults,
-	        updateSymbolSearchResults = _props5.updateSymbolSearchResults,
-	        selectedSymbolType = _props5.selectedSymbolType,
-	        symbols = _props5.symbols;
-
-
-	    if (query == "" || !selectedSource) {
-	      return;
-	    }
-
-	    var symbolSearchResults = (0, _fuzzaldrinPlus.filter)(symbols[selectedSymbolType], query, {
-	      key: "value"
-	    });
-
-	    updateSearchResults({ count: symbolSearchResults.length });
-	    updateSymbolSearchResults(symbolSearchResults);
-	  }
-
 	  doSearch(query) {
-	    var _props6 = this.props,
-	        selectedSource = _props6.selectedSource,
-	        setFileSearchQuery = _props6.setFileSearchQuery,
-	        ed = _props6.editor;
+	    var _props4 = this.props,
+	        selectedSource = _props4.selectedSource,
+	        setFileSearchQuery = _props4.setFileSearchQuery;
 
 	    if (!selectedSource || !selectedSource.get("text")) {
 	      return;
 	    }
 
 	    setFileSearchQuery(query);
 
-	    if (this.props.symbolSearchOn) {
-	      return this.updateSymbolSearchResults(query);
-	    } else if (ed) {
-	      this.searchContents(query);
-	    }
+	    this.searchContents(query);
+	  }
+
+	  updateSearchResults(characterIndex, line, matches) {
+	    var matchIndex = matches.findIndex(elm => elm.line === line && elm.ch === characterIndex);
+	    this.props.updateSearchResults({
+	      matches,
+	      matchIndex,
+	      count: matches.length,
+	      index: characterIndex
+	    });
 	  }
 
 	  searchContents(query) {
 	    var _this = this;
 
 	    return _asyncToGenerator(function* () {
-	      var _props7 = _this.props,
-	          selectedSource = _props7.selectedSource,
-	          modifiers = _props7.modifiers,
-	          ed = _props7.editor,
-	          index = _props7.searchResults.index;
+	      var _props5 = _this.props,
+	          selectedSource = _props5.selectedSource,
+	          modifiers = _props5.modifiers,
+	          ed = _props5.editor;
 
 
 	      if (!ed || !selectedSource || !selectedSource.get("text") || !modifiers) {
 	        return;
 	      }
 
 	      var ctx = { ed, cm: ed.codeMirror };
 
-	      var newCount = yield (0, _search.countMatches)(query, selectedSource.get("text"), modifiers.toJS());
-
-	      if (index == -1) {
-	        (0, _editor.clearIndex)(ctx, query, modifiers.toJS());
-	      }
-
-	      var newIndex = (0, _editor.find)(ctx, query, true, modifiers.toJS());
-	      _this.props.updateSearchResults({
-	        count: newCount,
-	        index: newIndex
-	      });
+	      var _modifiers = modifiers.toJS();
+	      var matches = yield (0, _search.getMatches)(query, selectedSource.get("text"), _modifiers);
+
+	      var _find = (0, _editor.find)(ctx, query, true, _modifiers),
+	          ch = _find.ch,
+	          line = _find.line;
+
+	      _this.updateSearchResults(ch, line, matches);
 	    })();
 	  }
 
-	  traverseSymbolResults(rev) {
-	    var selectedResultIndex = this.state.selectedResultIndex;
-
-	    var searchResults = this.props.symbolSearchResults;
-	    var resultCount = searchResults.length;
-
-	    if (rev) {
-	      var nextResultIndex = Math.max(0, selectedResultIndex - 1);
-
-	      if (selectedResultIndex === 0) {
-	        nextResultIndex = resultCount - 1;
-	      }
-	      this.setState({ selectedResultIndex: nextResultIndex });
-	      this.onSelectResultItem(searchResults[nextResultIndex]);
-	    } else {
-	      var _nextResultIndex = Math.min(resultCount - 1, selectedResultIndex + 1);
-
-	      if (selectedResultIndex === resultCount - 1) {
-	        _nextResultIndex = 0;
-	      }
-	      this.setState({ selectedResultIndex: _nextResultIndex });
-	      this.onSelectResultItem(searchResults[_nextResultIndex]);
-	    }
-	  }
-
-	  traverseCodeResults(rev) {
+	  traverseResults(e, rev) {
+	    e.stopPropagation();
+	    e.preventDefault();
 	    var ed = this.props.editor;
 
 	    if (!ed) {
 	      return;
 	    }
 
 	    var ctx = { ed, cm: ed.codeMirror };
 
-	    var _props8 = this.props,
-	        query = _props8.query,
-	        modifiers = _props8.modifiers,
-	        updateSearchResults = _props8.updateSearchResults,
-	        _props8$searchResults = _props8.searchResults,
-	        count = _props8$searchResults.count,
-	        index = _props8$searchResults.index;
+	    var _props6 = this.props,
+	        query = _props6.query,
+	        modifiers = _props6.modifiers,
+	        matches = _props6.searchResults.matches;
 
 
 	    if (query === "") {
-	      this.props.toggleFileSearch(true);
-	    }
-
-	    if (index == -1 && modifiers) {
-	      (0, _editor.clearIndex)(ctx, query, modifiers.toJS());
+	      this.props.setActiveSearch("file");
 	    }
 
 	    if (modifiers) {
-	      var findFnc = rev ? _editor.findPrev : _editor.findNext;
-	      var newIndex = findFnc(ctx, query, true, modifiers.toJS());
-	      updateSearchResults({
-	        index: newIndex,
-	        count
-	      });
-	    }
-	  }
-
-	  traverseResults(e, rev) {
-	    e.stopPropagation();
-	    e.preventDefault();
-
-	    var symbolSearchOn = this.props.symbolSearchOn;
-
-
-	    if (symbolSearchOn) {
-	      return this.traverseSymbolResults(rev);
-	    }
-
-	    this.traverseCodeResults(rev);
+	      var matchedLocations = matches || [];
+
+	      var _ref = rev ? (0, _editor.findPrev)(ctx, query, true, modifiers.toJS()) : (0, _editor.findNext)(ctx, query, true, modifiers.toJS()),
+	          ch = _ref.ch,
+	          line = _ref.line;
+
+	      this.updateSearchResults(ch, line, matchedLocations);
+	    }
 	  }
 
 	  // Handlers
-	  selectResultItem(e, item) {
-	    var _props9 = this.props,
-	        selectSource = _props9.selectSource,
-	        selectedSource = _props9.selectedSource;
-
-
-	    if (selectedSource) {
-	      selectSource(selectedSource.get("id"), {
-	        line: item.location.start.line
-	      });
-
-	      this.closeSearch(e);
-	    }
-	  }
-
-	  onSelectResultItem(item) {
-	    var _props10 = this.props,
-	        selectSource = _props10.selectSource,
-	        selectedSource = _props10.selectedSource,
-	        selectedSymbolType = _props10.selectedSymbolType,
-	        highlightLineRange = _props10.highlightLineRange;
-
-
-	    if (selectedSource && selectedSymbolType !== "functions") {
-	      selectSource(selectedSource.get("id"), {
-	        line: item.location.start.line
-	      });
-	    }
-
-	    if (selectedSource && selectedSymbolType === "functions") {
-	      highlightLineRange({
-	        start: item.location.start.line,
-	        end: item.location.end.line,
-	        sourceId: selectedSource.get("id")
-	      });
-	    }
-	  }
 
 	  onChange(e) {
 	    return this.doSearch(e.target.value);
 	  }
 
 	  onKeyUp(e) {
 	    if (e.key !== "Enter" && e.key !== "F3") {
 	      return;
 	    }
 
 	    this.traverseResults(e, e.shiftKey);
 	    e.preventDefault();
 	  }
-
-	  onKeyDown(e) {
-	    var _props11 = this.props,
-	        symbolSearchOn = _props11.symbolSearchOn,
-	        symbolSearchResults = _props11.symbolSearchResults;
-
-	    if (!symbolSearchOn || this.props.query == "") {
-	      return;
-	    }
-
-	    var searchResults = symbolSearchResults;
-
-	    if (e.key === "ArrowUp") {
-	      this.traverseSymbolResults(true);
-	      e.preventDefault();
-	    } else if (e.key === "ArrowDown") {
-	      this.traverseSymbolResults(false);
-	      e.preventDefault();
-	    } else if (e.key === "Enter") {
-	      if (searchResults.length) {
-	        this.selectResultItem(e, searchResults[this.state.selectedResultIndex]);
-	      }
-	      this.closeSearch(e);
-	      e.preventDefault();
-	    } else if (e.key === "Tab") {
-	      this.closeSearch(e);
-	      e.preventDefault();
-	    }
-	  }
-
 	  // Renderers
 	  buildSummaryMsg() {
-	    var _props12 = this.props,
-	        symbolSearchOn = _props12.symbolSearchOn,
-	        symbolSearchResults = _props12.symbolSearchResults;
-
-	    if (symbolSearchOn) {
-	      if (symbolSearchResults.length > 1) {
-	        return L10N.getFormatStr("editor.searchResults", this.state.selectedResultIndex + 1, symbolSearchResults.length);
-	      } else if (symbolSearchResults.length === 1) {
-	        return L10N.getFormatStr("editor.singleResult");
-	      }
-	    }
-
-	    var _props13 = this.props,
-	        _props13$searchResult = _props13.searchResults,
-	        count = _props13$searchResult.count,
-	        index = _props13$searchResult.index,
-	        query = _props13.query;
+	    var _props7 = this.props,
+	        _props7$searchResults = _props7.searchResults,
+	        matchIndex = _props7$searchResults.matchIndex,
+	        count = _props7$searchResults.count,
+	        index = _props7$searchResults.index,
+	        query = _props7.query;
 
 
 	    if (query.trim() == "") {
 	      return "";
 	    }
 
 	    if (count == 0) {
 	      return L10N.getStr("editor.noResults");
 	    }
 
 	    if (index == -1) {
 	      return L10N.getFormatStr("sourceSearch.resultsSummary1", count);
 	    }
 
-	    return L10N.getFormatStr("editor.searchResults", index + 1, count);
-	  }
-
-	  buildPlaceHolder() {
-	    var _props14 = this.props,
-	        symbolSearchOn = _props14.symbolSearchOn,
-	        selectedSymbolType = _props14.selectedSymbolType;
-
-	    if (symbolSearchOn) {
-	      // prettier-ignore
-	      return L10N.getFormatStr(`symbolSearch.search.${selectedSymbolType}Placeholder`);
-	    }
-
-	    return L10N.getStr("sourceSearch.search.placeholder");
+	    return L10N.getFormatStr("editor.searchResults", matchIndex + 1, count);
 	  }
 
 	  renderSearchModifiers() {
-	    var _props15 = this.props,
-	        modifiers = _props15.modifiers,
-	        toggleFileSearchModifier = _props15.toggleFileSearchModifier,
-	        symbolSearchOn = _props15.symbolSearchOn;
-
-
-	    if (symbolSearchOn) {
-	      return null;
-	    }
+	    var _props8 = this.props,
+	        modifiers = _props8.modifiers,
+	        toggleFileSearchModifier = _props8.toggleFileSearchModifier;
+
 
 	    function searchModBtn(modVal, className, svgName, tooltip) {
 	      return _react.DOM.button({
 	        className: (0, _classnames2.default)(className, {
-	          active: !symbolSearchOn && modifiers && modifiers.get(modVal)
+	          active: modifiers && modifiers.get(modVal)
 	        }),
-	        onClick: () => !symbolSearchOn ? toggleFileSearchModifier(modVal) : null,
+	        onClick: () => toggleFileSearchModifier(modVal),
 	        title: tooltip
 	      }, (0, _Svg2.default)(svgName));
 	    }
 
 	    return _react.DOM.div({ className: "search-modifiers" }, searchModBtn("regexMatch", "regex-match-btn", "regex-match", L10N.getStr("symbolSearch.searchModifier.regex")), searchModBtn("caseSensitive", "case-sensitive-btn", "case-match", L10N.getStr("symbolSearch.searchModifier.caseSensitive")), searchModBtn("wholeWord", "whole-word-btn", "whole-word-match", L10N.getStr("symbolSearch.searchModifier.wholeWord")));
 	  }
 
-	  renderSearchTypeToggle() {
-	    var toggleSymbolSearch = this.toggleSymbolSearch,
-	        toggleTextSearch = this.toggleTextSearch;
-	    var _props16 = this.props,
-	        symbolSearchOn = _props16.symbolSearchOn,
-	        selectedSymbolType = _props16.selectedSymbolType;
-
-
-	    function isButtonActive(searchType) {
-	      switch (searchType) {
-	        case "functions":
-	        case "variables":
-	          return symbolSearchOn && selectedSymbolType == searchType;
-	        // text search
-	        default:
-	          return !symbolSearchOn;
-	      }
-	    }
-
-	    function searchTextBtn() {
-	      var searchType = "text";
-	      var active = isButtonActive(searchType);
-
-	      return _react.DOM.button({
-	        className: (0, _classnames2.default)("search-type-btn", {
-	          active
-	        }),
-	        onClick: e => toggleTextSearch(e)
-	      }, searchType);
-	    }
-
-	    function searchTypeBtn(searchType) {
-	      var active = isButtonActive(searchType);
-	      var toggle = selectedSymbolType == searchType;
-
-	      return _react.DOM.button({
-	        className: (0, _classnames2.default)("search-type-btn", {
-	          active
-	        }),
-	        onClick: e => toggleSymbolSearch(e, { toggle, searchType })
-	      }, searchType);
-	    }
-
-	    return _react.DOM.section({ className: "search-type-toggles" }, _react.DOM.h1({ className: "search-toggle-title" }, L10N.getStr("editor.searchTypeToggleTitle")), searchTextBtn(), searchTypeBtn("functions"), searchTypeBtn("variables"));
-	  }
-
-	  renderBottomBar() {
-	    return _react.DOM.div({ className: "search-bottom-bar" }, this.renderSearchTypeToggle(), this.renderSearchModifiers());
-	  }
-
-	  renderResults() {
-	    var selectedResultIndex = this.state.selectedResultIndex;
-	    var _props17 = this.props,
-	        query = _props17.query,
-	        symbolSearchResults = _props17.symbolSearchResults,
-	        symbolSearchOn = _props17.symbolSearchOn;
-
-	    if (query == "" || !symbolSearchOn || !symbolSearchResults.length) {
-	      return;
-	    }
-
-	    return ResultList({
-	      items: symbolSearchResults,
-	      selected: selectedResultIndex,
-	      selectItem: this.selectResultItem,
-	      ref: "resultList"
-	    });
-	  }
-
 	  render() {
-	    var _props18 = this.props,
-	        count = _props18.searchResults.count,
-	        query = _props18.query,
-	        searchOn = _props18.searchOn,
-	        symbolSearchOn = _props18.symbolSearchOn;
-
-
-	    if (!searchOn && !symbolSearchOn) {
+	    var _props9 = this.props,
+	        count = _props9.searchResults.count,
+	        query = _props9.query,
+	        searchOn = _props9.searchOn;
+
+
+	    if (!searchOn) {
 	      return _react.DOM.div();
 	    }
 
 	    return _react.DOM.div({ className: "search-bar" }, SearchInput({
 	      query,
 	      count,
-	      placeholder: this.buildPlaceHolder(),
+	      placeholder: L10N.getStr("sourceSearch.search.placeholder"),
 	      summaryMsg: this.buildSummaryMsg(),
 	      onChange: this.onChange,
 	      onKeyUp: this.onKeyUp,
-	      onKeyDown: this.onKeyDown,
 	      handleNext: e => this.traverseResults(e, false),
 	      handlePrev: e => this.traverseResults(e, true),
 	      handleClose: this.closeSearch
-	    }), this.renderResults(), this.renderBottomBar());
+	    }), _react.DOM.div({ className: "search-bottom-bar" }, this.renderSearchModifiers()));
 	  }
 	}
 
 	SearchBar.displayName = "SearchBar";
 	SearchBar.contextTypes = {
 	  shortcuts: _react.PropTypes.object
 	};
 
-	function _getFormattedSymbols(state) {
-	  var source = (0, _selectors.getSelectedSource)(state);
-	  if (!source) {
-	    return { variables: [], functions: [] };
-	  }
-
-	  var _getSymbols = (0, _selectors.getSymbols)(state, source.toJS()),
-	      variables = _getSymbols.variables,
-	      functions = _getSymbols.functions;
-
-	  return {
-	    variables: variables.map(formatSymbol),
-	    functions: functions.map(formatSymbol)
-	  };
-	}
-
 	exports.default = (0, _reactRedux.connect)(state => {
 	  return {
-	    searchOn: (0, _selectors.getFileSearchState)(state),
+	    searchOn: (0, _selectors.getActiveSearchState)(state) === "file",
 	    query: (0, _selectors.getFileSearchQueryState)(state),
 	    modifiers: (0, _selectors.getFileSearchModifierState)(state),
-	    symbolSearchOn: (0, _selectors.getSymbolSearchState)(state),
-	    symbolSearchResults: (0, _selectors.getSymbolSearchResults)(state),
-	    searchResults: (0, _selectors.getSearchResults)(state),
-	    symbols: _getFormattedSymbols(state),
-	    selectedSymbolType: (0, _selectors.getSymbolSearchType)(state)
+	    searchResults: (0, _selectors.getSearchResults)(state)
 	  };
 	}, dispatch => (0, _redux.bindActionCreators)(_actions2.default, dispatch))(SearchBar);
 
 /***/ },
 /* 434 */,
 /* 435 */,
 /* 436 */,
 /* 437 */,
@@ -27389,83 +26190,80 @@ return /******/ (function(modules) { // 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
 	exports.default = GutterMenu;
 
 	var _devtoolsLaunchpad = __webpack_require__(131);
 
 	function GutterMenu(_ref) {
-	  var bp = _ref.bp,
+	  var breakpoint = _ref.breakpoint,
 	      line = _ref.line,
 	      event = _ref.event,
 	      toggleBreakpoint = _ref.toggleBreakpoint,
 	      showConditionalPanel = _ref.showConditionalPanel,
-	      toggleBreakpointDisabledStatus = _ref.toggleBreakpointDisabledStatus,
+	      toggleDisabledBreakpoint = _ref.toggleDisabledBreakpoint,
 	      isCbPanelOpen = _ref.isCbPanelOpen,
 	      closeConditionalPanel = _ref.closeConditionalPanel;
 
 	  event.stopPropagation();
 	  event.preventDefault();
-	  var breakpoint = {
-	    id: "node-menu-add-breakpoint",
-	    label: L10N.getStr("editor.addBreakpoint")
-	  },
-	      conditional = {
-	    id: "node-menu-add-conditional-breakpoint",
-	    label: L10N.getStr("editor.addConditionalBreakpoint")
-	  },
-	      disabled = void 0;
-	  if (bp) {
-	    breakpoint = {
+
+	  var gutterItems = {
+	    addBreakpoint: {
+	      id: "node-menu-add-breakpoint",
+	      label: L10N.getStr("editor.addBreakpoint")
+	    },
+	    addConditional: {
+	      id: "node-menu-add-conditional-breakpoint",
+	      label: L10N.getStr("editor.addConditionalBreakpoint")
+	    },
+	    removeBreakpoint: {
 	      id: "node-menu-remove-breakpoint",
 	      label: L10N.getStr("editor.removeBreakpoint")
-	    };
-	    conditional = {
+	    },
+	    editConditional: {
 	      id: "node-menu-edit-conditional-breakpoint",
 	      label: L10N.getStr("editor.editBreakpoint")
-	    };
-	    if (bp.disabled) {
-	      disabled = {
-	        id: "node-menu-enable-breakpoint",
-	        label: L10N.getStr("editor.enableBreakpoint")
-	      };
-	    } else {
-	      disabled = {
-	        id: "node-menu-disable-breakpoint",
-	        label: L10N.getStr("editor.disableBreakpoint")
-	      };
-	    }
-	  }
+	    },
+	    enableBreakpoint: {
+	      id: "node-menu-enable-breakpoint",
+	      label: L10N.getStr("editor.enableBreakpoint")
+	    },
+	    disableBreakpoint: {
+	      id: "node-menu-disable-breakpoint",
+	      label: L10N.getStr("editor.disableBreakpoint")
+	    }
+	  };
 
 	  var toggleBreakpointItem = Object.assign({
 	    accesskey: "B",
 	    disabled: false,
 	    click: () => {
 	      toggleBreakpoint(line);
 	      if (isCbPanelOpen) {
 	        closeConditionalPanel();
 	      }
 	    }
-	  }, breakpoint);
+	  }, breakpoint ? gutterItems.removeBreakpoint : gutterItems.addBreakpoint);
 
 	  var conditionalBreakpoint = Object.assign({
 	    accesskey: "C",
 	    disabled: false,
 	    click: () => showConditionalPanel(line)
-	  }, conditional);
+	  }, breakpoint && breakpoint.condition ? gutterItems.editConditional : gutterItems.addConditional);
 
 	  var items = [toggleBreakpointItem, conditionalBreakpoint];
 
-	  if (bp) {
+	  if (breakpoint) {
 	    var disableBreakpoint = Object.assign({
 	      accesskey: "D",
 	      disabled: false,
-	      click: () => toggleBreakpointDisabledStatus(line)
-	    }, disabled);
+	      click: () => toggleDisabledBreakpoint(line)
+	    }, breakpoint.disabled ? gutterItems.enableBreakpoint : gutterItems.disableBreakpoint);
 	    items.push(disableBreakpoint);
 	  }
 
 	  (0, _devtoolsLaunchpad.showMenu)(event, items);
 	}
 
 /***/ },
 /* 656 */
@@ -28104,22 +26902,17 @@ return /******/ (function(modules) { // 
 /* 680 */,
 /* 681 */,
 /* 682 */,
 /* 683 */,
 /* 684 */,
 /* 685 */,
 /* 686 */,
 /* 687 */,
-/* 688 */
-/***/ function(module, exports) {
-
-	module.exports = "<!-- This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --><svg viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M8,3L12,3L12,7L14,7L14,8L12,8L12,12L8,12L8,14L7,14L7,12L3,12L3,8L1,8L1,7L3,7L3,3L7,3L7,1L8,1L8,3ZM10,10L10,5L5,5L5,10L10,10Z\"></path></svg>"
-
-/***/ },
+/* 688 */,
 /* 689 */,
 /* 690 */,
 /* 691 */,
 /* 692 */,
 /* 693 */,
 /* 694 */,
 /* 695 */,
 /* 696 */
@@ -28458,19 +27251,19 @@ return /******/ (function(modules) { // 
 	    var gap = _react.DOM.div({ className: "gap", key: "gap" });
 	    return orientation === "up" ? [children, gap] : [gap, children];
 	  }
 
 	  getPopoverArrow(orientation, left) {
 	    var arrowOrientation = orientation === "up" ? "down" : "up";
 
 	    var arrowProp = arrowOrientation === "up" ? "top" : "bottom";
-	    var arrowPropValue = arrowOrientation === "up" ? -8 : 6;
-
-	    return new BracketArrow({
+	    var arrowPropValue = arrowOrientation === "up" ? -7 : 5;
+
+	    return BracketArrow({
 	      orientation: arrowOrientation,
 	      left,
 	      [arrowProp]: arrowPropValue
 	    });
 	  }
 
 	  renderPopover() {
 	    var onMouseLeave = this.props.onMouseLeave;
@@ -28961,20 +27754,21 @@ return /******/ (function(modules) { // 
 	var _classnames = __webpack_require__(175);
 
 	var _classnames2 = _interopRequireDefault(_classnames);
 
 	var _Svg = __webpack_require__(344);
 
 	var _Svg2 = _interopRequireDefault(_Svg);
 
+	var _editor = __webpack_require__(257);
+
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 	var breakpointSvg = document.createElement("div");
-
 	_reactDom2.default.render((0, _Svg2.default)("breakpoint"), breakpointSvg);
 
 	function makeMarker(isDisabled) {
 	  var bp = breakpointSvg.cloneNode(true);
 	  bp.className = (0, _classnames2.default)("editor new-breakpoint", {
 	    "breakpoint-disabled": isDisabled,
 	    "folding-enabled": (0, _devtoolsConfig.isEnabled)("codeFolding")
 	  });
@@ -28985,52 +27779,94 @@ return /******/ (function(modules) { // 
 	class Breakpoint extends _react.Component {
 
 	  constructor() {
 	    super();
 	    this.addBreakpoint = this.addBreakpoint.bind(this);
 	  }
 
 	  addBreakpoint() {
-	    var bp = this.props.breakpoint;
-	    var line = bp.location.line - 1;
-
-	    this.props.editor.setGutterMarker(line, "breakpoints", makeMarker(bp.disabled));
-	    this.props.editor.addLineClass(line, "line", "new-breakpoint");
-	    if (bp.condition) {
-	      this.props.editor.addLineClass(line, "line", "has-condition");
-	    } else {
-	      this.props.editor.removeLineClass(line, "line", "has-condition");
-	    }
-	  }
+	    var _props = this.props,
+	        breakpoint = _props.breakpoint,
+	        editor = _props.editor,
+	        selectedSource = _props.selectedSource;
+
+	    // NOTE: we need to wait for the breakpoint to be loaded
+	    // to get the generated location
+
+	    if (!selectedSource || breakpoint.loading) {
+	      return;
+	    }
+
+	    var line = breakpoint.location.line - 1;
+	    (0, _editor.showSourceText)(editor, selectedSource.toJS());
+
+	    editor.codeMirror.setGutterMarker(line, "breakpoints", makeMarker(breakpoint.disabled));
+
+	    editor.codeMirror.addLineClass(line, "line", "new-breakpoint");
+	    if (breakpoint.condition) {
+	      editor.codeMirror.addLineClass(line, "line", "has-condition");
+	    } else {
+	      editor.codeMirror.removeLineClass(line, "line", "has-condition");
+	    }
+	  }
+
 	  shouldComponentUpdate(nextProps) {
-	    return this.props.editor !== nextProps.editor || this.props.breakpoint.disabled !== nextProps.breakpoint.disabled || this.props.breakpoint.condition !== nextProps.breakpoint.condition;
-	  }
+	    var _props2 = this.props,
+	        editor = _props2.editor,
+	        breakpoint = _props2.breakpoint,
+	        selectedSource = _props2.selectedSource;
+
+	    return editor !== nextProps.editor || breakpoint.disabled !== nextProps.breakpoint.disabled || breakpoint.condition !== nextProps.breakpoint.condition || breakpoint.loading !== nextProps.breakpoint.loading || selectedSource !== nextProps.selectedSource;
+	  }
+
 	  componentDidMount() {
 	    if (!this.props.editor) {
 	      return;
 	    }
 
 	    this.addBreakpoint();
 	  }
+
 	  componentDidUpdate() {
 	    this.addBreakpoint();
 	  }
+
 	  componentWillUnmount() {
-	    if (!this.props.editor) {
-	      return;
-	    }
-
-	    var bp = this.props.breakpoint;
-	    var line = bp.location.line - 1;
-
-	    this.props.editor.setGutterMarker(line, "breakpoints", null);
-	    this.props.editor.removeLineClass(line, "line", "new-breakpoint");
-	    this.props.editor.removeLineClass(line, "line", "has-condition");
-	  }
+	    var _props3 = this.props,
+	        editor = _props3.editor,
+	        breakpoint = _props3.breakpoint,
+	        selectedSource = _props3.selectedSource;
+
+
+	    if (!editor || !selectedSource) {
+	      return;
+	    }
+
+	    if (breakpoint.loading) {
+	      return;
+	    }
+
+	    var line = breakpoint.location.line - 1;
+	    var doc = (0, _editor.getDocument)(selectedSource.get("id"));
+	    if (!doc) {
+	      return;
+	    }
+
+	    // NOTE: when we upgrade codemirror we can use `doc.setGutterMarker`
+	    if (doc.setGutterMarker) {
+	      doc.setGutterMarker(line, "breakpoints", null);
+	    } else {
+	      editor.codeMirror.setGutterMarker(line, "breakpoints", null);
+	    }
+
+	    doc.removeLineClass(line, "line", "new-breakpoint");
+	    doc.removeLineClass(line, "line", "has-condition");
+	  }
+
 	  render() {
 	    return null;
 	  }
 	}
 
 	Breakpoint.displayName = "Breakpoint";
 
 	exports.default = Breakpoint;
@@ -29223,17 +28059,20 @@ return /******/ (function(modules) { // 
 	      return null;
 	    }
 
 	    return _react.DOM.input({
 	      type: "checkbox",
 	      "aria-label": breakpointsDisabled ? L10N.getStr("breakpoints.enable") : L10N.getStr("breakpoints.disable"),
 	      className: boxClassName,
 	      disabled: breakpointsLoading,
-	      onClick: () => toggleAllBreakpoints(!breakpointsDisabled),
+	      onClick: e => {
+	        e.stopPropagation();
+	        toggleAllBreakpoints(!breakpointsDisabled);
+	      },
 	      checked: !breakpointsDisabled && !isIndeterminate,
 	      ref: input => {
 	        if (input) {
 	          input.indeterminate = isIndeterminate;
 	        }
 	      },
 	      title: breakpointsDisabled ? L10N.getStr("breakpoints.enable") : L10N.getStr("breakpoints.disable")
 	    });
@@ -29335,18 +28174,17 @@ return /******/ (function(modules) { // 
 	      splitterSize: 1,
 	      startPanel: Accordion({ items: this.getStartItems() }),
 	      endPanel: Accordion({ items: this.getEndItems() })
 	    });
 	  }
 
 	  render() {
 	    return _react.DOM.div({
-	      className: "secondary-panes",
-	      style: { overflowX: "hidden" }
+	      className: "secondary-panes"
 	    }, CommandBar(), this.props.horizontal ? this.renderHorizontalLayout() : this.renderVerticalLayout());
 	  }
 	}
 
 	SecondaryPanes.propTypes = {
 	  evaluateExpressions: _react.PropTypes.func.isRequired,
 	  pauseData: _react.PropTypes.object,
 	  horizontal: _react.PropTypes.bool,
@@ -29502,17 +28340,17 @@ return /******/ (function(modules) { // 
 	    }
 
 	    this.setState({ editing: null });
 	    e.target.value = "";
 	    this.props.updateExpression(value, expression);
 	  }
 
 	  renderExpressionEditInput(expression) {
-	    return _react.DOM.span({ className: "expression-input-container" }, _react.DOM.input({
+	    return _react.DOM.span({ className: "expression-input-container", key: expression.input }, _react.DOM.input({
 	      type: "text",
 	      className: "input-expression",
 	      onKeyPress: e => this.inputKeyPress(e, expression),
 	      onBlur: () => {
 	        this.setState({ editing: null });
 	      },
 	      defaultValue: expression.input,
 	      ref: c => {
@@ -29634,16 +28472,18 @@ return /******/ (function(modules) { // 
 	var _react = __webpack_require__(2);
 
 	var _reactRedux = __webpack_require__(151);
 
 	var _reselect = __webpack_require__(993);
 
 	var _redux = __webpack_require__(3);
 
+	var _devtoolsConfig = __webpack_require__(828);
+
 	var _reactImmutableProptypes = __webpack_require__(150);
 
 	var _reactImmutableProptypes2 = _interopRequireDefault(_reactImmutableProptypes);
 
 	var _classnames = __webpack_require__(175);
 
 	var _classnames2 = _interopRequireDefault(_classnames);
 
@@ -29652,17 +28492,17 @@ return /******/ (function(modules) { // 
 	var _actions2 = _interopRequireDefault(_actions);
 
 	var _selectors = __webpack_require__(242);
 
 	var _breakpoint = __webpack_require__(1057);
 
 	var _utils = __webpack_require__(234);
 
-	var _path = __webpack_require__(235);
+	var _source = __webpack_require__(233);
 
 	var _Close = __webpack_require__(378);
 
 	var _Close2 = _interopRequireDefault(_Close);
 
 	__webpack_require__(726);
 
 	var _get = __webpack_require__(67);
@@ -29676,21 +28516,23 @@ return /******/ (function(modules) { // 
 	    return false;
 	  }
 
 	  var bpId = (0, _breakpoint.makeLocationId)(breakpoint.location);
 	  var pausedId = (0, _breakpoint.makeLocationId)((0, _get2.default)(pause, "frame.location"));
 	  return bpId === pausedId;
 	}
 
+
 	function renderSourceLocation(source, line, column) {
-	  var url = source.get("url") ? (0, _path.basename)(source.get("url")) : null;
-	  var bpLocation = line + (column ? `:${column}` : "");
-	  // const line = url !== "" ? `: ${line}` : "";
-	  return url ? _react.DOM.div({ className: "location" }, `${(0, _utils.endTruncateStr)(url, 30)}: ${bpLocation}`) : null;
+	  var filename = source ? (0, _source.getFilename)(source.toJS()) : null;
+	  var columnVal = (0, _devtoolsConfig.isEnabled)("columnBreakpoints") && column ? `:${column}` : "";
+	  var bpLocation = `${line}${columnVal}`;
+
+	  return filename ? _react.DOM.div({ className: "location" }, `${(0, _utils.endTruncateStr)(filename, 30)}: ${bpLocation}`) : null;
 	}
 
 	class Breakpoints extends _react.PureComponent {
 	  shouldComponentUpdate(nextProps, nextState) {
 	    var breakpoints = this.props.breakpoints;
 
 	    return breakpoints !== nextProps.breakpoints;
 	  }
@@ -30919,17 +29761,18 @@ return /******/ (function(modules) { // 
 	    };
 
 	    this.onTabContextMenu = this.onTabContextMenu.bind(this);
 	    this.showContextMenu = this.showContextMenu.bind(this);
 	    this.updateHiddenSourceTabs = this.updateHiddenSourceTabs.bind(this);
 	    this.toggleSourcesDropdown = this.toggleSourcesDropdown.bind(this);
 	    this.renderDropdownSource = this.renderDropdownSource.bind(this);
 	    this.renderTabs = this.renderTabs.bind(this);
-	    this.renderTab = this.renderTab.bind(this);
+	    this.renderSourceTab = this.renderSourceTab.bind(this);
+	    this.renderSearchTab = this.renderSearchTab.bind(this);
 	    this.renderNewButton = this.renderNewButton.bind(this);
 	    this.renderDropDown = this.renderDropdown.bind(this);
 	    this.renderStartPanelToggleButton = this.renderStartPanelToggleButton.bind(this);
 	    this.renderEndPanelToggleButton = this.renderEndPanelToggleButton.bind(this);
 
 	    this.onResize = (0, _debounce2.default)(() => {
 	      this.updateHiddenSourceTabs();
 	    });
@@ -31105,59 +29948,108 @@ return /******/ (function(modules) { // 
 	        var tabIndex = 0;
 	        moveTab(source.get("url"), tabIndex);
 	      }
 	    }, filename);
 	  }
 
 	  renderTabs() {
 	    var sourceTabs = this.props.sourceTabs;
+
 	    if (!sourceTabs) {
 	      return;
 	    }
 
-	    return _react.DOM.div({ className: "source-tabs", ref: "sourceTabs" }, sourceTabs.map(this.renderTab));
-	  }
-
-	  renderTab(source) {
+	    return _react.DOM.div({ className: "source-tabs", ref: "sourceTabs" }, sourceTabs.map(this.renderSourceTab));
+	  }
+
+	  isProjectSearchEnabled() {
+	    return this.props.activeSearch === "project";
+	  }
+
+	  isSourceSearchEnabled() {
+	    return this.props.activeSearch === "source";
+	  }
+
+	  renderSearchTab(source) {
 	    var _props3 = this.props,
-	        selectedSource = _props3.selectedSource,
-	        selectSource = _props3.selectSource,
-	        closeTab = _props3.closeTab;
+	        closeTab = _props3.closeTab,
+	        closeActiveSearch = _props3.closeActiveSearch,
+	        setActiveSearch = _props3.setActiveSearch;
+
+
+	    function tabName(tab) {
+	      return `${tab} search results`;
+	    }
+
+	    function onClickClose(ev) {
+	      ev.stopPropagation();
+	      closeActiveSearch();
+	      closeTab(source);
+	    }
+	    return _react.DOM.div({
+	      className: (0, _classnames2.default)("source-tab", {
+	        active: this.isProjectSearchEnabled() || this.isSourceSearchEnabled(),
+	        pretty: false
+	      }),
+	      key: source,
+	      onClick: () => setActiveSearch(source),
+	      onContextMenu: e => this.onTabContextMenu(e, source),
+	      title: tabName(source)
+	    }, _react.DOM.div({ className: "filename" }, tabName(source)), (0, _Close2.default)({
+	      handleClick: onClickClose,
+	      tooltip: L10N.getStr("sourceTabs.closeTabButtonTooltip")
+	    }));
+	  }
+
+	  renderSourceTab(source) {
+	    var _props4 = this.props,
+	        selectedSource = _props4.selectedSource,
+	        selectSource = _props4.selectSource,
+	        closeTab = _props4.closeTab,
+	        closeActiveSearch = _props4.closeActiveSearch;
 
 	    var filename = (0, _source.getFilename)(source.toJS());
-	    var active = selectedSource && source.get("id") == selectedSource.get("id");
+	    var active = selectedSource && source.get("id") == selectedSource.get("id") && !this.isProjectSearchEnabled() && !this.isSourceSearchEnabled();
 	    var isPrettyCode = (0, _source.isPretty)(source.toJS());
 	    var sourceAnnotation = this.getSourceAnnotation(source);
 
 	    function onClickClose(ev) {
 	      ev.stopPropagation();
 	      closeTab(source.get("url"));
 	    }
 
 	    return _react.DOM.div({
 	      className: (0, _classnames2.default)("source-tab", {
 	        active,
 	        pretty: isPrettyCode
 	      }),
 	      key: source.get("id"),
-	      onClick: () => selectSource(source.get("id")),
+	      onClick: () => {
+	        closeActiveSearch();
+	        return selectSource(source.get("id"));
+	      },
 	      onContextMenu: e => this.onTabContextMenu(e, source.get("id")),
 	      title: (0, _source.getFilename)(source.toJS())
 	    }, sourceAnnotation, _react.DOM.div({ className: "filename" }, filename), (0, _Close2.default)({
 	      handleClick: onClickClose,
 	      tooltip: L10N.getStr("sourceTabs.closeTabButtonTooltip")
 	    }));
 	  }
 
 	  renderNewButton() {
 	    var newTabTooltip = L10N.getFormatStr("sourceTabs.newTabButtonTooltip", (0, _text.formatKeyShortcut)(L10N.getStr("sources.search.key2")));
 	    return _react.DOM.div({
 	      className: "new-tab-btn",
-	      onClick: () => this.props.toggleProjectSearch(),
+	      onClick: () => {
+	        if (this.props.searchOn) {
+	          return this.props.closeActiveSearch();
+	        }
+	        this.props.setActiveSearch("source");
+	      },
 	      title: newTabTooltip
 	    }, (0, _Svg2.default)("plus"));
 	  }
 
 	  renderDropdown() {
 	    var hiddenSourceTabs = this.state.hiddenSourceTabs;
 	    if (!hiddenSourceTabs || hiddenSourceTabs.size == 0) {
 	      return _react.DOM.div({});
@@ -31205,18 +30097,20 @@ return /******/ (function(modules) { // 
 	  }
 	}
 
 	SourceTabs.displayName = "SourceTabs";
 
 	exports.default = (0, _reactRedux.connect)(state => {
 	  return {
 	    selectedSource: (0, _selectors.getSelectedSource)(state),
+	    searchTabs: (0, _selectors.getSearchTabs)(state),
 	    sourceTabs: (0, _selectors.getSourcesForTabs)(state),
-	    searchOn: (0, _selectors.getProjectSearchState)(state)
+	    activeSearch: (0, _selectors.getActiveSearchState)(state),
+	    searchOn: (0, _selectors.getActiveSearchState)(state) === "source"
 	  };
 	}, dispatch => (0, _redux.bindActionCreators)(_actions2.default, dispatch))(SourceTabs);
 
 /***/ },
 /* 751 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
@@ -31391,31 +30285,32 @@ return /******/ (function(modules) { // 
 /* 827 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	Object.defineProperty(exports, "__esModule", {
 	  value: true
 	});
-	exports.getOutOfScopeLocations = exports.getVariablesInScope = exports.getSymbols = exports.getClosestExpression = exports.stopParserWorker = exports.startParserWorker = undefined;
+	exports.clearSymbols = exports.getOutOfScopeLocations = exports.getVariablesInScope = exports.getSymbols = exports.getClosestExpression = exports.stopParserWorker = exports.startParserWorker = undefined;
 
 	var _devtoolsUtils = __webpack_require__(900);
 
 	var WorkerDispatcher = _devtoolsUtils.workerUtils.WorkerDispatcher;
 
 
 	var dispatcher = new WorkerDispatcher();
 	var startParserWorker = exports.startParserWorker = dispatcher.start.bind(dispatcher);
 	var stopParserWorker = exports.stopParserWorker = dispatcher.stop.bind(dispatcher);
 
 	var getClosestExpression = exports.getClosestExpression = dispatcher.task("getClosestExpression");
 	var getSymbols = exports.getSymbols = dispatcher.task("getSymbols");
 	var getVariablesInScope = exports.getVariablesInScope = dispatcher.task("getVariablesInScope");
 	var getOutOfScopeLocations = exports.getOutOfScopeLocations = dispatcher.task("getOutOfScopeLocations");
+	var clearSymbols = exports.clearSymbols = dispatcher.task("clearSymbols");
 
 /***/ },
 /* 828 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	var feature = __webpack_require__(829);
@@ -32583,17 +31478,17 @@ return /******/ (function(modules) { // 
 
 	    // In Firefox, we need to initially request all of the sources. This
 	    // usually fires off individual `newSource` notifications as the
 	    // debugger finds them, but there may be existing sources already in
 	    // the debugger (if it's paused already, or if loading the page from
 	    // bfcache) so explicity fire `newSource` events for all returned
 	    // sources.
 	    var sources = yield _commands.clientCommands.fetchSources();
-	    actions.connect(tabTarget._form.url);
+	    actions.connect(tabTarget.url);
 	    yield actions.newSources(sources);
 
 	    // If the threadClient is already paused, make sure to show a
 	    // paused state.
 	    var pausedPacket = threadClient.getLastPausePacket();
 	    if (pausedPacket) {
 	      _events.clientEvents.paused("paused", pausedPacket);
 	    }
@@ -32730,20 +31625,20 @@ return /******/ (function(modules) { // 
 	        actor = _bpClient$location.actor,
 	        url = _bpClient$location.url,
 	        line = _bpClient$location.line,
 	        column = _bpClient$location.column,
 	        condition = _bpClient$location.condition;
 
 	    return {
 	      id: bpClient.actor,
+	      condition,
 	      actualLocation: {
 	        line,
 	        column,
-	        condition,
 	        sourceId: actor,
 	        sourceUrl: url
 	      }
 	    };
 	  }
 	  return null;
 	}
 
@@ -32758,16 +31653,20 @@ return /******/ (function(modules) { // 
 	  }).then((_ref) => {
 	    var _ref2 = _slicedToArray(_ref, 2),
 	        actualLocation = _ref2[0].actualLocation,
 	        bpClient = _ref2[1];
 
 	    actualLocation = (0, _create.createBreakpointLocation)(location, actualLocation);
 	    var id = (0, _breakpoint.makeLocationId)(actualLocation);
 	    bpClients[id] = bpClient;
+	    bpClient.location.line = actualLocation.line;
+	    bpClient.location.column = actualLocation.column;
+	    bpClient.location.url = actualLocation.sourceUrl || "";
+
 	    return { id, actualLocation };
 	  });
 	}
 
 	function removeBreakpoint(breakpoint) {
 	  try {
 	    var id = (0, _breakpoint.makeLocationId)(breakpoint.generatedLocation);
 	    var bpClient = bpClients[id];
@@ -32791,16 +31690,20 @@ return /******/ (function(modules) { // 
 	    return { id: breakpointId };
 	  });
 	}
 
 	function evaluate(script, _ref3) {
 	  var frameId = _ref3.frameId;
 
 	  var params = frameId ? { frameActor: frameId } : {};
+	  if (!tabTarget || !tabTarget.activeConsole) {
+	    return Promise.resolve();
+	  }
+
 	  return new Promise(resolve => {
 	    tabTarget.activeConsole.evaluateJS(script, result => resolve(result), params);
 	  });
 	}
 
 	function debuggeeCommand(script) {
 	  tabTarget.activeConsole.evaluateJS(script, () => {}, {});
 
@@ -32963,17 +31866,17 @@ return /******/ (function(modules) { // 
 
 	function createBreakpointLocation(location, actualLocation) {
 	  if (!actualLocation) {
 	    return location;
 	  }
 
 	  return {
 	    sourceId: actualLocation.source.actor,
-	    sourceUrl: location.sourceUrl,
+	    sourceUrl: actualLocation.source.url,
 	    line: actualLocation.line,
 	    column: actualLocation.column
 	  };
 	}
 
 /***/ },
 /* 892 */
 /***/ function(module, exports, __webpack_require__) {
@@ -33263,17 +32166,18 @@ return /******/ (function(modules) { // 
 	exports.toServerLocation = toServerLocation;
 	exports.createFrame = createFrame;
 	exports.createLoadedObject = createLoadedObject;
 	function fromServerLocation(serverLocation) {
 	  if (serverLocation) {
 	    return {
 	      sourceId: serverLocation.scriptId,
 	      line: serverLocation.lineNumber + 1,
-	      column: serverLocation.columnNumber
+	      column: serverLocation.columnNumber,
+	      sourceUrl: ""
 	    };
 	  }
 	}
 
 	function toServerLocation(location) {
 	  return {
 	    scriptId: location.sourceId,
 	    lineNumber: location.line - 1
@@ -33491,28 +32395,32 @@ return /******/ (function(modules) { // 
 	var _selectors = __webpack_require__(242);
 
 	var _selectors2 = _interopRequireDefault(_selectors);
 
 	var _App = __webpack_require__(243);
 
 	var _App2 = _interopRequireDefault(_App);
 
+	var _prefs = __webpack_require__(226);
+
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 	function bootstrapStore(client, services) {
 	  var createStore = (0, _createStore2.default)({
 	    log: (0, _devtoolsConfig.getValue)("logging.actions"),
 	    timing: (0, _devtoolsConfig.getValue)("performance.actions"),
 	    makeThunkArgs: (args, state) => {
 	      return Object.assign({}, args, { client }, services);
 	    }
 	  });
 
 	  var store = createStore((0, _redux.combineReducers)(_reducers2.default));
+	  store.subscribe(() => updatePrefs(store.getState()));
+
 	  var actions = (0, _redux.bindActionCreators)(__webpack_require__(244).default, store.dispatch);
 
 	  return { store, actions, selectors: _selectors2.default };
 	}
 
 	function bootstrapApp(connection, _ref) {
 	  var store = _ref.store,
 	      actions = _ref.actions;
@@ -33544,20 +32452,32 @@ return /******/ (function(modules) { // 
 	    // When used in Firefox, the toolbox manages the source map worker.
 	    (0, _devtoolsSourceMap.stopSourceMapWorker)();
 	  }
 	  (0, _prettyPrint.stopPrettyPrintWorker)();
 	  (0, _parser.stopParserWorker)();
 	  (0, _search.stopSearchWorker)();
 	}
 
+	function updatePrefs(state) {
+	  var pendingBreakpoints = _selectors2.default.getPendingBreakpoints(state);
+
+	  if (_prefs.prefs.pendingBreakpoints !== pendingBreakpoints) {
+	    _prefs.prefs.pendingBreakpoints = pendingBreakpoints;
+	  }
+	}
+
 /***/ },
 /* 898 */
 /***/ function(module, exports, __webpack_require__) {
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	const {
 	  originalToGeneratedId,
 	  generatedToOriginalId,
 	  isGeneratedId,
 	  isOriginalId
 	} = __webpack_require__(899);
 
 	const { workerUtils: { WorkerDispatcher } } = __webpack_require__(900);
@@ -33587,16 +32507,20 @@ return /******/ (function(modules) { // 
 	  startSourceMapWorker: dispatcher.start.bind(dispatcher),
 	  stopSourceMapWorker: dispatcher.stop.bind(dispatcher)
 	};
 
 /***/ },
 /* 899 */
 /***/ function(module, exports, __webpack_require__) {
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	const md5 = __webpack_require__(248);
 
 	function originalToGeneratedId(originalId) {
 	  const match = originalId.match(/(.*)\/originalSource/);
 	  return match ? match[1] : "";
 	}
 
 	function generatedToOriginalId(generatedId, url) {
@@ -33663,38 +32587,46 @@ return /******/ (function(modules) { // 
 	  getContentType,
 	  contentMapForTesting: contentMap
 	};
 
 /***/ },
 /* 900 */
 /***/ function(module, exports, __webpack_require__) {
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	const networkRequest = __webpack_require__(901);
 	const workerUtils = __webpack_require__(902);
 
 	module.exports = {
 	  networkRequest,
 	  workerUtils
 	};
 
 /***/ },
 /* 901 */
 /***/ function(module, exports) {
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	function networkRequest(url, opts) {
 	  return new Promise((resolve, reject) => {
 	    const req = new XMLHttpRequest();
 
 	    req.addEventListener("readystatechange", () => {
 	      if (req.readyState === XMLHttpRequest.DONE) {
 	        if (req.status === 200) {
 	          resolve({ content: req.responseText });
 	        } else {
-	          resolve(req.statusText);
+	          reject(req.statusText);
 	        }
 	      }
 	    });
 
 	    // Not working yet.
 	    // if (!opts.loadFromCache) {
 	    //   req.channel.loadFlags = (
 	    //     Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE |
@@ -33714,17 +32646,19 @@ return /******/ (function(modules) { // 
 /* 902 */
 /***/ function(module, exports) {
 
 	
 
 	function WorkerDispatcher() {
 	  this.msgId = 1;
 	  this.worker = null;
-	}
+	} /* 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/. */
 
 	WorkerDispatcher.prototype = {
 	  start(url) {
 	    this.worker = new Worker(url);
 	    this.worker.onerror = () => {
 	      console.error(`Error in worker ${url}`);
 	    };
 	  },
@@ -33745,17 +32679,16 @@ return /******/ (function(modules) { // 
 	        this.worker.postMessage({ id, method, args });
 
 	        const listener = ({ data: result }) => {
 	          if (result.id !== id) {
 	            return;
 	          }
 
 	          this.worker.removeEventListener("message", listener);
-
 	          if (result.error) {
 	            reject(result.error);
 	          } else {
 	            resolve(result.response);
 	          }
 	        };
 
 	        this.worker.addEventListener("message", listener);
@@ -33847,29 +32780,32 @@ return /******/ (function(modules) { // 
 	exports.updateSelection = updateSelection;
 
 	var _isEqual = __webpack_require__(1127);
 
 	var _isEqual2 = _interopRequireDefault(_isEqual);
 
 	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
-	var lineOffset = 1;
-
 	function getTokenLocation(codeMirror, tokenEl) {
 	  var _tokenEl$getBoundingC = tokenEl.getBoundingClientRect(),
 	      left = _tokenEl$getBoundingC.left,
-	      top = _tokenEl$getBoundingC.top;
-
-	  var _codeMirror$coordsCha = codeMirror.coordsChar({ left, top }),
+	      top = _tokenEl$getBoundingC.top,
+	      width = _tokenEl$getBoundingC.width,
+	      height = _tokenEl$getBoundingC.height;
+
+	  var _codeMirror$coordsCha = codeMirror.coordsChar({
+	    left: left + width / 2,
+	    top: top + height / 2
+	  }),
 	      line = _codeMirror$coordsCha.line,
 	      ch = _codeMirror$coordsCha.ch;
 
 	  return {
-	    line: line + lineOffset,
+	    line: line + 1,
 	    column: ch
 	  };
 	}
 
 	function updateSelection(target, editor, _ref) {
 	  var linesInScope = _ref.linesInScope,
 	      selection = _ref.selection,
 	      setSelection = _ref.setSelection,
@@ -33889,17 +32825,17 @@ return /******/ (function(modules) { // 
 	    if (!target.classList.contains("debug-expression")) {
 	      clearSelection();
 	    }
 	  }
 
 	  var invalidToken = tokenText === "" || tokenText.match(/[(){},.;\s]/);
 	  var invalidTarget = target.parentElement && !target.parentElement.closest(".CodeMirror-line") || cursorPos.top == 0;
 	  var isUpdating = selection && selection.updating;
-	  var inScope = linesInScope.includes(location.line);
+	  var inScope = linesInScope && linesInScope.includes(location.line);
 
 	  if (invalidTarget || !inScope || isUpdating || invalidToken) {
 	    return;
 	  }
 
 	  setSelection(tokenText, location, cursorPos);
 	}
 
@@ -34251,171 +33187,84 @@ return /******/ (function(modules) { // 
 
 /***/ },
 /* 920 */
 /***/ function(module, exports) {
 
 	module.exports = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 1792 1792\"><path d=\"M1395 736q0 13-10 23l-466 466q-10 10-23 10t-23-10l-466-466q-10-10-10-23t10-23l50-50q10-10 23-10t23 10l393 393 393-393q10-10 23-10t23 10l50 50q10 10 10 23z\" fill=\"#696969\"></path></svg>"
 
 /***/ },
-/* 921 */
-/***/ function(module, exports, __webpack_require__) {
-
-	"use strict";
-
-	Object.defineProperty(exports, "__esModule", {
-	  value: true
-	});
-
-	var _react = __webpack_require__(2);
-
-	var _redux = __webpack_require__(3);
-
-	var _reactRedux = __webpack_require__(151);
-
-	var _classnames = __webpack_require__(175);
-
-	var _classnames2 = _interopRequireDefault(_classnames);
-
-	var _actions = __webpack_require__(244);
-
-	var _actions2 = _interopRequireDefault(_actions);
-
-	var _selectors = __webpack_require__(242);
-
-	var _devtoolsConfig = __webpack_require__(828);
-
-	__webpack_require__(922);
-
-	var _previewFunction = __webpack_require__(701);
-
-	var _previewFunction2 = _interopRequireDefault(_previewFunction);
-
-	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-	class Outline extends _react.Component {
-
-	  constructor(props) {
-	    super(props);
-	    this.state = {};
-	  }
-
-	  selectItem(location) {
-	    var _props = this.props,
-	        selectedSource = _props.selectedSource,
-	        selectSource = _props.selectSource;
-
-	    if (!selectedSource) {
-	      return;
-	    }
-	    var selectedSourceId = selectedSource.get("id");
-	    var startLine = location.start.line;
-	    selectSource(selectedSourceId, { line: startLine });
-	  }
-
-	  renderFunction(func) {
-	    var name = func.name,
-	        location = func.location;
-
-
-	    return _react.DOM.li({
-	      key: `${name}:${location.start.line}:${location.start.column}`,
-	      className: "outline-list__element",
-	      onClick: () => this.selectItem(location)
-	    }, (0, _previewFunction2.default)({ name }));
-	  }
-
-	  renderFunctions() {
-	    var symbols = this.props.symbols;
-
-
-	    return symbols.functions.filter(func => func.name != "anonymous").map(func => this.renderFunction(func));
-	  }
-
-	  render() {
-	    var isHidden = this.props.isHidden;
-
-	    if (!(0, _devtoolsConfig.isEnabled)("outline")) {
-	      return null;
-	    }
-
-	    return _react.DOM.div({ className: (0, _classnames2.default)("outline", { hidden: isHidden }) }, _react.DOM.ul({ className: "outline-list" }, this.renderFunctions()));
-	  }
-	}
-
-	Outline.displayName = "Outline";
-
-	exports.default = (0, _reactRedux.connect)(state => {
-	  var selectedSource = (0, _selectors.getSelectedSource)(state);
-	  return {
-	    symbols: (0, _selectors.getSymbols)(state, selectedSource && selectedSource.toJS()),
-	    selectedSource
-	  };
-	}, dispatch => (0, _redux.bindActionCreators)(_actions2.default, dispatch))(Outline);
-
-/***/ },
-/* 922 */
-/***/ function(module, exports) {
-
-	// removed by extract-text-webpack-plugin
-
-/***/ },
+/* 921 */,
+/* 922 */,
 /* 923 */,
 /* 924 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	var _require = __webpack_require__(925),
 	    MODE = _require.MODE;
 
 	var _require2 = __webpack_require__(926),
 	    REPS = _require2.REPS,
 	    getRep = _require2.getRep;
 
+	var ObjectInspector = __webpack_require__(1154);
+
 	var _require3 = __webpack_require__(927),
-	    createFactories = _require3.createFactories,
 	    parseURLEncodedText = _require3.parseURLEncodedText,
 	    parseURLParams = _require3.parseURLParams,
-	    getSelectableInInspectorGrips = _require3.getSelectableInInspectorGrips,
 	    maybeEscapePropertyName = _require3.maybeEscapePropertyName,
 	    getGripPreviewItems = _require3.getGripPreviewItems;
 
 	module.exports = {
 	  REPS,
 	  getRep,
 	  MODE,
-	  createFactories,
 	  maybeEscapePropertyName,
 	  parseURLEncodedText,
 	  parseURLParams,
-	  getSelectableInInspectorGrips,
-	  getGripPreviewItems
+	  getGripPreviewItems,
+	  ObjectInspector
 	};
 
 /***/ },
 /* 925 */
 /***/ function(module, exports) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	module.exports = {
 	  MODE: {
 	    TINY: Symbol("TINY"),
 	    SHORT: Symbol("SHORT"),
 	    LONG: Symbol("LONG")
 	  }
 	};
 
 /***/ },
 /* 926 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+	__webpack_require__(1149);
+
 	var _require = __webpack_require__(927),
 	    isGrip = _require.isGrip;
 
 	// Load all existing rep templates
 
 
 	var Undefined = __webpack_require__(929);
 	var Null = __webpack_require__(930);
@@ -34458,54 +33307,57 @@ return /******/ (function(modules) { // 
 	 * The right template used for rendering is picked automatically according
 	 * to the current value type. The value must be passed is as 'object'
 	 * property.
 	 */
 	var Rep = function (props) {
 	  var object = props.object,
 	      defaultRep = props.defaultRep;
 
-	  var rep = getRep(object, defaultRep);
+	  var rep = getRep(object, defaultRep, props.noGrip);
 	  return rep(props);
 	};
 
 	// Helpers
 
 	/**
 	 * Return a rep object that is responsible for rendering given
 	 * object.
 	 *
 	 * @param object {Object} Object to be rendered in the UI. This
 	 * can be generic JS object as well as a grip (handle to a remote
 	 * debuggee object).
 	 *
 	 * @param defaultObject {React.Component} The default template
 	 * that should be used to render given object if none is found.
+	 *
+	 * @param noGrip {Boolean} If true, will only check reps not made for remote objects.
 	 */
 	function getRep(object) {
 	  var defaultRep = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Obj;
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
 
 	  var type = typeof object;
 	  if (type == "object" && object instanceof String) {
 	    type = "string";
-	  } else if (object && type == "object" && object.type) {
+	  } else if (object && type == "object" && object.type && noGrip !== true) {
 	    type = object.type;
 	  }
 
 	  if (isGrip(object)) {
 	    type = object.class;
 	  }
 
 	  for (var i = 0; i < reps.length; i++) {
 	    var 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)) {
+	      if (rep.supportsObject(object, type, noGrip)) {
 	        return rep.rep;
 	      }
 	    } catch (err) {
 	      console.error(err);
 	    }
 	  }
 
 	  return defaultRep.rep;
@@ -34551,35 +33403,23 @@ return /******/ (function(modules) { // 
 /***/ },
 /* 927 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// Dependencies
 	var React = __webpack_require__(2);
 
-	// Utils
-	var nodeConstants = __webpack_require__(928);
-
-	/**
-	 * Create React factories for given arguments.
-	 * Example:
-	 *   const { Rep } = createFactories(require("./rep"));
-	 */
-	function createFactories(args) {
-	  var result = {};
-	  for (var 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) {
@@ -34828,54 +33668,16 @@ return /******/ (function(modules) { // 
 	      "Invalid object");
 	    }
 	  };
 	  wrappedFunction.propTypes = renderMethod.propTypes;
 	  return wrappedFunction;
 	}
 
 	/**
-	 * Get an array of all the items from the grip in parameter (including the grip itself)
-	 * which can be selected in the inspector.
-	 *
-	 * @param {Object} Grip
-	 * @return {Array} Flat array of the grips which can be selected in the inspector
-	 */
-	function getSelectableInInspectorGrips(grip) {
-	  var grips = new Set(getFlattenedGrips([grip]));
-	  return [].concat(_toConsumableArray(grips)).filter(isGripSelectableInInspector);
-	}
-
-	/**
-	 * Indicate if a Grip can be selected in the inspector,
-	 * i.e. if it represents a node element.
-	 *
-	 * @param {Object} Grip
-	 * @return {Boolean}
-	 */
-	function isGripSelectableInInspector(grip) {
-	  return grip && typeof grip === "object" && grip.preview && [nodeConstants.TEXT_NODE, nodeConstants.ELEMENT_NODE].includes(grip.preview.nodeType);
-	}
-
-	/**
-	 * Get a flat array of all the grips and their preview items.
-	 *
-	 * @param {Array} Grips
-	 * @return {Array} Flat array of the grips and their preview items
-	 */
-	function getFlattenedGrips(grips) {
-	  return grips.reduce((res, grip) => {
-	    var previewItems = getGripPreviewItems(grip);
-	    var flatPreviewItems = previewItems.length > 0 ? getFlattenedGrips(previewItems) : [];
-
-	    return [].concat(_toConsumableArray(res), [grip], _toConsumableArray(flatPreviewItems));
-	  }, []);
-	}
-
-	/**
 	 * Get preview items from a Grip.
 	 *
 	 * @param {Object} Grip from which we want the preview items
 	 * @return {Array} Array of the preview items of the grip, or an empty array
 	 *                 if the grip does not have preview items
 	 */
 	function getGripPreviewItems(grip) {
 	  if (!grip) {
@@ -34927,75 +33729,42 @@ return /******/ (function(modules) { // 
 	    }
 
 	    return propertiesValues;
 	  }
 
 	  return [];
 	}
 
-	/**
-	 * Returns a new element wrapped with a component, props.objectLink if it exists,
-	 * or a span if there are multiple children, or directly the child if only one is passed.
-	 *
-	 * @param {Object} props A Rep "props" object that may contain `objectLink`
-	 *                 and `object` properties.
-	 * @param {Object} config Object to pass as props to the `objectLink` component.
-	 * @param {...Element} children Elements to be wrapped with the `objectLink` component.
-	 * @return {Element} Element, wrapped or not, depending if `objectLink`
-	 *                   was supplied in props.
-	 */
-	function safeObjectLink(props, config) {
-	  var _React$DOM;
-
-	  var objectLink = props.objectLink,
-	      object = props.object;
-
-	  for (var _len = arguments.length, children = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
-	    children[_key - 2] = arguments[_key];
-	  }
-
-	  if (objectLink) {
-	    return objectLink.apply(undefined, [Object.assign({
-	      object
-	    }, config)].concat(children));
-	  }
-
-	  if ((!config || Object.keys(config).length === 0) && children.length === 1) {
-	    return children[0];
-	  }
-
-	  return (_React$DOM = React.DOM).span.apply(_React$DOM, [config].concat(children));
-	}
-
-	module.exports = {
-	  createFactories,
+	module.exports = {
 	  isGrip,
 	  cropString,
 	  rawCropString,
 	  sanitizeString,
 	  escapeString,
 	  wrapRender,
 	  cropMultipleLines,
 	  parseURLParams,
 	  parseURLEncodedText,
 	  getFileName,
 	  getURLDisplayString,
-	  getSelectableInInspectorGrips,
 	  maybeEscapePropertyName,
-	  safeObjectLink,
 	  getGripPreviewItems
 	};
 
 /***/ },
 /* 928 */
 /***/ function(module, exports) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	module.exports = {
 	  ELEMENT_NODE: 1,
 	  ATTRIBUTE_NODE: 2,
 	  TEXT_NODE: 3,
 	  CDATA_SECTION_NODE: 4,
 	  ENTITY_REFERENCE_NODE: 5,
 	  ENTITY_NODE: 6,
 	  PROCESSING_INSTRUCTION_NODE: 7,
@@ -35015,16 +33784,20 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 929 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// Dependencies
 	var React = __webpack_require__(2);
 
 	var _require = __webpack_require__(927),
 	    wrapRender = _require.wrapRender;
 
 	// Shortcuts
 
@@ -35035,36 +33808,42 @@ return /******/ (function(modules) { // 
 	 * Renders undefined value
 	 */
 
 	var Undefined = function () {
 	  return span({ className: "objectBox objectBox-undefined" }, "undefined");
 	};
 
 	function supportsObject(object, type) {
-	  if (object && object.type && object.type == "undefined") {
-	    return true;
-	  }
-
-	  return type == "undefined";
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+	  if (noGrip === true) {
+	    return false;
+	  }
+
+	  return object && object.type && object.type == "undefined" || type == "undefined";
 	}
 
 	// Exports from this module
 
 	module.exports = {
 	  rep: wrapRender(Undefined),
 	  supportsObject
 	};
 
 /***/ },
 /* 930 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// Dependencies
 	var React = __webpack_require__(2);
 
 	var _require = __webpack_require__(927),
 	    wrapRender = _require.wrapRender;
 
 	// Shortcuts
 
@@ -35075,16 +33854,22 @@ return /******/ (function(modules) { // 
 	 * Renders null value
 	 */
 
 	function Null(props) {
 	  return span({ className: "objectBox objectBox-null" }, "null");
 	}
 
 	function supportsObject(object, type) {
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+	  if (noGrip === true) {
+	    return false;
+	  }
+
 	  if (object && object.type && object.type == "null") {
 	    return true;
 	  }
 
 	  return object == null;
 	}
 
 	// Exports from this module
@@ -35095,16 +33880,20 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 931 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// Dependencies
 	var React = __webpack_require__(2);
 
 	var _require = __webpack_require__(927),
 	    escapeString = _require.escapeString,
 	    rawCropString = _require.rawCropString,
 	    sanitizeString = _require.sanitizeString,
 	    wrapRender = _require.wrapRender;
@@ -35168,16 +33957,20 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 932 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// Dependencies
 	var React = __webpack_require__(2);
 
 	var _require = __webpack_require__(927),
 	    escapeString = _require.escapeString,
 	    sanitizeString = _require.sanitizeString,
 	    isGrip = _require.isGrip,
 	    wrapRender = _require.wrapRender;
@@ -35208,32 +34001,38 @@ return /******/ (function(modules) { // 
 	      useQuotes = _props$useQuotes === undefined ? true : _props$useQuotes,
 	      _props$escapeWhitespa = props.escapeWhitespace,
 	      escapeWhitespace = _props$escapeWhitespa === undefined ? true : _props$escapeWhitespa;
 	  var fullText = object.fullText,
 	      initial = object.initial,
 	      length = object.length;
 
 
-	  var config = { className: "objectBox objectBox-string" };
+	  var config = {
+	    "data-link-actor-id": object.actor,
+	    className: "objectBox objectBox-string"
+	  };
+
 	  if (style) {
 	    config.style = style;
 	  }
 
 	  var string = member && member.open ? fullText || initial : initial.substring(0, cropLimit);
 
 	  if (string.length < length) {
 	    string += "\u2026";
 	  }
 	  var formattedString = useQuotes ? escapeString(string, escapeWhitespace) : sanitizeString(string);
 	  return span(config, formattedString);
 	}
 
 	function supportsObject(object, type) {
-	  if (!isGrip(object)) {
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+	  if (noGrip === true || !isGrip(object)) {
 	    return false;
 	  }
 	  return object.type === "longString";
 	}
 
 	// Exports from this module
 	module.exports = {
 	  rep: wrapRender(LongStringRep),
@@ -35241,16 +34040,20 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 933 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// Dependencies
 	var React = __webpack_require__(2);
 
 	var _require = __webpack_require__(927),
 	    wrapRender = _require.wrapRender;
 
 	// Shortcuts
 
@@ -35291,21 +34094,24 @@ return /******/ (function(modules) { // 
 /***/ },
 /* 934 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// Dependencies
 	var React = __webpack_require__(2);
 
 	var _require = __webpack_require__(927),
-	    safeObjectLink = _require.safeObjectLink,
 	    wrapRender = _require.wrapRender;
 
 	var Caption = __webpack_require__(935);
 
 	var _require2 = __webpack_require__(925),
 	    MODE = _require2.MODE;
 
 	var ModePropType = React.PropTypes.oneOf(
@@ -35316,17 +34122,16 @@ return /******/ (function(modules) { // 
 	var DOM = React.DOM;
 
 	/**
 	 * Renders an array. The array is enclosed by left and right bracket
 	 * and the max number of rendered items depends on the current mode.
 	 */
 	ArrayRep.propTypes = {
 	  mode: ModePropType,
-	  objectLink: React.PropTypes.func,
 	  object: React.PropTypes.array.isRequired
 	};
 
 	function ArrayRep(props) {
 	  var object = props.object,
 	      _props$mode = props.mode,
 	      mode = _props$mode === undefined ? MODE.SHORT : _props$mode;
 
@@ -35337,28 +34142,25 @@ return /******/ (function(modules) { // 
 	    return space ? { left: "[ ", right: " ]" } : { left: "[", right: "]" };
 	  };
 
 	  if (mode === MODE.TINY) {
 	    var isEmpty = object.length === 0;
 	    items = [DOM.span({ className: "length" }, isEmpty ? "" : object.length)];
 	    brackets = needSpace(false);
 	  } else {
-	    var max = mode === MODE.SHORT ? 3 : 10;
-	    items = arrayIterator(props, object, max);
+	    items = arrayIterator(props, object, maxLengthMap.get(mode));
 	    brackets = needSpace(items.length > 0);
 	  }
 
 	  return DOM.span.apply(DOM, [{
-	    className: "objectBox objectBox-array" }, safeObjectLink(props, {
-	    className: "arrayLeftBracket",
-	    object: object
-	  }, brackets.left)].concat(_toConsumableArray(items), [safeObjectLink(props, {
-	    className: "arrayRightBracket",
-	    object: object
+	    className: "objectBox objectBox-array" }, DOM.span({
+	    className: "arrayLeftBracket"
+	  }, brackets.left)].concat(_toConsumableArray(items), [DOM.span({
+	    className: "arrayRightBracket"
 	  }, brackets.right), DOM.span({
 	    className: "arrayProperties",
 	    role: "group" })]));
 	}
 
 	function arrayIterator(props, array, max) {
 	  var items = [];
 	  var delim = void 0;
@@ -35381,19 +34183,17 @@ return /******/ (function(modules) { // 
 	        mode: MODE.TINY,
 	        delim: delim
 	      }));
 	    }
 	  }
 
 	  if (array.length > max) {
 	    items.push(Caption({
-	      object: safeObjectLink(props, {
-	        object: props.object
-	      }, array.length - max + " more…")
+	      object: DOM.span({}, "more…")
 	    }));
 	  }
 
 	  return items;
 	}
 
 	/**
 	 * Renders array item. Individual values are separated by a comma.
@@ -35414,28 +34214,37 @@ return /******/ (function(modules) { // 
 
 	  return DOM.span({}, Rep({ object: object, mode: mode }), delim);
 	}
 
 	function supportsObject(object, type) {
 	  return Array.isArray(object) || Object.prototype.toString.call(object) === "[object Arguments]";
 	}
 
+	var maxLengthMap = new Map();
+	maxLengthMap.set(MODE.SHORT, 3);
+	maxLengthMap.set(MODE.LONG, 10);
+
 	// Exports from this module
 	module.exports = {
 	  rep: wrapRender(ArrayRep),
-	  supportsObject
+	  supportsObject,
+	  maxLengthMap
 	};
 
 /***/ },
 /* 935 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// Dependencies
 	var React = __webpack_require__(2);
 	var DOM = React.DOM;
 
 	var _require = __webpack_require__(927),
 	    wrapRender = _require.wrapRender;
 
 	/**
@@ -35458,21 +34267,24 @@ return /******/ (function(modules) { // 
 /***/ },
 /* 936 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// Dependencies
 	var React = __webpack_require__(2);
 
 	var _require = __webpack_require__(927),
-	    safeObjectLink = _require.safeObjectLink,
 	    wrapRender = _require.wrapRender;
 
 	var Caption = __webpack_require__(935);
 	var PropRep = __webpack_require__(937);
 
 	var _require2 = __webpack_require__(925),
 	    MODE = _require2.MODE;
 	// Shortcuts
@@ -35483,38 +34295,37 @@ return /******/ (function(modules) { // 
 	 * Renders an object. An object is represented by a list of its
 	 * properties enclosed in curly brackets.
 	 */
 
 	ObjectRep.propTypes = {
 	  object: React.PropTypes.object.isRequired,
 	  // @TODO Change this to Object.values once it's supported in Node's version of V8
 	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
-	  objectLink: React.PropTypes.func,
 	  title: React.PropTypes.string
 	};
 
 	function ObjectRep(props) {
 	  var object = props.object;
 	  var propsArray = safePropIterator(props, object);
 
 	  if (props.mode === MODE.TINY || !propsArray.length) {
 	    return span({ className: "objectBox objectBox-object" }, getTitle(props, object));
 	  }
 
-	  return span.apply(undefined, [{ className: "objectBox objectBox-object" }, getTitle(props, object), safeObjectLink(props, {
+	  return span.apply(undefined, [{ className: "objectBox objectBox-object" }, getTitle(props, object), span({
 	    className: "objectLeftBrace"
-	  }, " { ")].concat(_toConsumableArray(propsArray), [safeObjectLink(props, {
+	  }, " { ")].concat(_toConsumableArray(propsArray), [span({
 	    className: "objectRightBrace"
 	  }, " }")]));
 	}
 
 	function getTitle(props, object) {
 	  var title = props.title || object.class || "Object";
-	  return safeObjectLink(props, { className: "objectTitle" }, title);
+	  return span({ className: "objectTitle" }, title);
 	}
 
 	function safePropIterator(props, object, max) {
 	  max = typeof max === "undefined" ? 3 : max;
 	  try {
 	    return propIterator(props, object, max);
 	  } catch (err) {
 	    console.error(err);
@@ -35539,50 +34350,63 @@ return /******/ (function(modules) { // 
 
 	  if (Object.keys(interestingObject).length < max) {
 	    // There are not enough props yet (or at least, not enough props to
 	    // be able to know whether we should print "more…" or not).
 	    // Let's display also empty members and functions.
 	    interestingObject = Object.assign({}, interestingObject, getFilteredObject(object, max - Object.keys(interestingObject).length, (type, value) => !isInterestingProp(type, value)));
 	  }
 
-	  var truncated = Object.keys(object).length > max;
-	  var propsArray = getPropsArray(interestingObject, truncated);
-	  if (truncated) {
+	  var propsArray = getPropsArray(interestingObject);
+	  if (Object.keys(object).length > max) {
 	    propsArray.push(Caption({
-	      object: safeObjectLink(props, {}, Object.keys(object).length - max + " more…")
+	      object: span({}, "more…")
 	    }));
 	  }
 
-	  return propsArray;
+	  return unfoldProps(propsArray);
+	}
+
+	function unfoldProps(items) {
+	  return items.reduce((res, item, index) => {
+	    if (Array.isArray(item)) {
+	      res = res.concat(item);
+	    } else {
+	      res.push(item);
+	    }
+
+	    // Interleave commas between elements
+	    if (index !== items.length - 1) {
+	      res.push(", ");
+	    }
+	    return res;
+	  }, []);
 	}
 
 	/**
 	 * Get an array of components representing the properties of the object
 	 *
 	 * @param {Object} object
-	 * @param {Boolean} truncated true if the object is truncated.
 	 * @return {Array} Array of PropRep.
 	 */
-	function getPropsArray(object, truncated) {
+	function getPropsArray(object) {
 	  var propsArray = [];
 
 	  if (!object) {
 	    return propsArray;
 	  }
 
 	  // Hardcode tiny mode to avoid recursive handling.
 	  var mode = MODE.TINY;
 	  var objectKeys = Object.keys(object);
 	  return objectKeys.map((name, i) => PropRep({
 	    mode,
 	    name,
 	    object: object[name],
-	    equal: ": ",
-	    delim: i !== objectKeys.length - 1 || truncated ? ", " : null
+	    equal: ": "
 	  }));
 	}
 
 	/**
 	 * Get a copy of the object filtered by a given predicate.
 	 *
 	 * @param {Object} object.
 	 * @param {Number} max The maximum length of keys array.
@@ -35627,16 +34451,20 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 937 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// Dependencies
 	var React = __webpack_require__(2);
 
 	var _require = __webpack_require__(927),
 	    maybeEscapePropertyName = _require.maybeEscapePropertyName,
 	    wrapRender = _require.wrapRender;
 
 	var _require2 = __webpack_require__(925),
@@ -35652,40 +34480,43 @@ return /******/ (function(modules) { // 
 	 * It's used to render object properties.
 	 */
 
 	PropRep.propTypes = {
 	  // Property name.
 	  name: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.object]).isRequired,
 	  // Equal character rendered between property name and value.
 	  equal: React.PropTypes.string,
-	  // 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])),
-	  objectLink: React.PropTypes.func,
 	  onDOMNodeMouseOver: React.PropTypes.func,
 	  onDOMNodeMouseOut: React.PropTypes.func,
 	  onInspectIconClick: React.PropTypes.func,
 	  // Normally a PropRep will quote a property name that isn't valid
 	  // when unquoted; but this flag can be used to suppress the
 	  // quoting.
 	  suppressQuotes: React.PropTypes.bool
 	};
 
+	/**
+	 * Function that given a name, a delimiter and an object returns an array
+	 * of React elements representing an object property (e.g. `name: value`)
+	 *
+	 * @param {Object} props
+	 * @return {Array} Array of React elements.
+	 */
 	function PropRep(props) {
 	  var Grip = __webpack_require__(938);
 
 	  var _require3 = __webpack_require__(926),
 	      Rep = _require3.Rep;
 
 	  var name = props.name,
 	      mode = props.mode,
 	      equal = props.equal,
-	      delim = props.delim,
 	      suppressQuotes = props.suppressQuotes;
 
 
 	  var key = void 0;
 	  // The key can be a simple string, for plain objects,
 	  // or another object for maps and weakmaps.
 	  if (typeof name === "string") {
 	    if (!suppressQuotes) {
@@ -35695,46 +34526,42 @@ return /******/ (function(modules) { // 
 	  } else {
 	    key = Rep(Object.assign({}, props, {
 	      object: name,
 	      mode: mode || MODE.TINY,
 	      defaultRep: Grip
 	    }));
 	  }
 
-	  var delimElement = void 0;
-	  if (delim) {
-	    delimElement = span({
-	      "className": "objectComma"
-	    }, delim);
-	  }
-
-	  return span({}, key, span({
+	  return [key, span({
 	    "className": "objectEqual"
-	  }, equal), Rep(Object.assign({}, props)), delimElement);
+	  }, equal), Rep(Object.assign({}, props))];
 	}
 
 	// Exports from this module
 	module.exports = wrapRender(PropRep);
 
 /***/ },
 /* 938 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// ReactJS
 	var React = __webpack_require__(2);
 	// Dependencies
 
 	var _require = __webpack_require__(927),
 	    isGrip = _require.isGrip,
-	    safeObjectLink = _require.safeObjectLink,
 	    wrapRender = _require.wrapRender;
 
 	var Caption = __webpack_require__(935);
 	var PropRep = __webpack_require__(937);
 
 	var _require2 = __webpack_require__(925),
 	    MODE = _require2.MODE;
 	// Shortcuts
@@ -35749,44 +34576,55 @@ return /******/ (function(modules) { // 
 	 */
 
 	GripRep.propTypes = {
 	  object: React.PropTypes.object.isRequired,
 	  // @TODO Change this to Object.values once it's supported in Node's version of V8
 	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
 	  isInterestingProp: React.PropTypes.func,
 	  title: React.PropTypes.string,
-	  objectLink: React.PropTypes.func,
 	  onDOMNodeMouseOver: React.PropTypes.func,
 	  onDOMNodeMouseOut: React.PropTypes.func,
-	  onInspectIconClick: React.PropTypes.func
+	  onInspectIconClick: React.PropTypes.func,
+	  noGrip: React.PropTypes.bool
 	};
 
 	function GripRep(props) {
-	  var object = props.object;
-	  var propsArray = safePropIterator(props, object, props.mode === MODE.LONG ? 10 : 3);
-
-	  if (props.mode === MODE.TINY) {
-	    return span({ className: "objectBox objectBox-object" }, getTitle(props, object));
-	  }
-
-	  return span.apply(undefined, [{ className: "objectBox objectBox-object" }, getTitle(props, object), safeObjectLink(props, {
+	  var _props$mode = props.mode,
+	      mode = _props$mode === undefined ? MODE.SHORT : _props$mode,
+	      object = props.object;
+
+
+	  var config = {
+	    "data-link-actor-id": object.actor,
+	    className: "objectBox objectBox-object"
+	  };
+
+	  if (mode === MODE.TINY) {
+	    return span(config, getTitle(props, object));
+	  }
+
+	  var propsArray = safePropIterator(props, object, maxLengthMap.get(mode));
+
+	  return span.apply(undefined, [config, getTitle(props, object), span({
 	    className: "objectLeftBrace"
-	  }, " { ")].concat(_toConsumableArray(propsArray), [safeObjectLink(props, {
+	  }, " { ")].concat(_toConsumableArray(propsArray), [span({
 	    className: "objectRightBrace"
 	  }, " }")]));
 	}
 
 	function getTitle(props, object) {
 	  var title = props.title || object.class || "Object";
-	  return safeObjectLink(props, {}, title);
+	  return span({
+	    className: "objectTitle"
+	  }, title);
 	}
 
 	function safePropIterator(props, object, max) {
-	  max = typeof max === "undefined" ? 3 : max;
+	  max = typeof max === "undefined" ? maxLengthMap.get(MODE.SHORT) : max;
 	  try {
 	    return propIterator(props, object, max);
 	  } catch (err) {
 	    console.error(err);
 	  }
 	  return [];
 	}
 
@@ -35818,65 +34656,76 @@ return /******/ (function(modules) { // 
 	  var indexes = getPropIndexes(properties, max, isInterestingProp);
 	  if (indexes.length < max && indexes.length < propertiesLength) {
 	    // There are not enough props yet. Then add uninteresting props to display them.
 	    indexes = indexes.concat(getPropIndexes(properties, max - indexes.length, (t, value, name) => {
 	      return !isInterestingProp(t, value, name);
 	    }));
 	  }
 
-	  var truncate = Object.keys(properties).length > max;
 	  // The server synthesizes some property names for a Proxy, like
 	  // <target> and <handler>; we don't want to quote these because,
 	  // as synthetic properties, they appear more natural when
 	  // unquoted.
 	  var suppressQuotes = object.class === "Proxy";
-	  var propsArray = getProps(props, properties, indexes, truncate, suppressQuotes);
-	  if (truncate) {
+	  var propsArray = getProps(props, properties, indexes, suppressQuotes);
+	  if (Object.keys(properties).length > max || propertiesLength > max) {
 	    // There are some undisplayed props. Then display "more...".
 	    propsArray.push(Caption({
-	      object: safeObjectLink(props, {}, `${propertiesLength - max} more…`)
+	      object: span({}, "more…")
 	    }));
 	  }
 
-	  return propsArray;
+	  return unfoldProps(propsArray);
+	}
+
+	function unfoldProps(items) {
+	  return items.reduce((res, item, index) => {
+	    if (Array.isArray(item)) {
+	      res = res.concat(item);
+	    } else {
+	      res.push(item);
+	    }
+
+	    // Interleave commas between elements
+	    if (index !== items.length - 1) {
+	      res.push(", ");
+	    }
+	    return res;
+	  }, []);
 	}
 
 	/**
 	 * Get props ordered by index.
 	 *
 	 * @param {Object} componentProps Grip Component props.
 	 * @param {Object} properties Properties of the object the Grip describes.
 	 * @param {Array} indexes Indexes of properties.
-	 * @param {Boolean} truncate true if the grip will be truncated.
 	 * @param {Boolean} suppressQuotes true if we should suppress quotes
 	 *                  on property names.
 	 * @return {Array} Props.
 	 */
-	function getProps(componentProps, properties, indexes, truncate, suppressQuotes) {
+	function getProps(componentProps, properties, indexes, suppressQuotes) {
 	  // Make indexes ordered by ascending.
 	  indexes.sort(function (a, b) {
 	    return a - b;
 	  });
 
 	  var propertiesKeys = Object.keys(properties);
 	  return indexes.map(i => {
 	    var name = propertiesKeys[i];
 	    var value = getPropValue(properties[name]);
 
 	    return PropRep(Object.assign({}, componentProps, {
 	      mode: MODE.TINY,
 	      name,
 	      object: value,
 	      equal: ": ",
-	      delim: i !== indexes.length - 1 || truncate ? ", " : null,
 	      defaultRep: Grip,
-	      // Do not propagate title and objectLink to properties reps
 	      title: null,
-	      objectLink: null,
 	      suppressQuotes
 	    }));
 	  });
 	}
 
 	/**
 	 * Get the indexes of props in the object.
 	 *
@@ -35928,37 +34777,48 @@ return /******/ (function(modules) { // 
 	      value = property.getterValue;
 	    }
 	  }
 	  return value;
 	}
 
 	// Registration
 	function supportsObject(object, type) {
-	  if (!isGrip(object)) {
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+	  if (noGrip === true || !isGrip(object)) {
 	    return false;
 	  }
 	  return object.preview && object.preview.ownProperties;
 	}
 
+	var maxLengthMap = new Map();
+	maxLengthMap.set(MODE.SHORT, 3);
+	maxLengthMap.set(MODE.LONG, 10);
+
 	// Grip is used in propIterator and has to be defined here.
 	var Grip = {
 	  rep: wrapRender(GripRep),
-	  supportsObject
+	  supportsObject,
+	  maxLengthMap
 	};
 
 	// Exports from this module
 	module.exports = Grip;
 
 /***/ },
 /* 939 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// Dependencies
 	var React = __webpack_require__(2);
 
 	var _require = __webpack_require__(927),
 	    wrapRender = _require.wrapRender;
 
 	// Shortcuts
 
@@ -35992,16 +34852,20 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 940 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// Dependencies
 	var React = __webpack_require__(2);
 
 	var _require = __webpack_require__(927),
 	    wrapRender = _require.wrapRender;
 
 	// Shortcuts
 
@@ -36012,17 +34876,20 @@ return /******/ (function(modules) { // 
 	 * Renders a Infinity object
 	 */
 
 	InfinityRep.propTypes = {
 	  object: React.PropTypes.object.isRequired
 	};
 
 	function InfinityRep(props) {
-	  return span({ className: "objectBox objectBox-number" }, props.object.type);
+	  var object = props.object;
+
+
+	  return span({ className: "objectBox objectBox-number" }, object.type);
 	}
 
 	function supportsObject(object, type) {
 	  return type == "Infinity" || type == "-Infinity";
 	}
 
 	// Exports from this module
 	module.exports = {
@@ -36031,16 +34898,20 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 941 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// Dependencies
 	var React = __webpack_require__(2);
 
 	var _require = __webpack_require__(927),
 	    wrapRender = _require.wrapRender;
 
 	// Shortcuts
 
@@ -36066,58 +34937,65 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 942 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// ReactJS
 	var React = __webpack_require__(2);
 
 	// Reps
 
 	var _require = __webpack_require__(927),
 	    isGrip = _require.isGrip,
-	    safeObjectLink = _require.safeObjectLink,
 	    wrapRender = _require.wrapRender;
 
 	var _require2 = __webpack_require__(931),
 	    StringRep = _require2.rep;
 
 	// Shortcuts
 
 
 	var span = React.DOM.span;
 
 	/**
 	 * Renders DOM attribute
 	 */
 
 	Attribute.propTypes = {
-	  object: React.PropTypes.object.isRequired,
-	  objectLink: React.PropTypes.func
+	  object: React.PropTypes.object.isRequired
 	};
 
 	function Attribute(props) {
 	  var object = props.object;
 
 	  var value = object.preview.value;
 
-	  return safeObjectLink(props, { className: "objectLink-Attr" }, span({ className: "attrTitle" }, getTitle(object)), span({ className: "attrEqual" }, "="), StringRep({ object: value }));
+	  return span({
+	    "data-link-actor-id": object.actor,
+	    className: "objectLink-Attr"
+	  }, span({ className: "attrTitle" }, getTitle(object)), span({ className: "attrEqual" }, "="), StringRep({ object: value }));
 	}
 
 	function getTitle(grip) {
 	  return grip.preview.nodeName;
 	}
 
 	// Registration
 	function supportsObject(grip, type) {
-	  if (!isGrip(grip)) {
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+	  if (noGrip === true || !isGrip(grip)) {
 	    return false;
 	  }
 
 	  return type == "Attr" && grip.preview;
 	}
 
 	module.exports = {
 	  rep: wrapRender(Attribute),
@@ -36125,59 +35003,68 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 943 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// ReactJS
 	var React = __webpack_require__(2);
 
 	// Reps
 
 	var _require = __webpack_require__(927),
 	    isGrip = _require.isGrip,
-	    safeObjectLink = _require.safeObjectLink,
 	    wrapRender = _require.wrapRender;
 
 	// Shortcuts
 
 
 	var span = React.DOM.span;
 
 	/**
 	 * Used to render JS built-in Date() object.
 	 */
 
 	DateTime.propTypes = {
-	  object: React.PropTypes.object.isRequired,
-	  objectLink: React.PropTypes.func
+	  object: React.PropTypes.object.isRequired
 	};
 
 	function DateTime(props) {
 	  var grip = props.object;
 	  var date = void 0;
 	  try {
-	    date = span({ className: "objectBox" }, getTitle(props, grip), span({ className: "Date" }, new Date(grip.preview.timestamp).toISOString()));
+	    date = span({
+	      "data-link-actor-id": grip.actor,
+	      className: "objectBox"
+	    }, getTitle(grip), span({ className: "Date" }, new Date(grip.preview.timestamp).toISOString()));
 	  } catch (e) {
 	    date = span({ className: "objectBox" }, "Invalid Date");
 	  }
 
 	  return date;
 	}
 
-	function getTitle(props, grip) {
-	  return safeObjectLink(props, {}, grip.class + " ");
+	function getTitle(grip) {
+	  return span({
+	    className: "objectTitle"
+	  }, grip.class + " ");
 	}
 
 	// Registration
 	function supportsObject(grip, type) {
-	  if (!isGrip(grip)) {
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+	  if (noGrip === true || !isGrip(grip)) {
 	    return false;
 	  }
 
 	  return type == "Date" && grip.preview;
 	}
 
 	// Exports from this module
 	module.exports = {
@@ -36186,59 +35073,68 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 944 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// ReactJS
 	var React = __webpack_require__(2);
 
 	// Reps
 
 	var _require = __webpack_require__(927),
 	    isGrip = _require.isGrip,
 	    getURLDisplayString = _require.getURLDisplayString,
-	    safeObjectLink = _require.safeObjectLink,
 	    wrapRender = _require.wrapRender;
 
 	// Shortcuts
 
 
 	var span = React.DOM.span;
 
 	/**
 	 * Renders DOM document object.
 	 */
 
 	Document.propTypes = {
-	  object: React.PropTypes.object.isRequired,
-	  objectLink: React.PropTypes.func
+	  object: React.PropTypes.object.isRequired
 	};
 
 	function Document(props) {
 	  var grip = props.object;
 
-	  return span({ className: "objectBox objectBox-object" }, getTitle(props, grip), span({ className: "objectPropValue" }, getLocation(grip)));
+	  return span({
+	    "data-link-actor-id": grip.actor,
+	    className: "objectBox objectBox-object"
+	  }, getTitle(grip), span({ className: "objectPropValue" }, getLocation(grip)));
 	}
 
 	function getLocation(grip) {
 	  var location = grip.preview.location;
 	  return location ? getURLDisplayString(location) : "";
 	}
 
-	function getTitle(props, grip) {
-	  return safeObjectLink(props, {}, grip.class + " ");
+	function getTitle(grip) {
+	  return span({
+	    className: "objectTitle"
+	  }, grip.class + " ");
 	}
 
 	// Registration
 	function supportsObject(object, type) {
-	  if (!isGrip(object)) {
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+	  if (noGrip === true || !isGrip(object)) {
 	    return false;
 	  }
 
 	  return object.preview && type == "HTMLDocument";
 	}
 
 	// Exports from this module
 	module.exports = {
@@ -36247,16 +35143,20 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 945 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// ReactJS
 	var React = __webpack_require__(2);
 
 	// Reps
 
 	var _require = __webpack_require__(927),
 	    isGrip = _require.isGrip,
 	    wrapRender = _require.wrapRender;
@@ -36269,17 +35169,16 @@ return /******/ (function(modules) { // 
 
 	/**
 	 * Renders DOM event objects.
 	 */
 
 
 	Event.propTypes = {
 	  object: React.PropTypes.object.isRequired,
-	  objectLink: React.PropTypes.func,
 	  // @TODO Change this to Object.values once it's supported in Node's version of V8
 	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
 	  onDOMNodeMouseOver: React.PropTypes.func,
 	  onDOMNodeMouseOut: React.PropTypes.func,
 	  onInspectIconClick: React.PropTypes.func
 	};
 
 	function Event(props) {
@@ -36336,17 +35235,19 @@ return /******/ (function(modules) { // 
 	  if (preview.eventKind == "key" && preview.modifiers && preview.modifiers.length) {
 	    title = `${title} ${preview.modifiers.join("-")}`;
 	  }
 	  return title;
 	}
 
 	// Registration
 	function supportsObject(grip, type) {
-	  if (!isGrip(grip)) {
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+	  if (noGrip === true || !isGrip(grip)) {
 	    return false;
 	  }
 
 	  return grip.preview && grip.preview.kind == "DOMEvent";
 	}
 
 	// Exports from this module
 	module.exports = {
@@ -36355,71 +35256,96 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 946 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// ReactJS
 	var React = __webpack_require__(2);
 
 	// Reps
 
 	var _require = __webpack_require__(927),
 	    isGrip = _require.isGrip,
 	    cropString = _require.cropString,
-	    safeObjectLink = _require.safeObjectLink,
 	    wrapRender = _require.wrapRender;
 
 	// Shortcuts
 
 
 	var span = React.DOM.span;
 
 	/**
 	 * This component represents a template for Function objects.
 	 */
 
 	FunctionRep.propTypes = {
 	  object: React.PropTypes.object.isRequired,
-	  objectLink: React.PropTypes.func
+	  parameterNames: React.PropTypes.array
 	};
 
 	function FunctionRep(props) {
 	  var grip = props.object;
 
-	  return (
+	  return span.apply(undefined, [{
+	    "data-link-actor-id": grip.actor,
+	    className: "objectBox objectBox-function",
 	    // Set dir="ltr" to prevent function parentheses from
 	    // appearing in the wrong direction
-	    span({ dir: "ltr", className: "objectBox objectBox-function" }, getTitle(props, grip), summarizeFunction(grip))
-	  );
+	    dir: "ltr"
+	  }, getTitle(props, grip), summarizeFunction(grip), "("].concat(_toConsumableArray(renderParams(props)), [")"]));
 	}
 
 	function getTitle(props, grip) {
 	  var title = "function ";
 	  if (grip.isGenerator) {
 	    title = "function* ";
 	  }
 	  if (grip.isAsync) {
 	    title = "async " + title;
 	  }
 
-	  return safeObjectLink(props, {}, title);
+	  return span({
+	    className: "objectTitle"
+	  }, title);
 	}
 
 	function summarizeFunction(grip) {
 	  var name = grip.userDisplayName || grip.displayName || grip.name || "";
-	  return cropString(name + "()", 100);
+	  return cropString(name, 100);
+	}
+
+	function renderParams(props) {
+	  var _props$parameterNames = props.parameterNames,
+	      parameterNames = _props$parameterNames === undefined ? [] : _props$parameterNames;
+
+
+	  return parameterNames.filter(param => param).reduce((res, param, index, arr) => {
+	    res.push(span({ className: "param" }, param));
+	    if (index < arr.length - 1) {
+	      res.push(span({ className: "delimiter" }, ", "));
+	    }
+	    return res;
+	  }, []);
 	}
 
 	// Registration
 	function supportsObject(grip, type) {
-	  if (!isGrip(grip)) {
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+	  if (noGrip === true || !isGrip(grip)) {
 	    return type == "function";
 	  }
 
 	  return type == "Function";
 	}
 
 	// Exports from this module
 
@@ -36431,23 +35357,26 @@ return /******/ (function(modules) { // 
 /***/ },
 /* 947 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// ReactJS
 	var React = __webpack_require__(2);
 	// Dependencies
 
 	var _require = __webpack_require__(927),
 	    isGrip = _require.isGrip,
-	    safeObjectLink = _require.safeObjectLink,
 	    wrapRender = _require.wrapRender;
 
 	var PropRep = __webpack_require__(937);
 
 	var _require2 = __webpack_require__(925),
 	    MODE = _require2.MODE;
 	// Shortcuts
 
@@ -36457,73 +35386,86 @@ return /******/ (function(modules) { // 
 	/**
 	 * Renders a DOM Promise object.
 	 */
 
 	PromiseRep.propTypes = {
 	  object: React.PropTypes.object.isRequired,
 	  // @TODO Change this to Object.values once it's supported in Node's version of V8
 	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
-	  objectLink: React.PropTypes.func,
 	  onDOMNodeMouseOver: React.PropTypes.func,
 	  onDOMNodeMouseOut: React.PropTypes.func,
 	  onInspectIconClick: React.PropTypes.func
 	};
 
 	function PromiseRep(props) {
 	  var object = props.object;
 	  var promiseState = object.promiseState;
 
 
+	  var config = {
+	    "data-link-actor-id": object.actor,
+	    className: "objectBox objectBox-object"
+	  };
+
 	  if (props.mode === MODE.TINY) {
 	    var _require3 = __webpack_require__(926),
 	        Rep = _require3.Rep;
 
-	    return span({ className: "objectBox objectBox-object" }, getTitle(props, object), safeObjectLink(props, {
+	    return span(config, getTitle(object), span({
 	      className: "objectLeftBrace"
-	    }, " { "), Rep({ object: promiseState.state }), safeObjectLink(props, {
+	    }, " { "), Rep({ object: promiseState.state }), span({
 	      className: "objectRightBrace"
 	    }, " }"));
 	  }
 
 	  var propsArray = getProps(props, promiseState);
-	  return span.apply(undefined, [{ className: "objectBox objectBox-object" }, getTitle(props, object), safeObjectLink(props, {
+	  return span.apply(undefined, [config, getTitle(object), span({
 	    className: "objectLeftBrace"
-	  }, " { ")].concat(_toConsumableArray(propsArray), [safeObjectLink(props, {
+	  }, " { ")].concat(_toConsumableArray(propsArray), [span({
 	    className: "objectRightBrace"
 	  }, " }")]));
 	}
 
-	function getTitle(props, object) {
-	  var title = object.class;
-	  return safeObjectLink(props, {}, title);
+	function getTitle(object) {
+	  return span({
+	    className: "objectTitle"
+	  }, object.class);
 	}
 
 	function getProps(props, promiseState) {
 	  var keys = ["state"];
 	  if (Object.keys(promiseState).includes("value")) {
 	    keys.push("value");
 	  }
 
-	  return keys.map((key, i) => {
+	  return keys.reduce((res, key, i) => {
 	    var object = promiseState[key];
-	    return PropRep(Object.assign({}, props, {
+	    res = res.concat(PropRep(Object.assign({}, props, {
 	      mode: MODE.TINY,
 	      name: `<${key}>`,
 	      object,
 	      equal: ": ",
-	      delim: i < keys.length - 1 ? ", " : null,
 	      suppressQuotes: true
-	    }));
-	  });
+	    })));
+
+	    // Interleave commas between elements
+	    if (i !== keys.length - 1) {
+	      res.push(", ");
+	    }
+
+	    return res;
+	  }, []);
 	}
 
 	// Registration
 	function supportsObject(object, type) {
-	  if (!isGrip(object)) {
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+	  if (noGrip === true || !isGrip(object)) {
 	    return false;
 	  }
 	  return type === "Promise";
 	}
 
 	// Exports from this module
 	module.exports = {
 	  rep: wrapRender(PromiseRep),
@@ -36531,52 +35473,57 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 948 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// ReactJS
 	var React = __webpack_require__(2);
 
 	// Reps
 
 	var _require = __webpack_require__(927),
 	    isGrip = _require.isGrip,
-	    safeObjectLink = _require.safeObjectLink,
 	    wrapRender = _require.wrapRender;
 
 	/**
 	 * Renders a grip object with regular expression.
 	 */
 
 
 	RegExp.propTypes = {
-	  object: React.PropTypes.object.isRequired,
-	  objectLink: React.PropTypes.func
+	  object: React.PropTypes.object.isRequired
 	};
 
 	function RegExp(props) {
 	  var object = props.object;
 
 
-	  return safeObjectLink(props, {
+	  return React.DOM.span({
+	    "data-link-actor-id": object.actor,
 	    className: "objectBox objectBox-regexp regexpSource"
 	  }, getSource(object));
 	}
 
 	function getSource(grip) {
 	  return grip.displayString;
 	}
 
 	// Registration
 	function supportsObject(object, type) {
-	  if (!isGrip(object)) {
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+	  if (noGrip === true || !isGrip(object)) {
 	    return false;
 	  }
 
 	  return type == "RegExp";
 	}
 
 	// Exports from this module
 	module.exports = {
@@ -36585,61 +35532,68 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 949 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// ReactJS
 	var React = __webpack_require__(2);
 
 	// Reps
 
 	var _require = __webpack_require__(927),
 	    isGrip = _require.isGrip,
 	    getURLDisplayString = _require.getURLDisplayString,
-	    safeObjectLink = _require.safeObjectLink,
 	    wrapRender = _require.wrapRender;
 
 	// Shortcuts
 
 
 	var span = React.DOM.span;
 
 	/**
 	 * Renders a grip representing CSSStyleSheet
 	 */
 
 	StyleSheet.propTypes = {
-	  object: React.PropTypes.object.isRequired,
-	  objectLink: React.PropTypes.func
+	  object: React.PropTypes.object.isRequired
 	};
 
 	function StyleSheet(props) {
 	  var grip = props.object;
 
-	  return span({ className: "objectBox objectBox-object" }, getTitle(props, grip), span({ className: "objectPropValue" }, getLocation(grip)));
-	}
-
-	function getTitle(props, grip) {
+	  return span({
+	    "data-link-actor-id": grip.actor,
+	    className: "objectBox objectBox-object"
+	  }, getTitle(grip), span({ className: "objectPropValue" }, getLocation(grip)));
+	}
+
+	function getTitle(grip) {
 	  var title = "StyleSheet ";
-	  return safeObjectLink(props, { className: "objectBox" }, title);
+	  return span({ className: "objectBoxTitle" }, title);
 	}
 
 	function getLocation(grip) {
 	  // Embedded stylesheets don't have URL and so, no preview.
 	  var url = grip.preview ? grip.preview.url : "";
 	  return url ? getURLDisplayString(url) : "";
 	}
 
 	// Registration
 	function supportsObject(object, type) {
-	  if (!isGrip(object)) {
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+	  if (noGrip === true || !isGrip(object)) {
 	    return false;
 	  }
 
 	  return type == "CSSStyleSheet";
 	}
 
 	// Exports from this module
 
@@ -36649,16 +35603,20 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 950 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// Dependencies
 	var React = __webpack_require__(2);
 
 	var _require = __webpack_require__(927),
 	    isGrip = _require.isGrip,
 	    cropString = _require.cropString,
 	    cropMultipleLines = _require.cropMultipleLines,
 	    wrapRender = _require.wrapRender;
@@ -36688,22 +35646,27 @@ return /******/ (function(modules) { // 
 	  var textContent = object.preview.textContent;
 
 	  if (mode === MODE.TINY) {
 	    textContent = cropMultipleLines(textContent, 30);
 	  } else if (mode === MODE.SHORT) {
 	    textContent = cropString(textContent, 50);
 	  }
 
-	  return span({ className: "objectBox theme-comment" }, `<!-- ${textContent} -->`);
+	  return span({
+	    className: "objectBox theme-comment",
+	    "data-link-actor-id": object.actor
+	  }, `<!-- ${textContent} -->`);
 	}
 
 	// Registration
 	function supportsObject(object, type) {
-	  if (!isGrip(object)) {
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+	  if (noGrip === true || !isGrip(object)) {
 	    return false;
 	  }
 	  return object.preview && object.preview.nodeType === nodeConstants.COMMENT_NODE;
 	}
 
 	// Exports from this module
 	module.exports = {
 	  rep: wrapRender(CommentNode),
@@ -36713,61 +35676,66 @@ return /******/ (function(modules) { // 
 /***/ },
 /* 951 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// ReactJS
 	var React = __webpack_require__(2);
 
 	// Utils
 
 	var _require = __webpack_require__(927),
 	    isGrip = _require.isGrip,
-	    safeObjectLink = _require.safeObjectLink,
 	    wrapRender = _require.wrapRender;
 
 	var _require2 = __webpack_require__(925),
 	    MODE = _require2.MODE;
 
 	var nodeConstants = __webpack_require__(928);
-	var Svg = __webpack_require__(952);
+	var Svg = __webpack_require__(1151);
 
 	// Shortcuts
 	var span = React.DOM.span;
 
 	/**
 	 * Renders DOM element node.
 	 */
 
 	ElementNode.propTypes = {
 	  object: React.PropTypes.object.isRequired,
 	  // @TODO Change this to Object.values once it's supported in Node's version of V8
 	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
 	  onDOMNodeMouseOver: React.PropTypes.func,
 	  onDOMNodeMouseOut: React.PropTypes.func,
-	  onInspectIconClick: React.PropTypes.func,
-	  objectLink: React.PropTypes.func
+	  onInspectIconClick: React.PropTypes.func
 	};
 
 	function ElementNode(props) {
 	  var object = props.object,
 	      mode = props.mode,
 	      onDOMNodeMouseOver = props.onDOMNodeMouseOver,
 	      onDOMNodeMouseOut = props.onDOMNodeMouseOut,
 	      onInspectIconClick = props.onInspectIconClick;
 
 	  var elements = getElements(object, mode);
 
 	  var isInTree = object.preview && object.preview.isConnected === true;
 
-	  var baseConfig = { className: "objectBox objectBox-node" };
+	  var baseConfig = {
+	    "data-link-actor-id": object.actor,
+	    className: "objectBox objectBox-node"
+	  };
 	  var inspectIcon = void 0;
 	  if (isInTree) {
 	    if (onDOMNodeMouseOver) {
 	      Object.assign(baseConfig, {
 	        onMouseOver: _ => onDOMNodeMouseOver(object)
 	      });
 	    }
 
@@ -36783,17 +35751,17 @@ return /******/ (function(modules) { // 
 	        draggable: false,
 	        // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands
 	        title: "Click to select the node in the inspector",
 	        onClick: e => onInspectIconClick(object, e)
 	      });
 	    }
 	  }
 
-	  return span(baseConfig, safeObjectLink.apply(undefined, [props, {}].concat(_toConsumableArray(elements))), inspectIcon);
+	  return span.apply(undefined, [baseConfig].concat(_toConsumableArray(elements), [inspectIcon]));
 	}
 
 	function getElements(grip, mode) {
 	  var _grip$preview = grip.preview,
 	      attributes = _grip$preview.attributes,
 	      nodeName = _grip$preview.nodeName;
 
 	  var nodeNameElement = span({
@@ -36805,128 +35773,105 @@ return /******/ (function(modules) { // 
 	    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;
 	  }
-	  var 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) => {
+	  var attributeKeys = Object.keys(attributes);
+	  if (attributeKeys.includes("class")) {
+	    attributeKeys.splice(attributeKeys.indexOf("class"), 1);
+	    attributeKeys.unshift("class");
+	  }
+	  if (attributeKeys.includes("id")) {
+	    attributeKeys.splice(attributeKeys.indexOf("id"), 1);
+	    attributeKeys.unshift("id");
+	  }
+	  var attributeElements = attributeKeys.reduce((arr, name, i, keys) => {
 	    var value = attributes[name];
 	    var attribute = span({}, span({ className: "attr-name theme-fg-color2" }, `${name}`), `="`, span({ className: "attr-value theme-fg-color6" }, `${value}`), `"`);
 
 	    return arr.concat([" ", attribute]);
 	  }, []);
 
 	  return ["<", nodeNameElement].concat(_toConsumableArray(attributeElements), [">"]);
 	}
 
 	// Registration
 	function supportsObject(object, type) {
-	  if (!isGrip(object)) {
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+	  if (noGrip === true || !isGrip(object)) {
 	    return false;
 	  }
 	  return object.preview && object.preview.nodeType === nodeConstants.ELEMENT_NODE;
 	}
 
 	// Exports from this module
 	module.exports = {
 	  rep: wrapRender(ElementNode),
 	  supportsObject
 	};
 
 /***/ },
-/* 952 */
-/***/ function(module, exports, __webpack_require__) {
-
-	"use strict";
-
-	var React = __webpack_require__(2);
-	var InlineSVG = __webpack_require__(346);
-
-	var svg = {
-	  "open-inspector": __webpack_require__(688)
-	};
-
-	module.exports = function (name, props) {
-	  // eslint-disable-line
-	  if (!svg[name]) {
-	    throw new Error("Unknown SVG: " + name);
-	  }
-	  var className = name;
-	  if (props && props.className) {
-	    className = `${name} ${props.className}`;
-	  }
-	  if (name === "subSettings") {
-	    className = "";
-	  }
-	  props = Object.assign({}, props, { className, src: svg[name] });
-	  return React.createElement(InlineSVG, props);
-	};
-
-/***/ },
+/* 952 */,
 /* 953 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// ReactJS
 	var React = __webpack_require__(2);
 
 	// Reps
 
 	var _require = __webpack_require__(927),
 	    isGrip = _require.isGrip,
 	    cropString = _require.cropString,
-	    safeObjectLink = _require.safeObjectLink,
 	    wrapRender = _require.wrapRender;
 
 	var _require2 = __webpack_require__(925),
 	    MODE = _require2.MODE;
 
-	var Svg = __webpack_require__(952);
+	var Svg = __webpack_require__(1151);
 
 	// Shortcuts
 	var DOM = React.DOM;
 
 	/**
 	 * Renders DOM #text node.
 	 */
 	TextNode.propTypes = {
 	  object: React.PropTypes.object.isRequired,
 	  // @TODO Change this to Object.values once it's supported in Node's version of V8
 	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
-	  objectLink: React.PropTypes.func,
 	  onDOMNodeMouseOver: React.PropTypes.func,
 	  onDOMNodeMouseOut: React.PropTypes.func,
 	  onInspectIconClick: React.PropTypes.func
 	};
 
 	function TextNode(props) {
 	  var grip = props.object,
 	      _props$mode = props.mode,
 	      mode = _props$mode === undefined ? MODE.SHORT : _props$mode,
 	      onDOMNodeMouseOver = props.onDOMNodeMouseOver,
 	      onDOMNodeMouseOut = props.onDOMNodeMouseOut,
 	      onInspectIconClick = props.onInspectIconClick;
 
 
-	  var baseConfig = { className: "objectBox objectBox-textNode" };
+	  var baseConfig = {
+	    "data-link-actor-id": grip.actor,
+	    className: "objectBox objectBox-textNode"
+	  };
 	  var inspectIcon = void 0;
 	  var isInTree = grip.preview && grip.preview.isConnected === true;
 
 	  if (isInTree) {
 	    if (onDOMNodeMouseOver) {
 	      Object.assign(baseConfig, {
 	        onMouseOver: _ => onDOMNodeMouseOver(grip)
 	      });
@@ -36945,34 +35890,36 @@ return /******/ (function(modules) { // 
 	        // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands
 	        title: "Click to select the node in the inspector",
 	        onClick: e => onInspectIconClick(grip, e)
 	      });
 	    }
 	  }
 
 	  if (mode === MODE.TINY) {
-	    return DOM.span(baseConfig, getTitle(props, grip), inspectIcon);
-	  }
-
-	  return DOM.span(baseConfig, getTitle(props, grip), DOM.span({ className: "nodeValue" }, " ", `"${getTextContent(grip)}"`), inspectIcon);
+	    return DOM.span(baseConfig, getTitle(grip), inspectIcon);
+	  }
+
+	  return DOM.span(baseConfig, getTitle(grip), DOM.span({ className: "nodeValue" }, " ", `"${getTextContent(grip)}"`), inspectIcon);
 	}
 
 	function getTextContent(grip) {
 	  return cropString(grip.preview.textContent);
 	}
 
-	function getTitle(props, grip) {
+	function getTitle(grip) {
 	  var title = "#text";
-	  return safeObjectLink(props, {}, title);
+	  return DOM.span({}, title);
 	}
 
 	// Registration
 	function supportsObject(grip, type) {
-	  if (!isGrip(grip)) {
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+	  if (noGrip === true || !isGrip(grip)) {
 	    return false;
 	  }
 
 	  return grip.preview && grip.class == "Text";
 	}
 
 	// Exports from this module
 	module.exports = {
@@ -36981,38 +35928,44 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 954 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// ReactJS
 	var React = __webpack_require__(2);
 	// Utils
 
 	var _require = __webpack_require__(927),
 	    isGrip = _require.isGrip,
-	    safeObjectLink = _require.safeObjectLink,
 	    wrapRender = _require.wrapRender;
 
 	var _require2 = __webpack_require__(925),
 	    MODE = _require2.MODE;
 
+	// Shortcuts
+
+
+	var span = React.DOM.span;
+
 	/**
 	 * Renders Error objects.
 	 */
 
-
 	ErrorRep.propTypes = {
 	  object: React.PropTypes.object.isRequired,
 	  // @TODO Change this to Object.values once it's supported in Node's version of V8
-	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
-	  objectLink: React.PropTypes.func
+	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key]))
 	};
 
 	function ErrorRep(props) {
 	  var object = props.object;
 	  var preview = object.preview;
 	  var name = preview && preview.name ? preview.name : "Error";
 
 	  var content = props.mode === MODE.TINY ? name : `${name}: ${preview.message}`;
@@ -37021,22 +35974,27 @@ return /******/ (function(modules) { // 
 	    /*
 	      * Since Reps are used in the JSON Viewer, we can't localize
 	      * the "Stack trace" label (defined in debugger.properties as
 	      * "variablesViewErrorStacktrace" property), until Bug 1317038 lands.
 	      */
 	    content = `${content}\nStack trace:\n${preview.stack}`;
 	  }
 
-	  return safeObjectLink(props, { className: "objectBox-stackTrace" }, content);
+	  return span({
+	    "data-link-actor-id": object.actor,
+	    className: "objectBox-stackTrace"
+	  }, content);
 	}
 
 	// Registration
 	function supportsObject(object, type) {
-	  if (!isGrip(object)) {
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+	  if (noGrip === true || !isGrip(object)) {
 	    return false;
 	  }
 	  return object.preview && type === "Error";
 	}
 
 	// Exports from this module
 	module.exports = {
 	  rep: wrapRender(ErrorRep),
@@ -37044,25 +36002,28 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 955 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// ReactJS
 	var React = __webpack_require__(2);
 
 	// Reps
 
 	var _require = __webpack_require__(927),
 	    isGrip = _require.isGrip,
 	    getURLDisplayString = _require.getURLDisplayString,
-	    safeObjectLink = _require.safeObjectLink,
 	    wrapRender = _require.wrapRender;
 
 	var _require2 = __webpack_require__(925),
 	    MODE = _require2.MODE;
 
 	// Shortcuts
 
 
@@ -37070,44 +36031,50 @@ return /******/ (function(modules) { // 
 
 	/**
 	 * Renders a grip representing a window.
 	 */
 
 	WindowRep.propTypes = {
 	  // @TODO Change this to Object.values once it's supported in Node's version of V8
 	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
-	  object: React.PropTypes.object.isRequired,
-	  objectLink: React.PropTypes.func
+	  object: React.PropTypes.object.isRequired
 	};
 
 	function WindowRep(props) {
 	  var mode = props.mode,
 	      object = props.object;
 
 
+	  var config = {
+	    "data-link-actor-id": object.actor,
+	    className: "objectBox objectBox-Window"
+	  };
+
 	  if (mode === MODE.TINY) {
-	    return span({ className: "objectBox objectBox-Window" }, getTitle(props, object));
-	  }
-
-	  return span({ className: "objectBox objectBox-Window" }, getTitle(props, object), " ", span({ className: "objectPropValue" }, getLocation(object)));
-	}
-
-	function getTitle(props, object) {
+	    return span(config, getTitle(object));
+	  }
+
+	  return span(config, getTitle(object), " ", span({ className: "objectPropValue" }, getLocation(object)));
+	}
+
+	function getTitle(object) {
 	  var title = object.displayClass || object.class || "Window";
-	  return safeObjectLink(props, { className: "objectBox" }, title);
+	  return span({ className: "objectBoxTitle" }, title);
 	}
 
 	function getLocation(object) {
 	  return getURLDisplayString(object.preview.url);
 	}
 
 	// Registration
 	function supportsObject(object, type) {
-	  if (!isGrip(object)) {
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+	  if (noGrip === true || !isGrip(object)) {
 	    return false;
 	  }
 
 	  return object.preview && type == "Window";
 	}
 
 	// Exports from this module
 	module.exports = {
@@ -37116,16 +36083,20 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 956 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// ReactJS
 	var React = __webpack_require__(2);
 
 	// Reps
 
 	var _require = __webpack_require__(927),
 	    isGrip = _require.isGrip,
 	    wrapRender = _require.wrapRender;
@@ -37135,45 +36106,40 @@ return /******/ (function(modules) { // 
 
 	var span = React.DOM.span;
 
 	/**
 	 * Renders a grip object with textual data.
 	 */
 
 	ObjectWithText.propTypes = {
-	  object: React.PropTypes.object.isRequired,
-	  objectLink: React.PropTypes.func
+	  object: React.PropTypes.object.isRequired
 	};
 
 	function ObjectWithText(props) {
 	  var grip = props.object;
-	  return span({ className: "objectBox objectBox-" + getType(grip) }, getTitle(props, grip), span({ className: "objectPropValue" }, getDescription(grip)));
-	}
-
-	function getTitle(props, grip) {
-	  if (props.objectLink) {
-	    return span({ className: "objectBox" }, props.objectLink({
-	      object: grip
-	    }, getType(grip) + " "));
-	  }
-	  return "";
+	  return span({
+	    "data-link-actor-id": grip.actor,
+	    className: "objectBox objectBox-" + getType(grip)
+	  }, span({ className: "objectPropValue" }, getDescription(grip)));
 	}
 
 	function getType(grip) {
 	  return grip.class;
 	}
 
 	function getDescription(grip) {
 	  return "\"" + grip.preview.text + "\"";
 	}
 
 	// Registration
 	function supportsObject(grip, type) {
-	  if (!isGrip(grip)) {
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+	  if (noGrip === true || !isGrip(grip)) {
 	    return false;
 	  }
 
 	  return grip.preview && grip.preview.kind == "ObjectWithText";
 	}
 
 	// Exports from this module
 	module.exports = {
@@ -37182,61 +36148,68 @@ return /******/ (function(modules) { // 
 	};
 
 /***/ },
 /* 957 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// ReactJS
 	var React = __webpack_require__(2);
 
 	// Reps
 
 	var _require = __webpack_require__(927),
 	    isGrip = _require.isGrip,
 	    getURLDisplayString = _require.getURLDisplayString,
-	    safeObjectLink = _require.safeObjectLink,
 	    wrapRender = _require.wrapRender;
 
 	// Shortcuts
 
 
 	var span = React.DOM.span;
 
 	/**
 	 * Renders a grip object with URL data.
 	 */
 
 	ObjectWithURL.propTypes = {
-	  object: React.PropTypes.object.isRequired,
-	  objectLink: React.PropTypes.func
+	  object: React.PropTypes.object.isRequired
 	};
 
 	function ObjectWithURL(props) {
 	  var grip = props.object;
-	  return span({ className: "objectBox objectBox-" + getType(grip) }, getTitle(props, grip), span({ className: "objectPropValue" }, getDescription(grip)));
-	}
-
-	function getTitle(props, grip) {
-	  return safeObjectLink(props, { className: "objectBox" }, getType(grip) + " ");
+	  return span({
+	    "data-link-actor-id": grip.actor,
+	    className: "objectBox objectBox-" + getType(grip)
+	  }, getTitle(grip), span({ className: "objectPropValue" }, getDescription(grip)));
+	}
+
+	function getTitle(grip) {
+	  return span({ className: "objectTitle" }, getType(grip) + " ");
 	}
 
 	function getType(grip) {
 	  return grip.class;
 	}
 
 	function getDescription(grip) {
 	  return getURLDisplayString(grip.preview.url);
 	}
 
 	// Registration
 	function supportsObject(grip, type) {
-	  if (!isGrip(grip)) {
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+	  if (noGrip === true || !isGrip(grip)) {
 	    return false;
 	  }
 
 	  return grip.preview && grip.preview.kind == "ObjectWithURL";
 	}
 
 	// Exports from this module
 	module.exports = {
@@ -37247,22 +36220,25 @@ return /******/ (function(modules) { // 
 /***/ },
 /* 958 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
 
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// Dependencies
 	var React = __webpack_require__(2);
 
 	var _require = __webpack_require__(927),
 	    isGrip = _require.isGrip,
-	    safeObjectLink = _require.safeObjectLink,
 	    wrapRender = _require.wrapRender;
 
 	var Caption = __webpack_require__(935);
 
 	var _require2 = __webpack_require__(925),
 	    MODE = _require2.MODE;
 
 	// Shortcuts
@@ -37275,17 +36251,16 @@ return /******/ (function(modules) { // 
 	 * and the max number of rendered items depends on the current mode.
 	 */
 
 	GripArray.propTypes = {
 	  object: React.PropTypes.object.isRequired,
 	  // @TODO Change this to Object.values once it's supported in Node's version of V8
 	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
 	  provider: React.PropTypes.object,
-	  objectLink: React.PropTypes.func,
 	  onDOMNodeMouseOver: React.PropTypes.func,
 	  onDOMNodeMouseOut: React.PropTypes.func,
 	  onInspectIconClick: React.PropTypes.func
 	};
 
 	function GripArray(props) {
 	  var object = props.object,
 	      _props$mode = props.mode,
@@ -37296,168 +36271,191 @@ return /******/ (function(modules) { // 
 	  var brackets = void 0;
 	  var needSpace = function (space) {
 	    return space ? { left: "[ ", right: " ]" } : { left: "[", right: "]" };
 	  };
 
 	  if (mode === MODE.TINY) {
 	    var objectLength = getLength(object);
 	    var isEmpty = objectLength === 0;
-	    items = [span({ className: "length" }, isEmpty ? "" : objectLength)];
+	    items = [span({
+	      className: "length"
+	    }, isEmpty ? "" : objectLength)];
 	    brackets = needSpace(false);
 	  } else {
-	    var max = mode === MODE.SHORT ? 3 : 10;
+	    var max = maxLengthMap.get(mode);
 	    items = arrayIterator(props, object, max);
 	    brackets = needSpace(items.length > 0);
 	  }
 
 	  var title = getTitle(props, object);
 
 	  return span.apply(undefined, [{
-	    className: "objectBox objectBox-array" }, title, safeObjectLink(props, {
+	    "data-link-actor-id": object.actor,
+	    className: "objectBox objectBox-array" }, title, span({
 	    className: "arrayLeftBracket"
-	  }, brackets.left)].concat(_toConsumableArray(items), [safeObjectLink(props, {
+	  }, brackets.left)].concat(_toConsumableArray(interleaveCommas(items)), [span({
 	    className: "arrayRightBracket"
 	  }, brackets.right), span({
 	    className: "arrayProperties",
 	    role: "group" })]));
 	}
 
-	/**
-	 * Renders array item. Individual values are separated by
-	 * a delimiter (a comma by default).
-	 */
-	GripArrayItem.propTypes = {
-	  delim: React.PropTypes.string,
-	  object: React.PropTypes.oneOfType([React.PropTypes.object, React.PropTypes.number, React.PropTypes.string]).isRequired,
-	  objectLink: React.PropTypes.func,
-	  // @TODO Change this to Object.values once it's supported in Node's version of V8
-	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
-	  provider: React.PropTypes.object,
-	  onDOMNodeMouseOver: React.PropTypes.func,
-	  onDOMNodeMouseOut: React.PropTypes.func,
-	  onInspectIconClick: React.PropTypes.func
-	};
-
-	function GripArrayItem(props) {
-	  var _require3 = __webpack_require__(926),
-	      Rep = _require3.Rep;
-
-	  var delim = props.delim;
-
-
-	  return span({}, Rep(Object.assign({}, props, {
-	    mode: MODE.TINY
-	  })), delim);
+	function interleaveCommas(items) {
+	  return items.reduce((res, item, index) => {
+	    if (index !== items.length - 1) {
+	      return res.concat(item, ", ");
+	    }
+	    return res.concat(item);
+	  }, []);
 	}
 
 	function getLength(grip) {
 	  if (!grip.preview) {
 	    return 0;
 	  }
 
 	  return grip.preview.length || grip.preview.childNodesLength || 0;
 	}
 
-	function getTitle(props, object, context) {
+	function getTitle(props, object) {
 	  if (props.mode === MODE.TINY) {
 	    return "";
 	  }
 
 	  var title = props.title || object.class || "Array";
-	  return safeObjectLink(props, {}, title + " ");
+	  return span({
+	    className: "objectTitle"
+	  }, title + " ");
 	}
 
 	function getPreviewItems(grip) {
 	  if (!grip.preview) {
 	    return null;
 	  }
 
 	  return grip.preview.items || grip.preview.childNodes || null;
 	}
 
 	function arrayIterator(props, grip, max) {
+	  var _require3 = __webpack_require__(926),
+	      Rep = _require3.Rep;
+
 	  var items = [];
 	  var gripLength = getLength(grip);
 
 	  if (!gripLength) {
 	    return items;
 	  }
 
 	  var previewItems = getPreviewItems(grip);
 	  if (!previewItems) {
 	    return items;
 	  }
 
-	  var delim = void 0;
-	  // number of grip preview items is limited to 10, but we may have more
-	  // items in grip-array.
-	  var delimMax = gripLength > previewItems.length ? previewItems.length : previewItems.length - 1;
 	  var provider = props.provider;
 
-	  for (var i = 0; i < previewItems.length && i < max; i++) {
+	  var emptySlots = 0;
+	  var foldedEmptySlots = 0;
+	  items = previewItems.reduce((res, itemGrip) => {
+	    if (res.length >= max) {
+	      return res;
+	    }
+
+	    var object = void 0;
 	    try {
-	      var itemGrip = previewItems[i];
-	      var value = provider ? provider.getValue(itemGrip) : itemGrip;
-
-	      delim = i == delimMax ? "" : ", ";
-
-	      items.push(GripArrayItem(Object.assign({}, props, {
-	        object: value,
-	        delim: delim,
+	      if (!provider && itemGrip === null) {
+	        emptySlots++;
+	        return res;
+	      }
+
+	      object = provider ? provider.getValue(itemGrip) : itemGrip;
+	    } catch (exc) {
+	      object = exc;
+	    }
+
+	    if (emptySlots > 0) {
+	      res.push(getEmptySlotsElement(emptySlots));
+	      foldedEmptySlots = foldedEmptySlots + emptySlots - 1;
+	      emptySlots = 0;
+	    }
+
+	    if (res.length < max) {
+	      res.push(Rep(Object.assign({}, props, {
+	        object,
+	        mode: MODE.TINY,
 	        // Do not propagate title to array items reps
 	        title: undefined
 	      })));
-	    } catch (exc) {
-	      items.push(GripArrayItem(Object.assign({}, props, {
-	        object: exc,
-	        delim: delim,
-	        // Do not propagate title to array items reps
-	        title: undefined
-	      })));
-	    }
-	  }
-	  if (previewItems.length > max || gripLength > previewItems.length) {
-	    var leftItemNum = gripLength - max > 0 ? gripLength - max : gripLength - previewItems.length;
+	    }
+
+	    return res;
+	  }, []);
+
+	  // Handle trailing empty slots if there are some.
+	  if (items.length < max && emptySlots > 0) {
+	    items.push(getEmptySlotsElement(emptySlots));
+	    foldedEmptySlots = foldedEmptySlots + emptySlots - 1;
+	  }
+
+	  var itemsShown = items.length + foldedEmptySlots;
+	  if (gripLength > itemsShown) {
 	    items.push(Caption({
-	      object: safeObjectLink(props, {}, leftItemNum + " more…")
+	      object: span({}, "more…")
 	    }));
 	  }
 
 	  return items;
 	}
 
+	function getEmptySlotsElement(number) {
+	  // TODO: Use l10N - See https://github.com/devtools-html/reps/issues/141
+	  return `<${number} empty slot${number > 1 ? "s" : ""}>`;
+	}
+
 	function supportsObject(grip, type) {
-	  if (!isGrip(grip)) {
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+	  if (noGrip === true || !isGrip(grip)) {
 	    return false;
 	  }
 
 	  return grip.preview && (grip.preview.kind == "ArrayLike" || type === "DocumentFragment");
 	}
 
+	var maxLengthMap = new Map();
+	maxLengthMap.set(MODE.SHORT, 3);
+	maxLengthMap.set(MODE.LONG, 10);
+
 	// Exports from this module
 	module.exports = {
 	  rep: wrapRender(GripArray),
-	  supportsObject
+	  supportsObject,
+	  maxLengthMap
 	};
 
 /***/ },
 /* 959 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
 
+	function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+
+	/* This Source Code Form is subject to the terms of the Mozilla Public
+	 * License, v. 2.0. If a copy of the MPL was not distributed with this
+	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 	// Dependencies
 	var React = __webpack_require__(2);
 
 	var _require = __webpack_require__(927),
 	    isGrip = _require.isGrip,
-	    safeObjectLink = _require.safeObjectLink,
 	    wrapRender = _require.wrapRender;
 
 	var Caption = __webpack_require__(935);
 	var PropRep = __webpack_require__(937);
 
 	var _require2 = __webpack_require__(925),
 	    MODE = _require2.MODE;
 	// Shortcuts
@@ -37469,42 +36467,51 @@ return /******/ (function(modules) { // 
 	 * Renders an map. A map is represented by a list of its
 	 * entries enclosed in curly brackets.
 	 */
 
 	GripMap.propTypes = {
 	  object: React.PropTypes.object,
 	  // @TODO Change this to Object.values once it's supported in Node's version of V8
 	  mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])),
-	  objectLink: React.PropTypes.func,
 	  isInterestingEntry: React.PropTypes.func,
 	  onDOMNodeMouseOver: React.PropTypes.func,
 	  onDOMNodeMouseOut: React.PropTypes.func,
 	  onInspectIconClick: React.PropTypes.func,
 	  title: React.PropTypes.string
 	};
 
 	function GripMap(props) {
-	  var object = props.object;
-	  var propsArray = safeEntriesIterator(props, object, props.mode === MODE.LONG ? 10 : 3);
-
-	  if (props.mode === MODE.TINY) {
-	    return span({ className: "objectBox objectBox-object" }, getTitle(props, object));
-	  }
-
-	  return span({ className: "objectBox objectBox-object" }, getTitle(props, object), safeObjectLink(props, {
+	  var mode = props.mode,
+	      object = props.object;
+
+
+	  var config = {
+	    "data-link-actor-id": object.actor,
+	    className: "objectBox objectBox-object"
+	  };
+
+	  if (mode === MODE.TINY) {
+	    return span(config, getTitle(props, object));
+	  }
+
+	  var propsArray = safeEntriesIterator(props, object, maxLengthMap.get(mode));
+
+	  return span.apply(undefined, [config, getTitle(props, object), span({
 	    className: "objectLeftBrace"
-	  }, " { "), propsArray, safeObjectLink(props, {
+	  }, " { ")].concat(_toConsumableArray(propsArray), [span({
 	    className: "objectRightBrace"
-	  }, " }"));
+	  }, " }")]));
 	}
 
 	function getTitle(props, object) {
 	  var title = props.title || (object && object.class ? object.class : "Map");
-	  return safeObjectLink(props, {}, title);
+	  return span({
+	    className: "objectTitle"
+	  }, title);
 	}
 
 	function safeEntriesIterator(props, object, max) {
 	  max = typeof max === "undefined" ? 3 : max;
 	  try {
 	    return entriesIterator(props, object, max);
 	  } catch (err) {
 	    console.error(err);
@@ -37528,34 +36535,49 @@ return /******/ (function(modules) { // 
 	    }));
 	  }
 
 	  var entries = getEntries(props, mapEntries, indexes);
 	  if (entries.length < mapEntries.length) {
 	    // There are some undisplayed entries. Then display "more…".
 	    entries.push(Caption({
 	      key: "more",
-	      object: safeObjectLink(props, {}, `${mapEntries.length - max} more…`)
+	      object: span({}, "more…")
 	    }));
 	  }
 
-	  return entries;
+	  return unfoldEntries(entries);
+	}
+
+	function unfoldEntries(items) {
+	  return items.reduce((res, item, index) => {
+	    if (Array.isArray(item)) {
+	      res = res.concat(item);
+	    } else {
+	      res.push(item);
+	    }
+
+	    // Interleave commas between elements
+	    if (index !== items.length - 1) {
+	      res.push(", ");
+	    }
+	    return res;
+	  }, []);
 	}
 
 	/**
 	 * Get entries ordered by index.
 	 *
 	 * @param {Object} props Component props.
 	 * @param {Array} entries Entries array.
 	 * @param {Array} indexes Indexes of entries.
 	 * @return {Array} Array of PropRep.
 	 */
 	function getEntries(props, entries, indexes) {
-	  var objectLink = props.objectLink,
-	      onDOMNodeMouseOver = props.onDOMNodeMouseOver,
+	  var onDOMNodeMouseOver = props.onDOMNodeMouseOver,
 	      onDOMNodeMouseOut = props.onDOMNodeMouseOut,
 	      onInspectIconClick = props.onInspectIconClick;
 
 	  // Make indexes ordered by ascending.
 
 	  indexes.sort(function (a, b) {
 	    return a - b;
 	  });
@@ -37563,25 +36585,20 @@ return /******/ (function(modules) { // 
 	  return indexes.map((index, i) => {
 	    var _entries$index = _slicedToArray(entries[index], 2),
 	        key = _entries$index[0],
 	        entryValue = _entries$index[1];
 
 	    var 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 ? ", " : null,
 	      mode: MODE.TINY,
-	      objectLink,
 	      onDOMNodeMouseOver,
 	      onDOMNodeMouseOut,
 	      onInspectIconClick
 	    });
 	  });
 	}
 
 	/**
@@ -37609,33 +36626,40 @@ return /******/ (function(modules) { // 
 	      }
 	    }
 
 	    return indexes;
 	  }, []);
 	}
 
 	function supportsObject(grip, type) {
-	  if (!isGrip(grip)) {
+	  var noGrip = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+
+	  if (noGrip === true || !isGrip(grip)) {
 	    return false;
 	  }
 	  return grip.preview && grip.preview.kind == "MapLike";
 	}
 
+	var maxLengthMap = new Map();
+	maxLengthMap.set(MODE.SHORT, 3);
+	maxLengthMap.set(MODE.LONG, 10);
+
 	// Exports from this module
 	module.exports = {
 	  rep: wrapRender(GripMap),
-	  supportsObject
+	  supportsObject,
+	  maxLengthMap
 	};
 
 /***/ },
 /* 960 */
 /***/ function(module, exports) {
 
-	module.exports = "# This Source Code Form is subject to the terms of the Mozilla Public\n# License, v. 2.0. If a copy of the MPL was not distributed with this\n# file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n# LOCALIZATION NOTE These strings are used inside the Debugger\n# which is available from the Web Developer sub-menu -> 'Debugger'.\n# The correct localization of this file might be to keep it in\n# English, or another language commonly spoken among web developers.\n# You want to make that choice consistent across the developer tools.\n# A good criteria is the language in which you'd find the best\n# documentation on web development on the web.\n\n# LOCALIZATION NOTE (collapsePanes): This is the tooltip for the button\n# that collapses the left and right panes in the debugger UI.\ncollapsePanes=Collapse panes\n\n# LOCALIZATION NOTE (copySourceUrl): This is the text that appears in the\n# context menu to copy the source URL of file open.\ncopySourceUrl=Copy Source Url\n\n# LOCALIZATION NOTE (copySourceUrl.accesskey): Access key to copy the source URL of a file from\n# the context menu.\ncopySourceUrl.accesskey=u\n\n# LOCALIZATION NOTE (copyStackTrace): This is the text that appears in the\n# context menu to copy the stack trace methods, file names and row number.\ncopyStackTrace=Copy Stack Trace\n\n# LOCALIZATION NOTE (copyStackTrace.accesskey): Access key to copy the stack trace data from\n# the context menu.\ncopyStackTrace.accesskey=c\n\n# LOCALIZATION NOTE (expandPanes): This is the tooltip for the button\n# that expands the left and right panes in the debugger UI.\nexpandPanes=Expand panes\n\n# LOCALIZATION NOTE (pauseButtonTooltip): The tooltip that is displayed for the pause\n# button when the debugger is in a running state.\npauseButtonTooltip=Pause %S\n\n# LOCALIZATION NOTE (pausePendingButtonTooltip): The tooltip that is displayed for\n# the pause button after it's been clicked but before the next JavaScript to run.\npausePendingButtonTooltip=Waiting for next execution\n\n# LOCALIZATION NOTE (resumeButtonTooltip): The label that is displayed on the pause\n# button when the debugger is in a paused state.\nresumeButtonTooltip=Resume %S\n\n# LOCALIZATION NOTE (stepOverTooltip): The label that is displayed on the\n# button that steps over a function call.\nstepOverTooltip=Step Over %S\n\n# LOCALIZATION NOTE (stepInTooltip): The label that is displayed on the\n# button that steps into a function call.\nstepInTooltip=Step In %S\n\n# LOCALIZATION NOTE (stepOutTooltip): The label that is displayed on the\n# button that steps out of a function call.\nstepOutTooltip=Step Out %S\n\n# LOCALIZATION NOTE (noWorkersText): The text to display in the workers list\n# when there are no workers.\nnoWorkersText=This page has no workers.\n\n# LOCALIZATION NOTE (noSourcesText): The text to display in the sources list\n# when there are no sources.\nnoSourcesText=This page has no sources.\n\n# LOCALIZATION NOTE (noEventListenersText): The text to display in the events tab\n# when there are no events.\nnoEventListenersText=No event listeners to display\n\n# LOCALIZATION NOTE (eventListenersHeader): The text to display in the events\n# header.\neventListenersHeader=Event Listeners\n\n# LOCALIZATION NOTE (noStackFramesText): The text to display in the call stack tab\n# when there are no stack frames.\nnoStackFramesText=No stack frames to display\n\n# LOCALIZATION NOTE (eventCheckboxTooltip): The tooltip text to display when\n# the user hovers over the checkbox used to toggle an event breakpoint.\neventCheckboxTooltip=Toggle breaking on this event\n\n# LOCALIZATION NOTE (eventOnSelector): The text to display in the events tab\n# for every event item, between the event type and event selector.\neventOnSelector=on\n\n# LOCALIZATION NOTE (eventInSource): The text to display in the events tab\n# for every event item, between the event selector and listener's owner source.\neventInSource=in\n\n# LOCALIZATION NOTE (eventNodes): The text to display in the events tab when\n# an event is listened on more than one target node.\neventNodes=%S nodes\n\n# LOCALIZATION NOTE (eventNative): The text to display in the events tab when\n# a listener is added from plugins, thus getting translated to native code.\neventNative=[native code]\n\n# LOCALIZATION NOTE (*Events): The text to display in the events tab for\n# each group of sub-level event entries.\nanimationEvents=Animation\naudioEvents=Audio\nbatteryEvents=Battery\nclipboardEvents=Clipboard\ncompositionEvents=Composition\ndeviceEvents=Device\ndisplayEvents=Display\ndragAndDropEvents=Drag and Drop\ngamepadEvents=Gamepad\nindexedDBEvents=IndexedDB\ninteractionEvents=Interaction\nkeyboardEvents=Keyboard\nmediaEvents=HTML5 Media\nmouseEvents=Mouse\nmutationEvents=Mutation\nnavigationEvents=Navigation\npointerLockEvents=Pointer Lock\nsensorEvents=Sensor\nstorageEvents=Storage\ntimeEvents=Time\ntouchEvents=Touch\notherEvents=Other\n\n# LOCALIZATION NOTE (blackboxCheckboxTooltip2): The tooltip text to display when\n# the user hovers over the checkbox used to toggle blackboxing its associated\n# source.\nblackboxCheckboxTooltip2=Toggle blackboxing\n\n# LOCALIZATION NOTE (sources.search.key2): Key shortcut to open the search for\n# searching all the source files the debugger has seen.\nsources.search.key2=CmdOrCtrl+P\n\n# LOCALIZATION NOTE (sources.search.alt.key): A second key shortcut to open the\n# search for searching all the source files the debugger has seen.\nsources.search.alt.key=CmdOrCtrl+O\n\n# LOCALIZATION NOTE (sources.noSourcesAvailable): Text shown when the debugger\n# does not have any sources.\nsources.noSourcesAvailable=This page has no sources\n\n# LOCALIZATION NOTE (sourcesPane.showSourcesTooltip): The tooltip shown when\n# the user will navigate to the source tree view.\nsourcesPane.showSourcesTooltip=Show sources\n\n# LOCALIZATION NOTE (sourcesPane.showOutlineTooltip): The tooltip shown when\n# the user will navigate to the source outline view.\nsourcesPane.showOutlineTooltip=Show outline\n\n# LOCALIZATION NOTE (sourceSearch.search.key2): Key shortcut to open the search\n# for searching within a the currently opened files in the editor\nsourceSearch.search.key2=CmdOrCtrl+F\n\n# LOCALIZATION NOTE (sourceSearch.search.placeholder): placeholder text in\n# the source search input bar\nsourceSearch.search.placeholder=Search in file…\n\n# LOCALIZATION NOTE (sourceSearch.search.again.key2): Key shortcut to highlight\n# the next occurrence of the last search triggered from a source search\nsourceSearch.search.again.key2=CmdOrCtrl+G\n\n# LOCALIZATION NOTE (sourceSearch.search.againPrev.key2): Key shortcut to highlight\n# the previous occurrence of the last search triggered from a source search\nsourceSearch.search.againPrev.key2=CmdOrCtrl+Shift+G\n\n# LOCALIZATION NOTE (sourceSearch.resultsSummary1): Shows a summary of\n# the number of matches for autocomplete\nsourceSearch.resultsSummary1=%d results\n\n# LOCALIZATION NOTE (noMatchingStringsText): The text to display in the\n# global search results when there are no matching strings after filtering.\nnoMatchingStringsText=No matches found\n\n# LOCALIZATION NOTE (emptySearchText): This is the text that appears in the\n# filter text box when it is empty and the scripts container is selected.\nemptySearchText=Search scripts (%S)\n\n# LOCALIZATION NOTE (emptyVariablesFilterText): This is the text that\n# appears in the filter text box for the variables view container.\nemptyVariablesFilterText=Filter variables\n\n# LOCALIZATION NOTE (emptyPropertiesFilterText): This is the text that\n# appears in the filter text box for the editor's variables view bubble.\nemptyPropertiesFilterText=Filter properties\n\n# LOCALIZATION NOTE (searchPanelFilter): This is the text that appears in the\n# filter panel popup for the filter scripts operation.\nsearchPanelFilter=Filter scripts (%S)\n\n# LOCALIZATION NOTE (searchPanelGlobal): This is the text that appears in the\n# filter panel popup for the global search operation.\nsearchPanelGlobal=Search in all files (%S)\n\n# LOCALIZATION NOTE (searchPanelFunction): This is the text that appears in the\n# filter panel popup for the function search operation.\nsearchPanelFunction=Search for function definition (%S)\n\n# LOCALIZATION NOTE (searchPanelToken): This is the text that appears in the\n# filter panel popup for the token search operation.\nsearchPanelToken=Find in this file (%S)\n\n# LOCALIZATION NOTE (searchPanelGoToLine): This is the text that appears in the\n# filter panel popup for the line search operation.\nsearchPanelGoToLine=Go to line (%S)\n\n# LOCALIZATION NOTE (searchPanelVariable): This is the text that appears in the\n# filter panel popup for the variables search operation.\nsearchPanelVariable=Filter variables (%S)\n\n# LOCALIZATION NOTE (breakpointMenuItem): The text for all the elements that\n# are displayed in the breakpoints menu item popup.\nbreakpointMenuItem.setConditional=Configure conditional breakpoint\nbreakpointMenuItem.enableSelf=Enable breakpoint\nbreakpointMenuItem.disableSelf=Disable breakpoint\nbreakpointMenuItem.deleteSelf=Remove breakpoint\nbreakpointMenuItem.enableOthers=Enable others\nbreakpointMenuItem.disableOthers=Disable others\nbreakpointMenuItem.deleteOthers=Remove others\nbreakpointMenuItem.enableAll=Enable all breakpoints\nbreakpointMenuItem.disableAll=Disable all breakpoints\nbreakpointMenuItem.deleteAll=Remove all breakpoints\n\n# LOCALIZATION NOTE (breakpoints.header): Breakpoints right sidebar pane header.\nbreakpoints.header=Breakpoints\n\n# LOCALIZATION NOTE (breakpoints.none): The text that appears when there are\n# no breakpoints present\nbreakpoints.none=No Breakpoints\n\n# LOCALIZATION NOTE (breakpoints.enable): The text that may appear as a tooltip\n# when hovering over the 'disable breakpoints' switch button in right sidebar\nbreakpoints.enable=Enable Breakpoints\n\n# LOCALIZATION NOTE (breakpoints.disable): The text that may appear as a tooltip\n# when hovering over the 'disable breakpoints' switch button in right sidebar\nbreakpoints.disable=Disable Breakpoints\n\n# LOCALIZATION NOTE (breakpoints.removeBreakpointTooltip): The tooltip that is displayed\n# for remove breakpoint button in right sidebar\nbreakpoints.removeBreakpointTooltip=Remove Breakpoint\n\n# LOCALIZATION NOTE (callStack.header): Call Stack right sidebar pane header.\ncallStack.header=Call Stack\n\n# LOCALIZATION NOTE (callStack.notPaused): Call Stack right sidebar pane\n# message when not paused.\ncallStack.notPaused=Not Paused\n\n# LOCALIZATION NOTE (callStack.collapse): Call Stack right sidebar pane\n# message to hide some of the frames that are shown.\ncallStack.collapse=Collapse Rows\n\n# LOCALIZATION NOTE (callStack.expand): Call Stack right sidebar pane\n# message to show more of the frames.\ncallStack.expand=Expand Rows\n\n# LOCALIZATION NOTE (editor.searchResults): Editor Search bar message\n# for the summarizing the selected search result. e.g. 5 of 10 results.\neditor.searchResults=%d of %d results\n\n# LOCALIZATION NOTE (sourceSearch.singleResult): Copy shown when there is one result.\neditor.singleResult=1 result\n\n# LOCALIZATION NOTE (editor.noResults): Editor Search bar message\n# for when no results found.\neditor.noResults=no results\n\n# LOCALIZATION NOTE (editor.searchResults.nextResult): Editor Search bar\n# tooltip for traversing to the Next Result\neditor.searchResults.nextResult=Next Result\n\n# LOCALIZATION NOTE (editor.searchResults.prevResult): Editor Search bar\n# tooltip for traversing to the Previous Result\neditor.searchResults.prevResult=Previous Result\n\n# LOCALIZATION NOTE (editor.searchTypeToggleTitle): Search bar title for\n# toggling search type buttons(function search, variable search)\neditor.searchTypeToggleTitle=Search for:\n\n# LOCALIZATION NOTE (editor.addBreakpoint): Editor gutter context menu item\n# for adding a breakpoint on a line.\neditor.addBreakpoint=Add Breakpoint\n\n# LOCALIZATION NOTE (editor.disableBreakpoint): Editor gutter context menu item\n# for disabling a breakpoint on a line.\neditor.disableBreakpoint=Disable Breakpoint\n\n# LOCALIZATION NOTE (editor.enableBreakpoint): Editor gutter context menu item\n# for enabling a breakpoint on a line.\neditor.enableBreakpoint=Enable Breakpoint\n\n# LOCALIZATION NOTE (editor.removeBreakpoint): Editor gutter context menu item\n# for removing a breakpoint on a line.\neditor.removeBreakpoint=Remove Breakpoint\n\n# LOCALIZATION NOTE (editor.editBreakpoint): Editor gutter context menu item\n# for setting a breakpoint condition on a line.\neditor.editBreakpoint=Edit Breakpoint\n\n# LOCALIZATION NOTE (editor.addConditionalBreakpoint): Editor gutter context\n# menu item for adding a breakpoint condition on a line.\neditor.addConditionalBreakpoint=Add Conditional Breakpoint\n\n# LOCALIZATION NOTE (editor.conditionalPanel.placeholder): Placeholder text for\n# input element inside ConditionalPanel component\neditor.conditionalPanel.placeholder=This breakpoint will pause when the expression is true\n\n# LOCALIZATION NOTE (editor.conditionalPanel.placeholder): Tooltip text for\n# close button inside ConditionalPanel component\neditor.conditionalPanel.close=Cancel edit breakpoint and close\n\n# LOCALIZATION NOTE (editor.jumpToMappedLocation1): Context menu item\n# for navigating to a source mapped location\neditor.jumpToMappedLocation1=Jump to %S location\n\n# LOCALIZATION NOTE (framework.disableGrouping): This is the text that appears in the\n# context menu to disable framework grouping.\nframework.disableGrouping=Disable Framework Grouping\n\n# LOCALIZATION NOTE (framework.disableGrouping.accesskey): Access key to toggle\n# framework grouping from the context menu.\nframework.disableGrouping.accesskey=u\n\n# LOCALIZATION NOTE (framework.enableGrouping): This is the text that appears in the\n# context menu to enable framework grouping.\nframework.enableGrouping=Enable Framework Grouping\n\n# LOCALIZATION NOTE (framework.enableGrouping.accesskey): Access key to toggle\n# framework grouping from the context menu.\nframework.enableGrouping.accesskey=u\n\n# LOCALIZATION NOTE (generated): Source Map term for a server source location\ngenerated=generated\n\n# LOCALIZATION NOTE (original): Source Map term for a debugger UI source location\noriginal=original\n\n# LOCALIZATION NOTE (expressions.placeholder): Placeholder text for expression\n# input element\nexpressions.placeholder=Add Watch Expression\n\n# LOCALIZATION NOTE (sourceTabs.closeTab): Editor source tab context menu item\n# for closing the selected tab below the mouse.\nsourceTabs.closeTab=Close tab\n\n# LOCALIZATION NOTE (sourceTabs.closeTab.accesskey): Access key to close the currently select\n# source tab from the editor context menu item.\nsourceTabs.closeTab.accesskey=c\n\n# LOCALIZATION NOTE (sourceTabs.closeOtherTabs): Editor source tab context menu item\n# for closing the other tabs.\nsourceTabs.closeOtherTabs=Close others\n\n# LOCALIZATION NOTE (sourceTabs.closeOtherTabs.accesskey): Access key to close other source tabs\n# from the editor context menu.\nsourceTabs.closeOtherTabs.accesskey=o\n\n# LOCALIZATION NOTE (sourceTabs.closeTabsToEnd): Editor source tab context menu item\n# for closing the tabs to the end (the right for LTR languages) of the selected tab.\nsourceTabs.closeTabsToEnd=Close tabs to the right\n\n# LOCALIZATION NOTE (sourceTabs.closeTabsToEnd.accesskey): Access key to close source tabs\n# after the selected tab from the editor context menu.\nsourceTabs.closeTabsToEnd.accesskey=e\n\n# LOCALIZATION NOTE (sourceTabs.closeAllTabs): Editor source tab context menu item\n# for closing all tabs.\nsourceTabs.closeAllTabs=Close all tabs\n\n# LOCALIZATION NOTE (sourceTabs.closeAllTabs.accesskey): Access key to close all tabs from the\n# editor context menu.\nsourceTabs.closeAllTabs.accesskey=a\n\n# LOCALIZATION NOTE (sourceTabs.revealInTree): Editor source tab context menu item\n# for revealing source in tree.\nsourceTabs.revealInTree=Reveal in Tree\n\n# LOCALIZATION NOTE (sourceTabs.revealInTree.accesskey): Access key to reveal a source in the\n# tree from the context menu.\nsourceTabs.revealInTree.accesskey=r\n\n# LOCALIZATION NOTE (sourceTabs.copyLink): Editor source tab context menu item\n# for copying a link address.\nsourceTabs.copyLink=Copy Link Address\n\n# LOCALIZATION NOTE (sourceTabs.copyLink.accesskey): Access key to copy a link addresss from the\n# editor context menu.\nsourceTabs.copyLink.accesskey=l\n\n# LOCALIZATION NOTE (sourceTabs.prettyPrint): Editor source tab context menu item\n# for pretty printing the source.\nsourceTabs.prettyPrint=Pretty Print Source\n\n# LOCALIZATION NOTE (sourceTabs.prettyPrint.accesskey): Access key to pretty print a source from\n# the editor context menu.\nsourceTabs.prettyPrint.accesskey=p\n\n# LOCALIZATION NOTE (sourceFooter.blackbox): Tooltip text associated\n# with the blackbox button\nsourceFooter.blackbox=Blackbox Source\n\n# LOCALIZATION NOTE (sourceFooter.unblackbox): Tooltip text associated\n# with the blackbox button\nsourceFooter.unblackbox=Unblackbox Source\n\n# LOCALIZATION NOTE (sourceFooter.unblackbox.accesskey): Access key to blackbox\n# an associated source\nsourceFooter.unblackbox.accesskey=b\n\n# LOCALIZATION NOTE (sourceFooter.blackbox.accesskey): Access key to blackbox\n# an associated source\nsourceFooter.blackbox.accesskey=b\n\n# LOCALIZATION NOTE (sourceFooter.blackboxed): Text associated\n# with a blackboxed source\nsourceFooter.blackboxed=Blackboxed Source\n\n# LOCALIZATION NOTE (sourceTabs.closeTabButtonTooltip): The tooltip that is displayed\n# for close tab button in source tabs.\nsourceTabs.closeTabButtonTooltip=Close tab\n\n# LOCALIZATION NOTE (sourceTabs.newTabButtonTooltip): The tooltip that is displayed for\n# new tab button in source tabs.\nsourceTabs.newTabButtonTooltip=Search for sources (%S)\n\n# LOCALIZATION NOTE (scopes.header): Scopes right sidebar pane header.\nscopes.header=Scopes\n\n# LOCALIZATION NOTE (scopes.notAvailable): Scopes right sidebar pane message\n# for when the debugger is paused, but there isn't pause data.\nscopes.notAvailable=Scopes Unavailable\n\n# LOCALIZATION NOTE (scopes.notPaused): Scopes right sidebar pane message\n# for when the debugger is not paused.\nscopes.notPaused=Not Paused\n\n# LOCALIZATION NOTE (scopes.block): Refers to a block of code in\n# the scopes pane when the debugger is paused.\nscopes.block=Block\n\n# LOCALIZATION NOTE (sources.header): Sources left sidebar header\nsources.header=Sources\n\n# LOCALIZATION NOTE (sources.search): Sources left sidebar prompt\n# e.g. Cmd+P to search. On a mac, we use the command unicode character.\n# On windows, it's ctrl.\nsources.search=%S to search\n\n# LOCALIZATION NOTE (watchExpressions.header): Watch Expressions right sidebar\n# pane header.\nwatchExpressions.header=Watch Expressions\n\n# LOCALIZATION NOTE (watchExpressions.refreshButton): Watch Expressions header\n# button for refreshing the expressions.\nwatchExpressions.refreshButton=Refresh\n\n# LOCALIZATION NOTE (welcome.search): The center pane welcome panel's\n# search prompt. e.g. cmd+p to search for files. On windows, it's ctrl, on\n# a mac we use the unicode character.\nwelcome.search=%S to search for sources\n\n# LOCALIZATION NOTE (sourceSearch.search): The center pane Source Search\n# prompt for searching for files.\nsourceSearch.search=Search Sources…\n\n# LOCALIZATION NOTE (sourceSearch.noResults): The center pane Source Search\n# message when the query did not match any of the sources.\nsourceSearch.noResults=No files matching %S found\n\n# LOCALIZATION NOTE (ignoreExceptions): The pause on exceptions button tooltip\n# when the debugger will not pause on exceptions.\nignoreExceptions=Ignore exceptions. Click to pause on uncaught exceptions\n\n# LOCALIZATION NOTE (pauseOnUncaughtExceptions): The pause on exceptions button\n# tooltip when the debugger will pause on uncaught exceptions.\npauseOnUncaughtExceptions=Pause on uncaught exceptions. Click to pause on all exceptions\n\n# LOCALIZATION NOTE (pauseOnExceptions): The pause on exceptions button tooltip\n# when the debugger will pause on all exceptions.\npauseOnExceptions=Pause on all exceptions. Click to ignore exceptions\n\n# LOCALIZATION NOTE (loadingText): The text that is displayed in the script\n# editor when the loading process has started but there is no file to display\n# yet.\nloadingText=Loading\\u2026\n\n# LOCALIZATION NOTE (errorLoadingText2): The text that is displayed in the debugger\n# viewer when there is an error loading a file\nerrorLoadingText2=Error loading this URL: %S\n\n# LOCALIZATION NOTE (addWatchExpressionText): The text that is displayed in the\n# watch expressions list to add a new item.\naddWatchExpressionText=Add watch expression\n\n# LOCALIZATION NOTE (addWatchExpressionButton): The button that is displayed in the\n# variables view popup.\naddWatchExpressionButton=Watch\n\n# LOCALIZATION NOTE (emptyVariablesText): The text that is displayed in the\n# variables pane when there are no variables to display.\nemptyVariablesText=No variables to display\n\n# LOCALIZATION NOTE (scopeLabel): The text that is displayed in the variables\n# pane as a header for each variable scope (e.g. \"Global scope, \"With scope\",\n# etc.).\nscopeLabel=%S scope\n\n# LOCALIZATION NOTE (watchExpressionsScopeLabel): The name of the watch\n# expressions scope. This text is displayed in the variables pane as a header for\n# the watch expressions scope.\nwatchExpressionsScopeLabel=Watch expressions\n\n# LOCALIZATION NOTE (globalScopeLabel): The name of the global scope. This text\n# is added to scopeLabel and displayed in the variables pane as a header for\n# the global scope.\nglobalScopeLabel=Global\n\n# LOCALIZATION NOTE (variablesViewErrorStacktrace): This is the text that is\n# shown before the stack trace in an error.\nvariablesViewErrorStacktrace=Stack trace:\n\n# LOCALIZATION NOTE (variablesViewMoreObjects): the text that is displayed\n# when you have an object preview that does not show all of the elements. At the end of the list\n# you see \"N more...\" in the web console output.\n# This is a semi-colon list of plural forms.\n# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals\n# #1 number of remaining items in the object\n# example: 3 more…\nvariablesViewMoreObjects=#1 more…;#1 more…\n\n# LOCALIZATION NOTE (variablesEditableNameTooltip): The text that is displayed\n# in the variables list on an item with an editable name.\nvariablesEditableNameTooltip=Double click to edit\n\n# LOCALIZATION NOTE (variablesEditableValueTooltip): The text that is displayed\n# in the variables list on an item with an editable value.\nvariablesEditableValueTooltip=Click to change value\n\n# LOCALIZATION NOTE (variablesCloseButtonTooltip): The text that is displayed\n# in the variables list on an item which can be removed.\nvariablesCloseButtonTooltip=Click to remove\n\n# LOCALIZATION NOTE (variablesEditButtonTooltip): The text that is displayed\n# in the variables list on a getter or setter which can be edited.\nvariablesEditButtonTooltip=Click to set value\n\n# LOCALIZATION NOTE (variablesEditableValueTooltip): The text that is displayed\n# in a tooltip on the \"open in inspector\" button in the the variables list for a\n# DOMNode item.\nvariablesDomNodeValueTooltip=Click to select the node in the inspector\n\n# LOCALIZATION NOTE (configurable|...|Tooltip): The text that is displayed\n# in the variables list on certain variables or properties as tooltips.\n# Expanations of what these represent can be found at the following links:\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed\n# It's probably best to keep these in English.\nconfigurableTooltip=configurable\nenumerableTooltip=enumerable\nwritableTooltip=writable\nfrozenTooltip=frozen\nsealedTooltip=sealed\nextensibleTooltip=extensible\noverriddenTooltip=overridden\nWebIDLTooltip=WebIDL\n\n# LOCALIZATION NOTE (variablesSeparatorLabel): The text that is displayed\n# in the variables list as a separator between the name and value.\nvariablesSeparatorLabel=:\n\n# LOCALIZATION NOTE (watchExpressionsSeparatorLabel2): The text that is displayed\n# in the watch expressions list as a separator between the code and evaluation.\nwatchExpressionsSeparatorLabel2=\\u0020→\n\n# LOCALIZATION NOTE (functionSearchSeparatorLabel): The text that is displayed\n# in the functions search panel as a separator between function's inferred name\n# and its real name (if available).\nfunctionSearchSeparatorLabel=←\n\n# LOCALIZATION NOTE(symbolSearch.search.functionsPlaceholder): The placeholder\n# text displayed when the user searches for functions in a file\nsymbolSearch.search.functionsPlaceholder=Search functions…\n\n# LOCALIZATION NOTE(symbolSearch.search.variablesPlaceholder): The placeholder\n# text displayed when the user searches for variables in a file\nsymbolSearch.search.variablesPlaceholder=Search variables…\n\n# LOCALIZATION NOTE(symbolSearch.search.key2): The Key Shortcut for\n# searching for a function or variable\nsymbolSearch.search.key2=CmdOrCtrl+Shift+O\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.regex): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.regex=Regex\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.caseSensitive): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.caseSensitive=Case sensitive\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.wholeWord): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.wholeWord=Whole word\n\n# LOCALIZATION NOTE (resumptionOrderPanelTitle): This is the text that appears\n# as a description in the notification panel popup, when multiple debuggers are\n# open in separate tabs and the user tries to resume them in the wrong order.\n# The substitution parameter is the URL of the last paused window that must be\n# resumed first.\nresumptionOrderPanelTitle=There are one or more paused debuggers. Please resume the most-recently paused debugger first at: %S\n\nvariablesViewOptimizedOut=(optimized away)\nvariablesViewUninitialized=(uninitialized)\nvariablesViewMissingArgs=(unavailable)\n\nanonymousSourcesLabel=Anonymous Sources\n\nexperimental=This is an experimental feature\n\n# LOCALIZATION NOTE (whyPaused.debuggerStatement): The text that is displayed\n# in a info block explaining how the debugger is currently paused due to a `debugger`\n# statement in the code\nwhyPaused.debuggerStatement=Paused on debugger statement\n\n# LOCALIZATION NOTE (whyPaused.breakpoint): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a breakpoint\nwhyPaused.breakpoint=Paused on breakpoint\n\n# LOCALIZATION NOTE (whyPaused.exception): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an exception\nwhyPaused.exception=Paused on exception\n\n# LOCALIZATION NOTE (whyPaused.resumeLimit): The text that is displayed\n# in a info block explaining how the debugger is currently paused while stepping\n# in or out of the stack\nwhyPaused.resumeLimit=Paused while stepping\n\n# LOCALIZATION NOTE (whyPaused.pauseOnDOMEvents): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# dom event\nwhyPaused.pauseOnDOMEvents=Paused on event listener\n\n# LOCALIZATION NOTE (whyPaused.breakpointConditionThrown): The text that is displayed\n# in an info block when evaluating a conditional breakpoint throws an error\nwhyPaused.breakpointConditionThrown=Error with conditional breakpoint\n\n# LOCALIZATION NOTE (whyPaused.xhr): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an\n# xml http request\nwhyPaused.xhr=Paused on XMLHttpRequest\n\n# LOCALIZATION NOTE (whyPaused.promiseRejection): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# promise rejection\nwhyPaused.promiseRejection=Paused on promise rejection\n\n# LOCALIZATION NOTE (whyPaused.assert): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an\n# assert\nwhyPaused.assert=Paused on assertion\n\n# LOCALIZATION NOTE (whyPaused.debugCommand): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# debugger statement\nwhyPaused.debugCommand=Paused on debugged function\n\n# LOCALIZATION NOTE (whyPaused.other): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an event\n# listener breakpoint set\nwhyPaused.other=Debugger paused\n\n# LOCALIZATION NOTE (ctrl): The text that is used for documenting\n# keyboard shortcuts that use the control key\nctrl=Ctrl\n"
+	module.exports = "# This Source Code Form is subject to the terms of the Mozilla Public\n# License, v. 2.0. If a copy of the MPL was not distributed with this\n# file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\n# LOCALIZATION NOTE These strings are used inside the Debugger\n# which is available from the Web Developer sub-menu -> 'Debugger'.\n# The correct localization of this file might be to keep it in\n# English, or another language commonly spoken among web developers.\n# You want to make that choice consistent across the developer tools.\n# A good criteria is the language in which you'd find the best\n# documentation on web development on the web.\n\n# LOCALIZATION NOTE (collapsePanes): This is the tooltip for the button\n# that collapses the left and right panes in the debugger UI.\ncollapsePanes=Collapse panes\n\n# LOCALIZATION NOTE (copySourceUrl): This is the text that appears in the\n# context menu to copy the source URL of file open.\ncopySourceUrl=Copy Source Url\n\n# LOCALIZATION NOTE (copySourceUrl.accesskey): Access key to copy the source URL of a file from\n# the context menu.\ncopySourceUrl.accesskey=u\n\n# LOCALIZATION NOTE (copyStackTrace): This is the text that appears in the\n# context menu to copy the stack trace methods, file names and row number.\ncopyStackTrace=Copy Stack Trace\n\n# LOCALIZATION NOTE (copyStackTrace.accesskey): Access key to copy the stack trace data from\n# the context menu.\ncopyStackTrace.accesskey=c\n\n# LOCALIZATION NOTE (expandPanes): This is the tooltip for the button\n# that expands the left and right panes in the debugger UI.\nexpandPanes=Expand panes\n\n# LOCALIZATION NOTE (pauseButtonTooltip): The tooltip that is displayed for the pause\n# button when the debugger is in a running state.\npauseButtonTooltip=Pause %S\n\n# LOCALIZATION NOTE (pausePendingButtonTooltip): The tooltip that is displayed for\n# the pause button after it's been clicked but before the next JavaScript to run.\npausePendingButtonTooltip=Waiting for next execution\n\n# LOCALIZATION NOTE (resumeButtonTooltip): The label that is displayed on the pause\n# button when the debugger is in a paused state.\nresumeButtonTooltip=Resume %S\n\n# LOCALIZATION NOTE (stepOverTooltip): The label that is displayed on the\n# button that steps over a function call.\nstepOverTooltip=Step Over %S\n\n# LOCALIZATION NOTE (stepInTooltip): The label that is displayed on the\n# button that steps into a function call.\nstepInTooltip=Step In %S\n\n# LOCALIZATION NOTE (stepOutTooltip): The label that is displayed on the\n# button that steps out of a function call.\nstepOutTooltip=Step Out %S\n\n# LOCALIZATION NOTE (noWorkersText): The text to display in the workers list\n# when there are no workers.\nnoWorkersText=This page has no workers.\n\n# LOCALIZATION NOTE (noSourcesText): The text to display in the sources list\n# when there are no sources.\nnoSourcesText=This page has no sources.\n\n# LOCALIZATION NOTE (noEventListenersText): The text to display in the events tab\n# when there are no events.\nnoEventListenersText=No event listeners to display\n\n# LOCALIZATION NOTE (eventListenersHeader): The text to display in the events\n# header.\neventListenersHeader=Event Listeners\n\n# LOCALIZATION NOTE (noStackFramesText): The text to display in the call stack tab\n# when there are no stack frames.\nnoStackFramesText=No stack frames to display\n\n# LOCALIZATION NOTE (eventCheckboxTooltip): The tooltip text to display when\n# the user hovers over the checkbox used to toggle an event breakpoint.\neventCheckboxTooltip=Toggle breaking on this event\n\n# LOCALIZATION NOTE (eventOnSelector): The text to display in the events tab\n# for every event item, between the event type and event selector.\neventOnSelector=on\n\n# LOCALIZATION NOTE (eventInSource): The text to display in the events tab\n# for every event item, between the event selector and listener's owner source.\neventInSource=in\n\n# LOCALIZATION NOTE (eventNodes): The text to display in the events tab when\n# an event is listened on more than one target node.\neventNodes=%S nodes\n\n# LOCALIZATION NOTE (eventNative): The text to display in the events tab when\n# a listener is added from plugins, thus getting translated to native code.\neventNative=[native code]\n\n# LOCALIZATION NOTE (*Events): The text to display in the events tab for\n# each group of sub-level event entries.\nanimationEvents=Animation\naudioEvents=Audio\nbatteryEvents=Battery\nclipboardEvents=Clipboard\ncompositionEvents=Composition\ndeviceEvents=Device\ndisplayEvents=Display\ndragAndDropEvents=Drag and Drop\ngamepadEvents=Gamepad\nindexedDBEvents=IndexedDB\ninteractionEvents=Interaction\nkeyboardEvents=Keyboard\nmediaEvents=HTML5 Media\nmouseEvents=Mouse\nmutationEvents=Mutation\nnavigationEvents=Navigation\npointerLockEvents=Pointer Lock\nsensorEvents=Sensor\nstorageEvents=Storage\ntimeEvents=Time\ntouchEvents=Touch\notherEvents=Other\n\n# LOCALIZATION NOTE (blackboxCheckboxTooltip2): The tooltip text to display when\n# the user hovers over the checkbox used to toggle blackboxing its associated\n# source.\nblackboxCheckboxTooltip2=Toggle blackboxing\n\n# LOCALIZATION NOTE (sources.search.key2): Key shortcut to open the search for\n# searching all the source files the debugger has seen.\nsources.search.key2=CmdOrCtrl+P\n\n# LOCALIZATION NOTE (sources.search.alt.key): A second key shortcut to open the\n# search for searching all the source files the debugger has seen.\nsources.search.alt.key=CmdOrCtrl+O\n\n# LOCALIZATION NOTE (projectTextSearch.key): A key shortcut to open the\n# full project text search for searching all the files the debugger has seen.\nprojectTextSearch.key=CmdOrCtrl+Shift+F\n\n# LOCALIZATION NOTE (sources.noSourcesAvailable): Text shown when the debugger\n# does not have any sources.\nsources.noSourcesAvailable=This page has no sources\n\n# LOCALIZATION NOTE (sourcesPane.showSourcesTooltip): The tooltip shown when\n# the user will navigate to the source tree view.\nsourcesPane.showSourcesTooltip=Show sources\n\n# LOCALIZATION NOTE (sourcesPane.showOutlineTooltip): The tooltip shown when\n# the user will navigate to the source outline view.\nsourcesPane.showOutlineTooltip=Show outline\n\n# LOCALIZATION NOTE (sourceSearch.search.key2): Key shortcut to open the search\n# for searching within a the currently opened files in the editor\nsourceSearch.search.key2=CmdOrCtrl+F\n\n# LOCALIZATION NOTE (sourceSearch.search.placeholder): placeholder text in\n# the source search input bar\nsourceSearch.search.placeholder=Search in file…\n\n# LOCALIZATION NOTE (sourceSearch.search.again.key2): Key shortcut to highlight\n# the next occurrence of the last search triggered from a source search\nsourceSearch.search.again.key2=CmdOrCtrl+G\n\n# LOCALIZATION NOTE (sourceSearch.search.againPrev.key2): Key shortcut to highlight\n# the previous occurrence of the last search triggered from a source search\nsourceSearch.search.againPrev.key2=CmdOrCtrl+Shift+G\n\n# LOCALIZATION NOTE (sourceSearch.resultsSummary1): Shows a summary of\n# the number of matches for autocomplete\nsourceSearch.resultsSummary1=%d results\n\n# LOCALIZATION NOTE (noMatchingStringsText): The text to display in the\n# global search results when there are no matching strings after filtering.\nnoMatchingStringsText=No matches found\n\n# LOCALIZATION NOTE (emptySearchText): This is the text that appears in the\n# filter text box when it is empty and the scripts container is selected.\nemptySearchText=Search scripts (%S)\n\n# LOCALIZATION NOTE (emptyVariablesFilterText): This is the text that\n# appears in the filter text box for the variables view container.\nemptyVariablesFilterText=Filter variables\n\n# LOCALIZATION NOTE (emptyPropertiesFilterText): This is the text that\n# appears in the filter text box for the editor's variables view bubble.\nemptyPropertiesFilterText=Filter properties\n\n# LOCALIZATION NOTE (searchPanelFilter): This is the text that appears in the\n# filter panel popup for the filter scripts operation.\nsearchPanelFilter=Filter scripts (%S)\n\n# LOCALIZATION NOTE (searchPanelGlobal): This is the text that appears in the\n# filter panel popup for the global search operation.\nsearchPanelGlobal=Search in all files (%S)\n\n# LOCALIZATION NOTE (searchPanelFunction): This is the text that appears in the\n# filter panel popup for the function search operation.\nsearchPanelFunction=Search for function definition (%S)\n\n# LOCALIZATION NOTE (searchPanelToken): This is the text that appears in the\n# filter panel popup for the token search operation.\nsearchPanelToken=Find in this file (%S)\n\n# LOCALIZATION NOTE (searchPanelGoToLine): This is the text that appears in the\n# filter panel popup for the line search operation.\nsearchPanelGoToLine=Go to line (%S)\n\n# LOCALIZATION NOTE (searchPanelVariable): This is the text that appears in the\n# filter panel popup for the variables search operation.\nsearchPanelVariable=Filter variables (%S)\n\n# LOCALIZATION NOTE (breakpointMenuItem): The text for all the elements that\n# are displayed in the breakpoints menu item popup.\nbreakpointMenuItem.setConditional=Configure conditional breakpoint\nbreakpointMenuItem.enableSelf=Enable breakpoint\nbreakpointMenuItem.disableSelf=Disable breakpoint\nbreakpointMenuItem.deleteSelf=Remove breakpoint\nbreakpointMenuItem.enableOthers=Enable others\nbreakpointMenuItem.disableOthers=Disable others\nbreakpointMenuItem.deleteOthers=Remove others\nbreakpointMenuItem.enableAll=Enable all breakpoints\nbreakpointMenuItem.disableAll=Disable all breakpoints\nbreakpointMenuItem.deleteAll=Remove all breakpoints\n\n# LOCALIZATION NOTE (breakpoints.header): Breakpoints right sidebar pane header.\nbreakpoints.header=Breakpoints\n\n# LOCALIZATION NOTE (breakpoints.none): The text that appears when there are\n# no breakpoints present\nbreakpoints.none=No Breakpoints\n\n# LOCALIZATION NOTE (breakpoints.enable): The text that may appear as a tooltip\n# when hovering over the 'disable breakpoints' switch button in right sidebar\nbreakpoints.enable=Enable Breakpoints\n\n# LOCALIZATION NOTE (breakpoints.disable): The text that may appear as a tooltip\n# when hovering over the 'disable breakpoints' switch button in right sidebar\nbreakpoints.disable=Disable Breakpoints\n\n# LOCALIZATION NOTE (breakpoints.removeBreakpointTooltip): The tooltip that is displayed\n# for remove breakpoint button in right sidebar\nbreakpoints.removeBreakpointTooltip=Remove Breakpoint\n\n# LOCALIZATION NOTE (callStack.header): Call Stack right sidebar pane header.\ncallStack.header=Call Stack\n\n# LOCALIZATION NOTE (callStack.notPaused): Call Stack right sidebar pane\n# message when not paused.\ncallStack.notPaused=Not Paused\n\n# LOCALIZATION NOTE (callStack.collapse): Call Stack right sidebar pane\n# message to hide some of the frames that are shown.\ncallStack.collapse=Collapse Rows\n\n# LOCALIZATION NOTE (callStack.expand): Call Stack right sidebar pane\n# message to show more of the frames.\ncallStack.expand=Expand Rows\n\n# LOCALIZATION NOTE (editor.searchResults): Editor Search bar message\n# for the summarizing the selected search result. e.g. 5 of 10 results.\neditor.searchResults=%d of %d results\n\n# LOCALIZATION NOTE (sourceSearch.singleResult): Copy shown when there is one result.\neditor.singleResult=1 result\n\n# LOCALIZATION NOTE (editor.noResults): Editor Search bar message\n# for when no results found.\neditor.noResults=no results\n\n# LOCALIZATION NOTE (editor.searchResults.nextResult): Editor Search bar\n# tooltip for traversing to the Next Result\neditor.searchResults.nextResult=Next Result\n\n# LOCALIZATION NOTE (editor.searchResults.prevResult): Editor Search bar\n# tooltip for traversing to the Previous Result\neditor.searchResults.prevResult=Previous Result\n\n# LOCALIZATION NOTE (editor.searchTypeToggleTitle): Search bar title for\n# toggling search type buttons(function search, variable search)\neditor.searchTypeToggleTitle=Search for:\n\n# LOCALIZATION NOTE (editor.addBreakpoint): Editor gutter context menu item\n# for adding a breakpoint on a line.\neditor.addBreakpoint=Add Breakpoint\n\n# LOCALIZATION NOTE (editor.disableBreakpoint): Editor gutter context menu item\n# for disabling a breakpoint on a line.\neditor.disableBreakpoint=Disable Breakpoint\n\n# LOCALIZATION NOTE (editor.enableBreakpoint): Editor gutter context menu item\n# for enabling a breakpoint on a line.\neditor.enableBreakpoint=Enable Breakpoint\n\n# LOCALIZATION NOTE (editor.removeBreakpoint): Editor gutter context menu item\n# for removing a breakpoint on a line.\neditor.removeBreakpoint=Remove Breakpoint\n\n# LOCALIZATION NOTE (editor.editBreakpoint): Editor gutter context menu item\n# for setting a breakpoint condition on a line.\neditor.editBreakpoint=Edit Breakpoint\n\n# LOCALIZATION NOTE (editor.addConditionalBreakpoint): Editor gutter context\n# menu item for adding a breakpoint condition on a line.\neditor.addConditionalBreakpoint=Add Conditional Breakpoint\n\n# LOCALIZATION NOTE (editor.conditionalPanel.placeholder): Placeholder text for\n# input element inside ConditionalPanel component\neditor.conditionalPanel.placeholder=This breakpoint will pause when the expression is true\n\n# LOCALIZATION NOTE (editor.conditionalPanel.placeholder): Tooltip text for\n# close button inside ConditionalPanel component\neditor.conditionalPanel.close=Cancel edit breakpoint and close\n\n# LOCALIZATION NOTE (editor.jumpToMappedLocation1): Context menu item\n# for navigating to a source mapped location\neditor.jumpToMappedLocation1=Jump to %S location\n\n# LOCALIZATION NOTE (framework.disableGrouping): This is the text that appears in the\n# context menu to disable framework grouping.\nframework.disableGrouping=Disable Framework Grouping\n\n# LOCALIZATION NOTE (framework.disableGrouping.accesskey): Access key to toggle\n# framework grouping from the context menu.\nframework.disableGrouping.accesskey=u\n\n# LOCALIZATION NOTE (framework.enableGrouping): This is the text that appears in the\n# context menu to enable framework grouping.\nframework.enableGrouping=Enable Framework Grouping\n\n# LOCALIZATION NOTE (framework.enableGrouping.accesskey): Access key to toggle\n# framework grouping from the context menu.\nframework.enableGrouping.accesskey=u\n\n# LOCALIZATION NOTE (generated): Source Map term for a server source location\ngenerated=generated\n\n# LOCALIZATION NOTE (original): Source Map term for a debugger UI source location\noriginal=original\n\n# LOCALIZATION NOTE (expressions.placeholder): Placeholder text for expression\n# input element\nexpressions.placeholder=Add Watch Expression\n\n# LOCALIZATION NOTE (sourceTabs.closeTab): Editor source tab context menu item\n# for closing the selected tab below the mouse.\nsourceTabs.closeTab=Close tab\n\n# LOCALIZATION NOTE (sourceTabs.closeTab.accesskey): Access key to close the currently select\n# source tab from the editor context menu item.\nsourceTabs.closeTab.accesskey=c\n\n# LOCALIZATION NOTE (sourceTabs.closeOtherTabs): Editor source tab context menu item\n# for closing the other tabs.\nsourceTabs.closeOtherTabs=Close others\n\n# LOCALIZATION NOTE (sourceTabs.closeOtherTabs.accesskey): Access key to close other source tabs\n# from the editor context menu.\nsourceTabs.closeOtherTabs.accesskey=o\n\n# LOCALIZATION NOTE (sourceTabs.closeTabsToEnd): Editor source tab context menu item\n# for closing the tabs to the end (the right for LTR languages) of the selected tab.\nsourceTabs.closeTabsToEnd=Close tabs to the right\n\n# LOCALIZATION NOTE (sourceTabs.closeTabsToEnd.accesskey): Access key to close source tabs\n# after the selected tab from the editor context menu.\nsourceTabs.closeTabsToEnd.accesskey=e\n\n# LOCALIZATION NOTE (sourceTabs.closeAllTabs): Editor source tab context menu item\n# for closing all tabs.\nsourceTabs.closeAllTabs=Close all tabs\n\n# LOCALIZATION NOTE (sourceTabs.closeAllTabs.accesskey): Access key to close all tabs from the\n# editor context menu.\nsourceTabs.closeAllTabs.accesskey=a\n\n# LOCALIZATION NOTE (sourceTabs.revealInTree): Editor source tab context menu item\n# for revealing source in tree.\nsourceTabs.revealInTree=Reveal in Tree\n\n# LOCALIZATION NOTE (sourceTabs.revealInTree.accesskey): Access key to reveal a source in the\n# tree from the context menu.\nsourceTabs.revealInTree.accesskey=r\n\n# LOCALIZATION NOTE (sourceTabs.copyLink): Editor source tab context menu item\n# for copying a link address.\nsourceTabs.copyLink=Copy Link Address\n\n# LOCALIZATION NOTE (sourceTabs.copyLink.accesskey): Access key to copy a link addresss from the\n# editor context menu.\nsourceTabs.copyLink.accesskey=l\n\n# LOCALIZATION NOTE (sourceTabs.prettyPrint): Editor source tab context menu item\n# for pretty printing the source.\nsourceTabs.prettyPrint=Pretty Print Source\n\n# LOCALIZATION NOTE (sourceTabs.prettyPrint.accesskey): Access key to pretty print a source from\n# the editor context menu.\nsourceTabs.prettyPrint.accesskey=p\n\n# LOCALIZATION NOTE (sourceFooter.blackbox): Tooltip text associated\n# with the blackbox button\nsourceFooter.blackbox=Blackbox Source\n\n# LOCALIZATION NOTE (sourceFooter.unblackbox): Tooltip text associated\n# with the blackbox button\nsourceFooter.unblackbox=Unblackbox Source\n\n# LOCALIZATION NOTE (sourceFooter.unblackbox.accesskey): Access key to blackbox\n# an associated source\nsourceFooter.unblackbox.accesskey=b\n\n# LOCALIZATION NOTE (sourceFooter.blackbox.accesskey): Access key to blackbox\n# an associated source\nsourceFooter.blackbox.accesskey=b\n\n# LOCALIZATION NOTE (sourceFooter.blackboxed): Text associated\n# with a blackboxed source\nsourceFooter.blackboxed=Blackboxed Source\n\n# LOCALIZATION NOTE (sourceTabs.closeTabButtonTooltip): The tooltip that is displayed\n# for close tab button in source tabs.\nsourceTabs.closeTabButtonTooltip=Close tab\n\n# LOCALIZATION NOTE (sourceTabs.newTabButtonTooltip): The tooltip that is displayed for\n# new tab button in source tabs.\nsourceTabs.newTabButtonTooltip=Search for sources (%S)\n\n# LOCALIZATION NOTE (scopes.header): Scopes right sidebar pane header.\nscopes.header=Scopes\n\n# LOCALIZATION NOTE (scopes.notAvailable): Scopes right sidebar pane message\n# for when the debugger is paused, but there isn't pause data.\nscopes.notAvailable=Scopes Unavailable\n\n# LOCALIZATION NOTE (scopes.notPaused): Scopes right sidebar pane message\n# for when the debugger is not paused.\nscopes.notPaused=Not Paused\n\n# LOCALIZATION NOTE (scopes.block): Refers to a block of code in\n# the scopes pane when the debugger is paused.\nscopes.block=Block\n\n# LOCALIZATION NOTE (sources.header): Sources left sidebar header\nsources.header=Sources\n\n# LOCALIZATION NOTE (sources.search): Sources left sidebar prompt\n# e.g. Cmd+P to search. On a mac, we use the command unicode character.\n# On windows, it's ctrl.\nsources.search=%S to search\n\n# LOCALIZATION NOTE (watchExpressions.header): Watch Expressions right sidebar\n# pane header.\nwatchExpressions.header=Watch Expressions\n\n# LOCALIZATION NOTE (watchExpressions.refreshButton): Watch Expressions header\n# button for refreshing the expressions.\nwatchExpressions.refreshButton=Refresh\n\n# LOCALIZATION NOTE (welcome.search): The center pane welcome panel's\n# search prompt. e.g. cmd+p to search for files. On windows, it's ctrl, on\n# a mac we use the unicode character.\nwelcome.search=%S to search for sources\n\n# LOCALIZATION NOTE (sourceSearch.search): The center pane Source Search\n# prompt for searching for files.\nsourceSearch.search=Search Sources…\n\n# LOCALIZATION NOTE (sourceSearch.noResults): The center pane Source Search\n# message when the query did not match any of the sources.\nsourceSearch.noResults=No files matching %S found\n\n# LOCALIZATION NOTE (ignoreExceptions): The pause on exceptions button tooltip\n# when the debugger will not pause on exceptions.\nignoreExceptions=Ignore exceptions. Click to pause on uncaught exceptions\n\n# LOCALIZATION NOTE (pauseOnUncaughtExceptions): The pause on exceptions button\n# tooltip when the debugger will pause on uncaught exceptions.\npauseOnUncaughtExceptions=Pause on uncaught exceptions. Click to pause on all exceptions\n\n# LOCALIZATION NOTE (pauseOnExceptions): The pause on exceptions button tooltip\n# when the debugger will pause on all exceptions.\npauseOnExceptions=Pause on all exceptions. Click to ignore exceptions\n\n# LOCALIZATION NOTE (loadingText): The text that is displayed in the script\n# editor when the loading process has started but there is no file to display\n# yet.\nloadingText=Loading\\u2026\n\n# LOCALIZATION NOTE (errorLoadingText2): The text that is displayed in the debugger\n# viewer when there is an error loading a file\nerrorLoadingText2=Error loading this URL: %S\n\n# LOCALIZATION NOTE (addWatchExpressionText): The text that is displayed in the\n# watch expressions list to add a new item.\naddWatchExpressionText=Add watch expression\n\n# LOCALIZATION NOTE (addWatchExpressionButton): The button that is displayed in the\n# variables view popup.\naddWatchExpressionButton=Watch\n\n# LOCALIZATION NOTE (emptyVariablesText): The text that is displayed in the\n# variables pane when there are no variables to display.\nemptyVariablesText=No variables to display\n\n# LOCALIZATION NOTE (scopeLabel): The text that is displayed in the variables\n# pane as a header for each variable scope (e.g. \"Global scope, \"With scope\",\n# etc.).\nscopeLabel=%S scope\n\n# LOCALIZATION NOTE (watchExpressionsScopeLabel): The name of the watch\n# expressions scope. This text is displayed in the variables pane as a header for\n# the watch expressions scope.\nwatchExpressionsScopeLabel=Watch expressions\n\n# LOCALIZATION NOTE (globalScopeLabel): The name of the global scope. This text\n# is added to scopeLabel and displayed in the variables pane as a header for\n# the global scope.\nglobalScopeLabel=Global\n\n# LOCALIZATION NOTE (variablesViewErrorStacktrace): This is the text that is\n# shown before the stack trace in an error.\nvariablesViewErrorStacktrace=Stack trace:\n\n# LOCALIZATION NOTE (variablesViewMoreObjects): the text that is displayed\n# when you have an object preview that does not show all of the elements. At the end of the list\n# you see \"N more...\" in the web console output.\n# This is a semi-colon list of plural forms.\n# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals\n# #1 number of remaining items in the object\n# example: 3 more…\nvariablesViewMoreObjects=#1 more…;#1 more…\n\n# LOCALIZATION NOTE (variablesEditableNameTooltip): The text that is displayed\n# in the variables list on an item with an editable name.\nvariablesEditableNameTooltip=Double click to edit\n\n# LOCALIZATION NOTE (variablesEditableValueTooltip): The text that is displayed\n# in the variables list on an item with an editable value.\nvariablesEditableValueTooltip=Click to change value\n\n# LOCALIZATION NOTE (variablesCloseButtonTooltip): The text that is displayed\n# in the variables list on an item which can be removed.\nvariablesCloseButtonTooltip=Click to remove\n\n# LOCALIZATION NOTE (variablesEditButtonTooltip): The text that is displayed\n# in the variables list on a getter or setter which can be edited.\nvariablesEditButtonTooltip=Click to set value\n\n# LOCALIZATION NOTE (variablesEditableValueTooltip): The text that is displayed\n# in a tooltip on the \"open in inspector\" button in the the variables list for a\n# DOMNode item.\nvariablesDomNodeValueTooltip=Click to select the node in the inspector\n\n# LOCALIZATION NOTE (configurable|...|Tooltip): The text that is displayed\n# in the variables list on certain variables or properties as tooltips.\n# Expanations of what these represent can be found at the following links:\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen\n# https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed\n# It's probably best to keep these in English.\nconfigurableTooltip=configurable\nenumerableTooltip=enumerable\nwritableTooltip=writable\nfrozenTooltip=frozen\nsealedTooltip=sealed\nextensibleTooltip=extensible\noverriddenTooltip=overridden\nWebIDLTooltip=WebIDL\n\n# LOCALIZATION NOTE (variablesSeparatorLabel): The text that is displayed\n# in the variables list as a separator between the name and value.\nvariablesSeparatorLabel=:\n\n# LOCALIZATION NOTE (watchExpressionsSeparatorLabel2): The text that is displayed\n# in the watch expressions list as a separator between the code and evaluation.\nwatchExpressionsSeparatorLabel2=\\u0020→\n\n# LOCALIZATION NOTE (functionSearchSeparatorLabel): The text that is displayed\n# in the functions search panel as a separator between function's inferred name\n# and its real name (if available).\nfunctionSearchSeparatorLabel=←\n\n# LOCALIZATION NOTE(symbolSearch.search.functionsPlaceholder): The placeholder\n# text displayed when the user searches for functions in a file\nsymbolSearch.search.functionsPlaceholder=Search functions…\n\n# LOCALIZATION NOTE(symbolSearch.search.variablesPlaceholder): The placeholder\n# text displayed when the user searches for variables in a file\nsymbolSearch.search.variablesPlaceholder=Search variables…\n\n# LOCALIZATION NOTE(symbolSearch.search.key2): The Key Shortcut for\n# searching for a function or variable\nsymbolSearch.search.key2=CmdOrCtrl+Shift+O\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.regex): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.regex=Regex\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.caseSensitive): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.caseSensitive=Case sensitive\n\n# LOCALIZATION NOTE(symbolSearch.searchModifier.wholeWord): A search option\n# when searching text in a file\nsymbolSearch.searchModifier.wholeWord=Whole word\n\n# LOCALIZATION NOTE (resumptionOrderPanelTitle): This is the text that appears\n# as a description in the notification panel popup, when multiple debuggers are\n# open in separate tabs and the user tries to resume them in the wrong order.\n# The substitution parameter is the URL of the last paused window that must be\n# resumed first.\nresumptionOrderPanelTitle=There are one or more paused debuggers. Please resume the most-recently paused debugger first at: %S\n\nvariablesViewOptimizedOut=(optimized away)\nvariablesViewUninitialized=(uninitialized)\nvariablesViewMissingArgs=(unavailable)\n\nanonymousSourcesLabel=Anonymous Sources\n\nexperimental=This is an experimental feature\n\n# LOCALIZATION NOTE (whyPaused.debuggerStatement): The text that is displayed\n# in a info block explaining how the debugger is currently paused due to a `debugger`\n# statement in the code\nwhyPaused.debuggerStatement=Paused on debugger statement\n\n# LOCALIZATION NOTE (whyPaused.breakpoint): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a breakpoint\nwhyPaused.breakpoint=Paused on breakpoint\n\n# LOCALIZATION NOTE (whyPaused.exception): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an exception\nwhyPaused.exception=Paused on exception\n\n# LOCALIZATION NOTE (whyPaused.resumeLimit): The text that is displayed\n# in a info block explaining how the debugger is currently paused while stepping\n# in or out of the stack\nwhyPaused.resumeLimit=Paused while stepping\n\n# LOCALIZATION NOTE (whyPaused.pauseOnDOMEvents): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# dom event\nwhyPaused.pauseOnDOMEvents=Paused on event listener\n\n# LOCALIZATION NOTE (whyPaused.breakpointConditionThrown): The text that is displayed\n# in an info block when evaluating a conditional breakpoint throws an error\nwhyPaused.breakpointConditionThrown=Error with conditional breakpoint\n\n# LOCALIZATION NOTE (whyPaused.xhr): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an\n# xml http request\nwhyPaused.xhr=Paused on XMLHttpRequest\n\n# LOCALIZATION NOTE (whyPaused.promiseRejection): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# promise rejection\nwhyPaused.promiseRejection=Paused on promise rejection\n\n# LOCALIZATION NOTE (whyPaused.assert): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an\n# assert\nwhyPaused.assert=Paused on assertion\n\n# LOCALIZATION NOTE (whyPaused.debugCommand): The text that is displayed\n# in a info block explaining how the debugger is currently paused on a\n# debugger statement\nwhyPaused.debugCommand=Paused on debugged function\n\n# LOCALIZATION NOTE (whyPaused.other): The text that is displayed\n# in a info block explaining how the debugger is currently paused on an event\n# listener breakpoint set\nwhyPaused.other=Debugger paused\n\n# LOCALIZATION NOTE (ctrl): The text that is used for documenting\n# keyboard shortcuts that use the control key\nctrl=Ctrl\n"
 
 /***/ },
 /* 961 */,
 /* 962 */,
 /* 963 */
 /***/ function(module, exports, __webpack_require__) {
 
 	var baseKeys = __webpack_require__(217),
@@ -37957,166 +36981,17 @@ return /******/ (function(modules) { // 
 	 */
 
 	function isObject(val) {
 	  return Object == val.constructor;
 	}
 
 
 /***/ },
-/* 966 */
-/***/ function(module, exports, __webpack_require__) {
-
-	"use strict";
-
-	/* This Source Code Form is subject to the terms of the Mozilla Public
-	 * License, v. 2.0. If a copy of the MPL was not distributed with this
-	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-	var _require = __webpack_require__(830),
-	    Menu = _require.Menu,
-	    MenuItem = _require.MenuItem;
-
-	var _require2 = __webpack_require__(828),
-	    isFirefoxPanel = _require2.isFirefoxPanel;
-
-	if (!isFirefoxPanel()) {
-	  __webpack_require__(973);
-	}
-
-	function createPopup(doc) {
-	  var popup = doc.createElement("menupopup");
-	  popup.className = "landing-popup";
-	  if (popup.openPopupAtScreen) {
-	    return popup;
-	  }
-
-	  function preventDefault(e) {
-	    e.preventDefault();
-	    e.returnValue = false;
-	  }
-
-	  var mask = document.querySelector("#contextmenu-mask");
-	  if (!mask) {
-	    mask = doc.createElement("div");
-	    mask.id = "contextmenu-mask";
-	    document.body.appendChild(mask);
-	  }
-
-	  mask.onclick = () => popup.hidePopup();
-
-	  popup.openPopupAtScreen = function (clientX, clientY) {
-	    this.style.setProperty("left", `${clientX}px`);
-	    this.style.setProperty("top", `${clientY}px`);
-	    mask = document.querySelector("#contextmenu-mask");
-	    window.onwheel = preventDefault;
-	    mask.classList.add("show");
-	    this.dispatchEvent(new Event("popupshown"));
-	    this.popupshown;
-	  };
-
-	  popup.hidePopup = function () {
-	    this.remove();
-	    mask = document.querySelector("#contextmenu-mask");
-	    mask.classList.remove("show");
-	    window.onwheel = null;
-	  };
-
-	  return popup;
-	}
-
-	if (!isFirefoxPanel()) {
-	  Menu.prototype.createPopup = createPopup;
-	}
-
-	function onShown(menu, popup) {
-	  popup.childNodes.forEach((menuItemNode, i) => {
-	    var item = menu.items[i];
-
-	    if (!item.disabled && item.visible) {
-	      menuItemNode.onclick = () => {
-	        item.click();
-	        popup.hidePopup();
-	      };
-
-	      showSubMenu(item.submenu, menuItemNode, popup);
-	    }
-	  });
-	}
-
-	function showMenu(evt, items) {
-	  if (items.length === 0) {
-	    return;
-	  }
-
-	  var menu = new Menu();
-	  items.filter(item => item.visible === undefined || item.visible === true).forEach(item => {
-	    var menuItem = new MenuItem(item);
-	    menuItem.submenu = createSubMenu(item.submenu);
-	    menu.append(menuItem);
-	  });
-
-	  if (isFirefoxPanel()) {
-	    menu.popup(evt.screenX, evt.screenY, { doc: window.parent.document });
-	    return;
-	  }
-
-	  menu.on("open", (_, popup) => onShown(menu, popup));
-	  menu.popup(evt.clientX, evt.clientY, { doc: document });
-	}
-
-	function createSubMenu(subItems) {
-	  if (subItems) {
-	    var subMenu = new Menu();
-	    subItems.forEach(subItem => {
-	      subMenu.append(new MenuItem(subItem));
-	    });
-	    return subMenu;
-	  }
-	  return null;
-	}
-
-	function showSubMenu(subMenu, menuItemNode, popup) {
-	  if (subMenu) {
-	    var subMenuNode = menuItemNode.querySelector("menupopup");
-
-	    var _popup$getBoundingCli = popup.getBoundingClientRect(),
-	        left = _popup$getBoundingCli.left,
-	        top = _popup$getBoundingCli.top,
-	        width = _popup$getBoundingCli.width;
-
-	    subMenuNode.style.setProperty("left", `${left + width}px`);
-	    subMenuNode.style.setProperty("top", `${top}px`);
-
-	    var subMenuItemNodes = menuItemNode.querySelector("menupopup:not(.landing-popup)").childNodes;
-	    subMenuItemNodes.forEach((subMenuItemNode, j) => {
-	      var subMenuItem = subMenu.items.filter(item => item.visible === undefined || item.visible === true)[j];
-	      if (!subMenuItem.disabled && subMenuItem.visible) {
-	        subMenuItemNode.onclick = () => {
-	          subMenuItem.click();
-	          popup.hidePopup();
-	        };
-	      }
-	    });
-	  }
-	}
-
-	function buildMenu(items) {
-	  return items.map(itm => {
-	    var hide = typeof itm.hidden === "function" ? itm.hidden() : itm.hidden;
-	    return hide ? null : itm.item;
-	  }).filter(itm => itm !== null);
-	}
-
-	module.exports = {
-	  showMenu,
-	  buildMenu
-	};
-
-/***/ },
+/* 966 */,
 /* 967 */
 /***/ function(module, exports, __webpack_require__) {
 
 	"use strict";
 
 	/* This Source Code Form is subject to the terms of the Mozilla Public
 	 * License, v. 2.0. If a copy of the MPL was not distributed with this
 	 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@@ -39011,22 +37886,17 @@ return /******/ (function(modules) { // 
 
 	  off(key, listener) {
 	    this.eventEmitter.off(key, listener);
 	  }
 	};
 	exports.KeyShortcuts = KeyShortcuts;
 
 /***/ },
-/* 973 */
-/***/ function(module, exports) {
-
-	// removed by extract-text-webpack-plugin
-
-/***/ },
+/* 973 */,
 /* 974 */,
 /* 975 */
 /***/ function(module, exports, __webpack_require__) {
 
 	var __WEBPACK_AMD_DEFINE_RESULT__;'use strict';
 
 	/* globals window, exports, define */
 
@@ -41546,16 +40416,47 @@ return /******/ (function(modules) { // 
 	   * @param aGrip Object
 	   *        The long string grip returned by the protocol.
 	   */
 	  threadLongString: function (aGrip) {
 	    return this._longString(aGrip, "_threadGrips");
 	  },
 
 	  /**
+	   * Get or create an ArrayBuffer client, checking the grip client cache if it
+	   * already exists.
+	   *
+	   * @param aGrip Object
+	   *        The ArrayBuffer grip returned by the protocol.
+	   * @param aGripCacheName String
+	   *        The property name of the grip client cache to check for existing
+	   *        clients in.
+	   */
+	  _arrayBuffer: function (aGrip, aGripCacheName) {
+	    if (aGrip.actor in this[aGripCacheName]) {
+	      return this[aGripCacheName][aGrip.actor];
+	    }
+
+	    var client = new ArrayBufferClient(this.client, aGrip);
+	    this[aGripCacheName][aGrip.actor] = client;
+	    return client;
+	  },
+
+	  /**
+	   * Return an instance of ArrayBufferClient for the given ArrayBuffer grip that
+	   * is scoped to the thread lifetime.
+	   *
+	   * @param aGrip Object
+	   *        The ArrayBuffer grip returned by the protocol.
+	   */
+	  threadArrayBuffer: function (aGrip) {
+	    return this._arrayBuffer(aGrip, "_threadGrips");
+	  },
+
+	  /**
 	   * Clear and invalidate all the grip clients from the given cache.
 	   *
 	   * @param aGripCacheName
 	   *        The property name of the grip cache we want to clear.
 	   */
 	  _clearObjectClients: function (aGripCacheName) {
 	    for (var id in this[aGripCacheName]) {
 	      this[aGripCacheName][id].valid = false;
@@ -42069,16 +40970,54 @@ return /******/ (function(modules) { // 
 	   *        The function called when we receive the property values.
 	   */
 	  all: DebuggerClient.requester({
 	    type: "all"
 	  }, {})
 	};
 
 	/**
+	 * A ArrayBufferClient provides a way to access ArrayBuffer from the
+	 * debugger server.
+	 *
+	 * @param aClient DebuggerC