Updating the Chromium reference build for Windows. The continuous
build at patch 41134 was used.

TEST=none
BUG=none


Review URL: http://codereview.chromium.org/853002

git-svn-id: http://src.chromium.org/svn/trunk/deps/reference_builds/chrome@41353 4ff67af0-8c30-449e-8e8b-ad334ec8d88c
diff --git a/avcodec-52.dll b/avcodec-52.dll
index c635c08..671ac2b 100755
--- a/avcodec-52.dll
+++ b/avcodec-52.dll
Binary files differ
diff --git a/avformat-52.dll b/avformat-52.dll
index 200a44b..85f8513 100755
--- a/avformat-52.dll
+++ b/avformat-52.dll
Binary files differ
diff --git a/avutil-50.dll b/avutil-50.dll
index 764f545..d24d904 100755
--- a/avutil-50.dll
+++ b/avutil-50.dll
Binary files differ
diff --git a/chrome.dll b/chrome.dll
index 1097546..2f01a89 100755
--- a/chrome.dll
+++ b/chrome.dll
Binary files differ
diff --git a/chrome.exe b/chrome.exe
index 60cde9c..32bf803 100755
--- a/chrome.exe
+++ b/chrome.exe
Binary files differ
diff --git a/chrome_dll.pdb b/chrome_dll.pdb
index 5470617..6363e54 100755
--- a/chrome_dll.pdb
+++ b/chrome_dll.pdb
Binary files differ
diff --git a/chrome_exe.pdb b/chrome_exe.pdb
index f02a6da..5cc5bc3 100755
--- a/chrome_exe.pdb
+++ b/chrome_exe.pdb
Binary files differ
diff --git a/crash_service.exe b/crash_service.exe
index 5a3c0b4..5036596 100755
--- a/crash_service.exe
+++ b/crash_service.exe
Binary files differ
diff --git a/locales/ar.dll b/locales/ar.dll
index c3007c7..42aaa3d 100755
--- a/locales/ar.dll
+++ b/locales/ar.dll
Binary files differ
diff --git a/locales/bg.dll b/locales/bg.dll
index 35eb19c..08b6c7b 100755
--- a/locales/bg.dll
+++ b/locales/bg.dll
Binary files differ
diff --git a/locales/bn.dll b/locales/bn.dll
index b54f6cd..8201a73 100755
--- a/locales/bn.dll
+++ b/locales/bn.dll
Binary files differ
diff --git a/locales/ca.dll b/locales/ca.dll
index 5d9ab1c..d584714 100755
--- a/locales/ca.dll
+++ b/locales/ca.dll
Binary files differ
diff --git a/locales/cs.dll b/locales/cs.dll
index 4e84915..6da467e 100755
--- a/locales/cs.dll
+++ b/locales/cs.dll
Binary files differ
diff --git a/locales/da.dll b/locales/da.dll
index 4ac28dd..de0f19b 100755
--- a/locales/da.dll
+++ b/locales/da.dll
Binary files differ
diff --git a/locales/de.dll b/locales/de.dll
index af6fa34..8ae39ef 100755
--- a/locales/de.dll
+++ b/locales/de.dll
Binary files differ
diff --git a/locales/el.dll b/locales/el.dll
index 5ade8fe..8f4f996 100755
--- a/locales/el.dll
+++ b/locales/el.dll
Binary files differ
diff --git a/locales/en-GB.dll b/locales/en-GB.dll
index 6f88f95..d25ba25 100755
--- a/locales/en-GB.dll
+++ b/locales/en-GB.dll
Binary files differ
diff --git a/locales/en-US.dll b/locales/en-US.dll
index c23755b..4d78b7e 100755
--- a/locales/en-US.dll
+++ b/locales/en-US.dll
Binary files differ
diff --git a/locales/es-419.dll b/locales/es-419.dll
index 370ec95..4f69134 100755
--- a/locales/es-419.dll
+++ b/locales/es-419.dll
Binary files differ
diff --git a/locales/es.dll b/locales/es.dll
index 563d091..3e41bc7 100755
--- a/locales/es.dll
+++ b/locales/es.dll
Binary files differ
diff --git a/locales/et.dll b/locales/et.dll
index 7b1589f..56696c2 100755
--- a/locales/et.dll
+++ b/locales/et.dll
Binary files differ
diff --git a/locales/fi.dll b/locales/fi.dll
index 543afa1..563ed98 100755
--- a/locales/fi.dll
+++ b/locales/fi.dll
Binary files differ
diff --git a/locales/fil.dll b/locales/fil.dll
index a8ae3a6..0abee28 100755
--- a/locales/fil.dll
+++ b/locales/fil.dll
Binary files differ
diff --git a/locales/fr.dll b/locales/fr.dll
index 30faeb6..36a91a9 100755
--- a/locales/fr.dll
+++ b/locales/fr.dll
Binary files differ
diff --git a/locales/gu.dll b/locales/gu.dll
index 007c4dd..382fafa 100755
--- a/locales/gu.dll
+++ b/locales/gu.dll
Binary files differ
diff --git a/locales/he.dll b/locales/he.dll
index 9270060..fe84d2d 100755
--- a/locales/he.dll
+++ b/locales/he.dll
Binary files differ
diff --git a/locales/hi.dll b/locales/hi.dll
index 13f8989..f6d348b 100755
--- a/locales/hi.dll
+++ b/locales/hi.dll
Binary files differ
diff --git a/locales/hr.dll b/locales/hr.dll
index b57606a..79171d0 100755
--- a/locales/hr.dll
+++ b/locales/hr.dll
Binary files differ
diff --git a/locales/hu.dll b/locales/hu.dll
index 84dd09f..741a822 100755
--- a/locales/hu.dll
+++ b/locales/hu.dll
Binary files differ
diff --git a/locales/id.dll b/locales/id.dll
index 707dff0..1f7c4fa 100755
--- a/locales/id.dll
+++ b/locales/id.dll
Binary files differ
diff --git a/locales/it.dll b/locales/it.dll
index 8c17ca2..a1181de 100755
--- a/locales/it.dll
+++ b/locales/it.dll
Binary files differ
diff --git a/locales/ja.dll b/locales/ja.dll
index 53e7437..0b84d6e 100755
--- a/locales/ja.dll
+++ b/locales/ja.dll
Binary files differ
diff --git a/locales/kn.dll b/locales/kn.dll
index af59ba4..23d19ed 100755
--- a/locales/kn.dll
+++ b/locales/kn.dll
Binary files differ
diff --git a/locales/ko.dll b/locales/ko.dll
index e1e0d6a..522d58c 100755
--- a/locales/ko.dll
+++ b/locales/ko.dll
Binary files differ
diff --git a/locales/lt.dll b/locales/lt.dll
index cdd98c7..ea19d66 100755
--- a/locales/lt.dll
+++ b/locales/lt.dll
Binary files differ
diff --git a/locales/lv.dll b/locales/lv.dll
index 09a6769..af78ad2 100755
--- a/locales/lv.dll
+++ b/locales/lv.dll
Binary files differ
diff --git a/locales/ml.dll b/locales/ml.dll
index ba699d5..4df6f70 100755
--- a/locales/ml.dll
+++ b/locales/ml.dll
Binary files differ
diff --git a/locales/mr.dll b/locales/mr.dll
index 187eddf..055c191 100755
--- a/locales/mr.dll
+++ b/locales/mr.dll
Binary files differ
diff --git a/locales/nb.dll b/locales/nb.dll
index cc66102..8216f26 100755
--- a/locales/nb.dll
+++ b/locales/nb.dll
Binary files differ
diff --git a/locales/nl.dll b/locales/nl.dll
index 43b050a..2adc017 100755
--- a/locales/nl.dll
+++ b/locales/nl.dll
Binary files differ
diff --git a/locales/or.dll b/locales/or.dll
index b06d834..022c123 100755
--- a/locales/or.dll
+++ b/locales/or.dll
Binary files differ
diff --git a/locales/pl.dll b/locales/pl.dll
index cae96b0..fd005f2 100755
--- a/locales/pl.dll
+++ b/locales/pl.dll
Binary files differ
diff --git a/locales/pt-BR.dll b/locales/pt-BR.dll
index 8b4d28e..5825376 100755
--- a/locales/pt-BR.dll
+++ b/locales/pt-BR.dll
Binary files differ
diff --git a/locales/pt-PT.dll b/locales/pt-PT.dll
index b9aa7c3..f8a9978 100755
--- a/locales/pt-PT.dll
+++ b/locales/pt-PT.dll
Binary files differ
diff --git a/locales/ro.dll b/locales/ro.dll
index 45699c4..b7182d9 100755
--- a/locales/ro.dll
+++ b/locales/ro.dll
Binary files differ
diff --git a/locales/ru.dll b/locales/ru.dll
index a3d5099..bae88ca 100755
--- a/locales/ru.dll
+++ b/locales/ru.dll
Binary files differ
diff --git a/locales/sk.dll b/locales/sk.dll
index 6e33584..6220c41 100755
--- a/locales/sk.dll
+++ b/locales/sk.dll
Binary files differ
diff --git a/locales/sl.dll b/locales/sl.dll
index d6807b9..ea11408 100755
--- a/locales/sl.dll
+++ b/locales/sl.dll
Binary files differ
diff --git a/locales/sr.dll b/locales/sr.dll
index df46c10..b68efc6 100755
--- a/locales/sr.dll
+++ b/locales/sr.dll
Binary files differ
diff --git a/locales/sv.dll b/locales/sv.dll
index b6e9d3c..eaa63c1 100755
--- a/locales/sv.dll
+++ b/locales/sv.dll
Binary files differ
diff --git a/locales/ta.dll b/locales/ta.dll
index 7a104db..526bc02 100755
--- a/locales/ta.dll
+++ b/locales/ta.dll
Binary files differ
diff --git a/locales/te.dll b/locales/te.dll
index 01d4114..ec34dd6 100755
--- a/locales/te.dll
+++ b/locales/te.dll
Binary files differ
diff --git a/locales/th.dll b/locales/th.dll
index 139971e..21d2c5b 100755
--- a/locales/th.dll
+++ b/locales/th.dll
Binary files differ
diff --git a/locales/tr.dll b/locales/tr.dll
index b64a2c8..0689bee 100755
--- a/locales/tr.dll
+++ b/locales/tr.dll
Binary files differ
diff --git a/locales/uk.dll b/locales/uk.dll
index e8478e7..f7abef0 100755
--- a/locales/uk.dll
+++ b/locales/uk.dll
Binary files differ
diff --git a/locales/vi.dll b/locales/vi.dll
index 1804b2f..b772a80 100755
--- a/locales/vi.dll
+++ b/locales/vi.dll
Binary files differ
diff --git a/locales/zh-CN.dll b/locales/zh-CN.dll
index af2b318..f05fdd8 100755
--- a/locales/zh-CN.dll
+++ b/locales/zh-CN.dll
Binary files differ
diff --git a/locales/zh-TW.dll b/locales/zh-TW.dll
index 9681572..2adae22 100755
--- a/locales/zh-TW.dll
+++ b/locales/zh-TW.dll
Binary files differ
diff --git a/mini_installer.pdb b/mini_installer.pdb
index 3f58d2f..7f7bf9c 100755
--- a/mini_installer.pdb
+++ b/mini_installer.pdb
Binary files differ
diff --git a/nacl64.dll b/nacl64.dll
new file mode 100644
index 0000000..19637db
--- /dev/null
+++ b/nacl64.dll
Binary files differ
diff --git a/nacl64.exe b/nacl64.exe
new file mode 100644
index 0000000..d975549
--- /dev/null
+++ b/nacl64.exe
Binary files differ
diff --git a/resources/bookmark_manager/css/bmm.css b/resources/bookmark_manager/css/bmm.css
new file mode 100644
index 0000000..f3cbdfa
--- /dev/null
+++ b/resources/bookmark_manager/css/bmm.css
@@ -0,0 +1,266 @@
+/*
+Copyright (c) 2010 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+*/
+html, body {
+  margin: 0;
+  width: 100%;
+  height: 100%;
+  cursor: default;
+}
+
+list {
+  display: block;
+  overflow-x: hidden;
+  overflow-y: visible; /* let the container do the scrolling */
+}
+
+list > * {
+  text-decoration: none;
+  padding: 5px;
+}
+
+list > * > * {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  display: block;
+  color: black;
+  width: 100%;
+  -webkit-box-sizing: border-box;
+  background: 0 50% no-repeat;
+  -webkit-padding-start: 20px;
+}
+
+list > * > * > span {
+  -webkit-transition: all .15s;
+  text-decoration: none;
+  color: #000;
+  cursor: pointer;
+  opacity: .7;
+}
+
+list > * > :first-child {
+  font-weight: bold;
+  font-size: 110%;
+}
+
+list > * > :last-child {
+  overflow: hidden;
+}
+
+list > * > * > .folder {
+  background-image: url("../images/folder_closed.png");
+  background-repeat: no-repeat;
+  background-position: 0% 50%;
+  display: inline-block;
+  -webkit-padding-start: 18px;
+}
+
+html[dir=rtl] list > * > * > .folder {
+  background-image: url("../images/folder_closed_rtl.png");
+  background-position: 100% 50%;
+}
+
+html[os=mac] list > * > * > .folder {
+  background-image: url("../images/bookmark_bar_folder_mac.png");
+}
+
+list > * > * > :hover {
+  text-decoration: underline;
+  color: blue;
+  opacity: 1;
+}
+
+list > * > * > :active {
+  color: -webkit-activelink;
+}
+
+html[dir=rtl] list .label {
+  background-position: 100% 50%;
+}
+
+list > .folder > .label {
+  background-image: url("../images/folder_closed.png");
+}
+
+/* We need to ensure that even empty labels take up space */
+list > * > .label:empty:after,
+list > * > .url:empty:after {
+  content: " ";
+  white-space: pre;
+}
+
+list > .folder > .url:empty:after {
+  content: "";
+}
+
+/*
+/* Edit mode
+*/
+
+list .label input,
+list .url input {
+  /* Do not inherit the line-height */
+  font-family: inherit;
+  font-size: inherit;
+  font-weight: inherit;
+  color: black;
+  background: white;
+  border: 1px solid black;
+  margin: -2px -8px -2px -3px;
+  padding: 1px 7px 1px 1px;
+  outline: none;
+  text-decoration: none;
+}
+
+html[dir=rtl] list .label input,
+html[dir=rtl] list .url input {
+  margin: -2px -3px -2px -8px;
+  padding: 1px 1px 1px 7px;
+}
+
+list [editing] .label,
+list [editing] .url,
+list [editing] > * {
+  overflow: visible;
+  opacity: 1;
+}
+
+list [editing] .url {
+  text-decoration: none;
+  color: inherit;
+}
+
+list .url form {
+  display: inline;
+}
+
+list .url > form > input {
+  -webkit-transition: color .15s, background-color .15s;
+}
+
+list .url > form > :invalid {
+  background: #fdd;
+  color: black;
+}
+
+/* end editing */
+
+html[dir=rtl] list > .folder > .label {
+  background-image: url("../images/folder_closed_rtl.png");
+}
+
+html[os=mac] list > .folder > .label {
+  background-image: url("../images/bookmark_bar_folder_mac.png");
+}
+
+html[os=mac] .tree-label {
+  background-image: url("../images/bookmark_bar_folder_mac.png");
+}
+
+html[os=mac] .tree-row[selected] > .tree-label {
+  background-image: url("../images/bookmark_bar_folder_mac.png");
+}
+
+.main {
+  position: absolute;
+  top: 75px;
+  left: 0;
+  right: 0;
+  bottom: 0;
+}
+
+#tree-container {
+  position: absolute;
+  left: 0;
+  width: 200px;
+  top: 0;
+  bottom: 0;
+  overflow: auto;
+  -webkit-box-sizing: border-box;
+  padding: 0px 5px 5px 5px;
+}
+
+#tree {
+  min-width: 100%;
+  overflow: visible; /* let the container do the scrolling */
+  display: inline-block;
+}
+
+#list {
+  position: absolute;
+  left: 200px;
+  right: 0;
+  top: 0;
+  bottom: 0;
+  -webkit-box-sizing: border-box;
+  padding: 0 5px 5px 5px;
+}
+
+.logo {
+  -webkit-appearance: none;
+  border: 0;
+  background: transparent;
+  background: 50% 50% no-repeat url("../images/bookmarks_section.png");
+  width: 67px;
+  height: 67px;
+  cursor: pointer;
+  vertical-align: bottom;
+  margin: 5px;
+}
+
+html[dir=rtl] #tree-container {
+  left: auto;
+  right: 0;
+}
+
+html[dir=rtl] #list {
+  left: 0;
+  right: 200px;
+}
+
+.header > div {
+  display: inline-block;
+  margin: 5px;
+}
+
+#drop-overlay {
+  position: absolute;
+  display: none;
+  pointer-events: none;
+  border: 1px solid hsl(214, 91%, 85%);;
+  -webkit-border-radius: 3px;
+  -webkit-box-sizing: border-box;
+  background-color: hsla(214, 91%, 85%, .5);
+  overflow: hidden;
+  z-index: -1;
+}
+
+#drop-overlay.line {
+  border: 3px solid black;
+  border-top-color: transparent;
+  border-bottom-color: transparent;
+  background-color: black;
+  background-clip: padding-box;
+  height: 8px;
+  -webkit-border-radius: 0;
+  z-index: 10;
+}
+
+.toolbar button {
+  -webkit-appearance: none;
+  background: transparent;
+  border: 0;
+  font: inherit;
+  padding: 0;
+  background: -webkit-canvas(drop-down-arrow) 100% 50% no-repeat;
+  padding-right: 9px;
+}
+
+html[dir=rtl] .toolbar button {
+  background-position: 0% 50%;
+  padding-right: 0;
+  padding-left: 9px;
+}
diff --git a/resources/bookmark_manager/css/bmm.css.js b/resources/bookmark_manager/css/bmm.css.js
new file mode 100644
index 0000000..3ea295f
--- /dev/null
+++ b/resources/bookmark_manager/css/bmm.css.js
@@ -0,0 +1,17 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Create the drop down arrow for the drop down buttons.
+(function() {
+  var ctx = document.getCSSCanvasContext('2d', 'drop-down-arrow', 9, 4);
+  ctx.fillStyle = '#000';
+  ctx.translate(1.5, .5);
+  ctx.beginPath();
+  ctx.moveTo(0, 0);
+  ctx.lineTo(6, 0);
+  ctx.lineTo(3, 3);
+  ctx.closePath();
+  ctx.fill();
+  ctx.stroke();
+})();
diff --git a/resources/bookmark_manager/css/list.css b/resources/bookmark_manager/css/list.css
new file mode 100644
index 0000000..e148337
--- /dev/null
+++ b/resources/bookmark_manager/css/list.css
@@ -0,0 +1,60 @@
+
+list {
+  overflow: auto;
+  outline: none;
+}
+
+list > * {
+  -webkit-user-select: none;
+  border: 1px solid rgba(255,255,255,0); /* transparent white */
+  background-color: rgba(255,255,255,0);
+  -webkit-border-radius: 2px;
+  padding: 0px 3px;
+  line-height: 20px;
+  white-space: nowrap;
+  cursor: default;
+  -webkit-transition: all .12s;
+  position: relative; /* to allow overlap */
+  display: block;
+}
+
+list > [lead] {
+  border-color: transparent;
+}
+
+list:focus > [lead] {
+  border-color: hsl(214, 91%, 65%);
+  z-index: 2;
+}
+
+list > [anchor] {
+
+}
+
+list > :hover {
+  border-color: hsl(214, 91%, 85%);
+  z-index: 1;
+  background-color: hsl(214,91%,97%);
+}
+
+list > :hover,
+list > [selected] {
+  background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(255,255,255,0.8)), to(rgba(255,255,255,0)));
+}
+
+list > [selected] {
+  border-color: hsl(0,0%,85%);
+  background-color: hsl(0,0%,90%);
+  z-index: 2;
+}
+
+list:focus > [selected] {
+  background-color: hsl(214,91%,89%);
+  border-color: hsl(214, 91%, 65%);
+}
+
+list:focus > [lead][selected],
+list > [selected]:hover {
+  background-color: hsl(214,91%,87%);
+  border-color: hsl(214, 91%, 65%);
+}
diff --git a/resources/bookmark_manager/css/menu.css b/resources/bookmark_manager/css/menu.css
new file mode 100644
index 0000000..b7e0942
--- /dev/null
+++ b/resources/bookmark_manager/css/menu.css
@@ -0,0 +1,47 @@
+
+menu {
+  display: none;
+  position: absolute;
+  border: 1px solid #999;
+  -webkit-box-shadow: 2px 2px 3px hsla(0, 0%, 0%, .3);
+  color: black;
+  background-color: hsla(213, 0%, 100%, .95);
+  left: 0;
+  white-space: nowrap;
+  z-index: 2;
+  padding: 1px;
+  margin: 0;
+  cursor: default;
+}
+
+menu > * {
+  display: block;
+  margin: 0;
+  width: 100%;
+  text-align: start;
+}
+
+menu > :not(hr) {
+  -webkit-appearance: none;
+  background: transparent;
+  font: inherit;
+  border: 0;
+  padding: 3px 8px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+menu > hr {
+  border: 0;
+  border-top: 1px solid rgb(153, 153, 153);
+  margin: 2px 0;
+}
+
+menu > [hidden] {
+  display: none;
+}
+
+menu > [selected] {
+  background-color: hsl(213, 66%, 57%);
+  color: white;
+}
diff --git a/resources/bookmark_manager/css/tree.css b/resources/bookmark_manager/css/tree.css
new file mode 100644
index 0000000..d1825e4
--- /dev/null
+++ b/resources/bookmark_manager/css/tree.css
@@ -0,0 +1,164 @@
+tree {
+  outline: none;
+  overflow: auto;
+  display: block;
+}
+
+.tree-item > .tree-row {
+  color: black;
+  -webkit-user-select: none;
+  border: 1px solid rgba(255,255,255,0); /* transparent white */
+  background-color: rgba(255,255,255,0);
+  -webkit-border-radius: 2px;
+  padding: 0px 3px;
+  line-height: 20px;
+  white-space: nowrap;
+  cursor: default;
+  position: relative;
+}
+
+.expand-icon {
+  width: 11px;
+  height: 16px;
+  display: inline-block;
+  vertical-align: top;
+  position: relative;
+  top: 2px;
+  background-image: -webkit-canvas(triangle-empty);
+  background-position: 50% 50%;
+  background-repeat: no-repeat;
+  -webkit-transition: all .15s, opacity 1.5s;
+  opacity: 0;
+}
+
+html[dir=rtl] .expand-icon {
+  -webkit-transform: scale(-1, 1);
+}
+
+tree:hover .expand-icon,
+tree:focus .expand-icon {
+  opacity: 1;
+  -webkit-transition: all .15s, opacity .5s;
+}
+
+.tree-item[expanded] > .tree-row > .expand-icon {
+  background-image: -webkit-canvas(triangle-filled);
+  -webkit-transform: translate(0, 3px) rotate(45deg);
+}
+
+html[dir=rtl] .tree-item[expanded] > .tree-row > .expand-icon {
+  -webkit-transform: scale(-1, 1) translate(0, 3px) rotate(45deg); /* flip */
+}
+
+.tree-item > .tree-row > .expand-icon:hover {
+  background-image: -webkit-canvas(triangle-hover);
+}
+
+.tree-row .expand-icon {
+  visibility: hidden;
+}
+
+.tree-row[may-have-children] .expand-icon {
+  visibility: visible;
+}
+
+.tree-row[has-children=false] .expand-icon {
+  visibility: hidden;
+}
+
+.tree-item > .tree-row:hover {
+  border-color: hsl(214, 91%, 85%);
+  z-index: 1;
+  background-color: hsl(214, 91%, 97%);
+}
+
+/*
+  WebKit has a bug with attribute selectors so we apply selected to the tree row
+  as well.
+
+  https://bugs.webkit.org/show_bug.cgi?id=12519
+
+*/
+.tree-row[selected]:hover,
+.tree-row[selected] {
+  background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(255,255,255,0.8)), to(rgba(255,255,255,0)));
+}
+
+.tree-row[selected] {
+  border-color: hsl(0,0%,85%);
+  background-color: hsl(0, 0%, 90%);
+  z-index: 2;
+}
+
+:focus .tree-row[selected] {
+  background-color: hsl(214, 91%, 89%);
+  border-color: #7da2ce;
+}
+
+.tree-children[expanded] {
+  display: block;
+}
+
+.tree-children {
+  display: none;
+}
+
+.tree-item > .tree-row > * {
+  display: inline-block;
+  -webkit-box-sizing: border-box;
+}
+
+.tree-label {
+  -webkit-padding-start: 20px;
+  background-repeat: no-repeat;
+  background-position: 0 50%;
+  background-image: url("../images/folder_closed.png");
+}
+
+/* We need to ensure that even empty labels take up space */
+.tree-label:empty:after {
+  content: " ";
+  white-space: pre;
+}
+
+.tree-rename > .tree-row > .tree-label {
+  -webkit-user-select: auto;
+  -webkit-user-modify: read-write-plaintext-only;
+  background: white;
+  color: black;
+  outline: 1px solid black;
+}
+
+html[dir=rtl] .tree-label {
+  background-position: 100% 50%;
+}
+
+.tree-row[selected] > .tree-label {
+  background-image: url("../images/folder_open.png");
+}
+
+html[dir='rtl'] .tree-label {
+  background-image: url("../images/folder_closed_rtl.png");
+}
+
+html[dir='rtl'] .tree-row[selected] > .tree-label {
+  background-image: url("../images/folder_open_rtl.png");
+}
+
+.tree-item[editing] input {
+  /* Do not inherit the line-height */
+  font-family: inherit;
+  font-size: inherit;
+  font-weight: inherit;
+  border: 1px solid black;
+  color: black;
+  background: white;
+  margin: -2px -8px -2px -3px;
+  padding: 1px 7px 1px 1px;
+  outline: none;
+}
+
+html[dir=rtl] .tree-item[editing] input {
+  margin: -2px -3px -2px -8px;
+  padding: 1px 1px 1px 7px;
+}
diff --git a/resources/bookmark_manager/css/tree.css.js b/resources/bookmark_manager/css/tree.css.js
new file mode 100644
index 0000000..74fb06d
--- /dev/null
+++ b/resources/bookmark_manager/css/tree.css.js
@@ -0,0 +1,79 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function() {
+  var a = 7;
+  var a2 = a / 2;
+  var ctx = document.getCSSCanvasContext('2d', 'triangle-filled', a2 + 2, a + 1);
+
+  ctx.fillStyle = '#000';
+  ctx.translate(.5, .5);
+  ctx.beginPath();
+  ctx.moveTo(0, 0);
+  ctx.lineTo(0, a);
+  ctx.lineTo(a2, a2);
+  ctx.closePath();
+  ctx.fill();
+  ctx.stroke();
+
+  var ctx = document.getCSSCanvasContext('2d', 'triangle-empty', a2 + 2, a + 1);
+
+  ctx.strokeStyle = '#999';
+  ctx.lineWidth  = 1.2;
+  ctx.translate(.5, .5);
+  ctx.fillStyle = '#000';
+  ctx.beginPath();
+
+
+  ctx.moveTo(0, 0);
+  ctx.lineTo(0, a);
+  ctx.lineTo(a2, a2);
+  ctx.closePath();
+  ctx.stroke();
+
+  var ctx = document.getCSSCanvasContext('2d', 'triangle-hover', a2 + 2 + 4, a + 1 + 4);
+
+  ctx.shadowColor = 'hsl(214,91%,89%)'
+  ctx.shadowBlur = 3;
+  ctx.shadowOffsetX = 1;
+  ctx.shadowOffsetY = 0;
+
+  ctx.strokeStyle = 'hsl(214,91%,79%)';
+  ctx.lineWidth  = 1.2;
+  ctx.translate(.5 + 2, .5 + 2);
+  ctx.fillStyle = '#000';
+  ctx.beginPath();
+
+  ctx.moveTo(0, 0);
+  ctx.lineTo(0, a);
+  ctx.lineTo(a2, a2);
+  ctx.closePath();
+  ctx.stroke();
+})();
+
+// We need to generate CSS for the indentation.
+(function() {
+  // We need to generat the following
+  //.tree-item > * > .tree-item > .tree-row {
+  //  -webkit-padding-start: 20px;
+  //}
+
+  //.tree-item > * .tree-item > * .tree-item > * > .tree-item > .tree-row {
+  //  -webkit-padding-start: 60px;
+  //}
+  var style = document.createElement('style');
+
+  function repeat(s, n) {
+    return Array(n + 1).join(s);
+  }
+
+  var s = '';
+  for (var i = 1; i < 10; i++) {
+    s += repeat('.tree-item > * ', i) + '.tree-item > .tree-row {\n' +
+         '-webkit-padding-start:' + i * 20 + 'px\n' +
+         '}\n';
+  }
+  style.textContent = s;
+  document.documentElement.firstElementChild.appendChild(style);
+})();
diff --git a/resources/bookmark_manager/images/bookmark_bar_folder_mac.png b/resources/bookmark_manager/images/bookmark_bar_folder_mac.png
new file mode 100644
index 0000000..ec5d21f
--- /dev/null
+++ b/resources/bookmark_manager/images/bookmark_bar_folder_mac.png
Binary files differ
diff --git a/resources/bookmark_manager/images/bookmark_manager_recent.png b/resources/bookmark_manager/images/bookmark_manager_recent.png
new file mode 100644
index 0000000..9740e90
--- /dev/null
+++ b/resources/bookmark_manager/images/bookmark_manager_recent.png
Binary files differ
diff --git a/resources/bookmark_manager/images/bookmark_manager_search.png b/resources/bookmark_manager/images/bookmark_manager_search.png
new file mode 100644
index 0000000..76abc27
--- /dev/null
+++ b/resources/bookmark_manager/images/bookmark_manager_search.png
Binary files differ
diff --git a/resources/bookmark_manager/images/bookmarks_favicon.png b/resources/bookmark_manager/images/bookmarks_favicon.png
new file mode 100644
index 0000000..4da0edc
--- /dev/null
+++ b/resources/bookmark_manager/images/bookmarks_favicon.png
Binary files differ
diff --git a/resources/bookmark_manager/images/bookmarks_section.png b/resources/bookmark_manager/images/bookmarks_section.png
new file mode 100644
index 0000000..1633f68
--- /dev/null
+++ b/resources/bookmark_manager/images/bookmarks_section.png
Binary files differ
diff --git a/resources/bookmark_manager/images/folder_closed.png b/resources/bookmark_manager/images/folder_closed.png
new file mode 100644
index 0000000..746fab9
--- /dev/null
+++ b/resources/bookmark_manager/images/folder_closed.png
Binary files differ
diff --git a/resources/bookmark_manager/images/folder_closed_rtl.png b/resources/bookmark_manager/images/folder_closed_rtl.png
new file mode 100644
index 0000000..dbd0b0a
--- /dev/null
+++ b/resources/bookmark_manager/images/folder_closed_rtl.png
Binary files differ
diff --git a/resources/bookmark_manager/images/folder_open.png b/resources/bookmark_manager/images/folder_open.png
new file mode 100644
index 0000000..3276810
--- /dev/null
+++ b/resources/bookmark_manager/images/folder_open.png
Binary files differ
diff --git a/resources/bookmark_manager/images/folder_open_rtl.png b/resources/bookmark_manager/images/folder_open_rtl.png
new file mode 100644
index 0000000..9ba7069
--- /dev/null
+++ b/resources/bookmark_manager/images/folder_open_rtl.png
Binary files differ
diff --git a/resources/bookmark_manager/js/bmm.js b/resources/bookmark_manager/js/bmm.js
new file mode 100644
index 0000000..73cefa6
--- /dev/null
+++ b/resources/bookmark_manager/js/bmm.js
@@ -0,0 +1,98 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('bmm', function() {
+  const TreeIterator = bmm.TreeIterator;
+  const Promise = cr.Promise;
+
+  /**
+   * Whether a node contains another node.
+   * @param {!BookmarkTreeNode} parent
+   * @param {!BookmarkTreeNode} descendant
+   * @return {boolean} Whether the parent contains the descendant.
+   */
+  function contains(parent, descendant) {
+    if (descendant.parentId == parent.id)
+      return true;
+    // the bmm.treeLookup contains all folders
+    var parentTreeItem = bmm.treeLookup[descendant.parentId];
+    if (!parentTreeItem || !parentTreeItem.bookmarkNode)
+      return false;
+    return this.contains(parent, parentTreeItem.bookmarkNode);
+  }
+
+  /**
+   * @param {!BookmarkTreeNode} node The node to test.
+   * @return {boolean} Whether a bookmark node is a folder.
+   */
+  function isFolder(node) {
+    return !('url' in node);
+  }
+
+  var loadingPromise;
+
+  /**
+   * Loads the entire bookmark tree and returns a {@code cr.Promise} that will
+   * be fulfilled when done. This reuses multiple loads so that we never load
+   * more than one tree at the same time.
+   * @return {!cr.Promise} The future promise for the load.
+   */
+  function loadTree() {
+    var p = new Promise;
+    if (!loadingPromise) {
+      loadingPromise = new Promise;
+      chrome.bookmarks.getTree(function(nodes) {
+        loadingPromise.value = nodes[0];
+        loadingPromise = null;
+      });
+    }
+    loadingPromise.addListener(function(n) {
+      p.value = n;
+    });
+    return p;
+  }
+
+  /**
+   * Helper function for {@code loadSubtree}. This does an in order search of
+   * the tree.
+   * @param {!BookmarkTreeNode} node The node to start searching at.
+   * @param {string} id The ID of the node to find.
+   * @return {BookmarkTreeNode} The found node or null if not found.
+   */
+  function findNode(node, id) {
+    var it = new TreeIterator(node);
+    var n;
+    while (it.moveNext()) {
+      n = it.current;
+      if (n.id == id)
+        return n;
+    }
+    return null;
+  }
+
+  /**
+   * Loads a subtree of the bookmark tree and returns a {@code cr.Promise} that
+   * will be fulfilled when done. This reuses multiple loads so that we never
+   * load more than one tree at the same time. (This actually loads the entire
+   * tree but it will only return the relevant subtree in the value of the
+   * future promise.)
+   * @return {!cr.Promise} The future promise for the load.
+   */
+  function loadSubtree(id) {
+    var p = new Promise;
+    var lp = loadTree();
+    lp.addListener(function(tree) {
+      var node = findNode(tree, id);
+      p.value = node || Error('Failed to load subtree ' + id);
+    });
+    return p;
+  }
+
+  return {
+    contains: contains,
+    isFolder: isFolder,
+    loadSubtree: loadSubtree,
+    loadTree: loadTree
+  };
+});
diff --git a/resources/bookmark_manager/js/bmm/bookmarklist.js b/resources/bookmark_manager/js/bmm/bookmarklist.js
new file mode 100644
index 0000000..f244936
--- /dev/null
+++ b/resources/bookmark_manager/js/bmm/bookmarklist.js
@@ -0,0 +1,420 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+cr.define('bmm', function() {
+  // require cr.ui.define
+  // require cr.ui.limitInputWidth.
+  // require cr.ui.contextMenuHandler
+  const List = cr.ui.List;
+  const ListItem = cr.ui.ListItem;
+
+  var listLookup = {};
+
+  /**
+   * Removes all children and appends a new child.
+   * @param {!Node} parent The node to remove all children from.
+   * @param {!Node} newChild The new child to append.
+   */
+  function replaceAllChildren(parent, newChild) {
+    var n;
+    while ((n = parent.lastChild)) {
+      parent.removeChild(n);
+    }
+    parent.appendChild(newChild);
+  }
+
+  /**
+   * Creates a new bookmark list.
+   * @param {Object=} opt_propertyBag Optional properties.
+   * @constructor
+   * @extends {HTMLButtonElement}
+   */
+  var BookmarkList = cr.ui.define('list');
+
+  BookmarkList.prototype = {
+    __proto__: List.prototype,
+
+    decorate: function() {
+      List.prototype.decorate.call(this);
+      this.addEventListener('click', this.handleClick_);
+    },
+
+    parentId_: '',
+    get parentId() {
+      return this.parentId_;
+    },
+    set parentId(parentId) {
+      if (this.parentId_ == parentId)
+        return;
+
+      var oldParentId = this.parentId_;
+      this.parentId_ = parentId;
+
+      var callback = cr.bind(this.handleBookmarkCallback, this);
+
+      if (!parentId) {
+        callback([]);
+      } else if (/^q=/.test(parentId)) {
+        chrome.bookmarks.search(parentId.slice(2), callback);
+      } else if (parentId == 'recent') {
+        chrome.bookmarks.getRecent(50, callback);
+      } else {
+        chrome.bookmarks.getChildren(parentId, callback);
+      }
+
+      cr.dispatchPropertyChange(this, 'parentId', parentId, oldParentId);
+    },
+
+    handleBookmarkCallback: function(items) {
+      if (!items) {
+        // Failed to load bookmarks. Most likely due to the bookmark beeing
+        // removed.
+        cr.dispatchSimpleEvent(this, 'invalidId');
+        return;
+      }
+      // Remove all fields without recreating the object since other code
+      // references it.
+      for (var id in listLookup){
+        delete listLookup[id];
+      }
+      this.clear();
+      var showFolder = this.showFolder();
+      items.forEach(function(item) {
+        var li = createListItem(item, showFolder);
+        this.add(li);
+      }, this);
+      cr.dispatchSimpleEvent(this, 'load');
+    },
+
+    /**
+     * The bookmark node that the list is currently displaying. If we are currently
+     * displaying recent or search this returns null.
+     * @type {BookmarkTreeNode}
+     */
+    get bookmarkNode() {
+      if (this.isSearch() || this.isRecent())
+        return null;
+      var treeItem = bmm.treeLookup[this.parentId];
+      return treeItem && treeItem.bookmarkNode;
+    },
+
+    showFolder: function() {
+      return this.isSearch() || this.isRecent();
+    },
+
+    isSearch: function() {
+      return this.parentId_[0] == 'q';
+    },
+
+    isRecent: function() {
+      return this.parentId_ == 'recent';
+    },
+
+    /**
+     * Handles the clicks on the list so that we can check if the user clicked
+     * on a link or an folder.
+     * @private
+     * @param {Event} e The click event object.
+     */
+    handleClick_: function(e) {
+
+      var el = e.target;
+      if (el.href) {
+        var event = this.ownerDocument.createEvent('Event');
+        event.initEvent('urlClicked', true, false);
+        event.url = el.href;
+        event.kind = e.shiftKey ? 'window' : e.button == 1 ? 'tab' : 'self';
+        this.dispatchEvent(event);
+      }
+    },
+
+    // Bookmark model update callbacks
+    handleBookmarkChanged: function(id, changeInfo) {
+      var listItem = listLookup[id];
+      if (listItem) {
+        listItem.bookmarkNode.title = changeInfo.title;
+        if ('url' in changeInfo)
+          listItem.bookmarkNode.url = changeInfo['url'];
+        updateListItem(listItem, listItem.bookmarkNode, list.showFolder());
+      }
+    },
+
+    handleChildrenReordered: function(id, reorderInfo) {
+      if (this.parentId == id) {
+        var self = this;
+        reorderInfo.childIds.forEach(function(id, i) {
+          var li = listLookup[id]
+          self.addAt(li, i);
+          // At this point we do not read the index from the bookmark node so we
+          // do not need to update it.
+          li.bookmarkNode.index = i;
+        });
+      }
+    },
+
+    handleCreated: function(id, bookmarkNode) {
+      if (this.parentId == bookmarkNode.parentId) {
+        var li = createListItem(bookmarkNode, false);
+        this.addAt(li, bookmarkNode.index);
+      }
+    },
+
+    handleMoved: function(id, moveInfo) {
+      if (moveInfo.parentId == this.parentId ||
+          moveInfo.oldParentId == this.parentId) {
+
+        if (moveInfo.oldParentId == moveInfo.parentId) {
+          var listItem = listLookup[id];
+          if (listItem) {
+            this.remove(listItem);
+            this.addAt(listItem, moveInfo.index);
+          }
+        } else {
+          if (moveInfo.oldParentId == this.parentId) {
+            var listItem = listLookup[id];
+            if (listItem) {
+              this.remove(listItem);
+              delete listLookup[id];
+            }
+          }
+
+          if (moveInfo.parentId == list.parentId) {
+            var self = this;
+            chrome.bookmarks.get(id, function(bookmarkNodes) {
+              var bookmarkNode = bookmarkNodes[0];
+              var li = createListItem(bookmarkNode, false);
+              self.addAt(li, bookmarkNode.index);
+            });
+          }
+        }
+      }
+    },
+
+    handleRemoved: function(id, removeInfo) {
+      var listItem = listLookup[id];
+      if (listItem) {
+        this.remove(listItem);
+        delete listLookup[id];
+      }
+    }
+  };
+
+  /**
+   * The contextMenu property.
+   * @type {cr.ui.Menu}
+   */
+  cr.ui.contextMenuHandler.addContextMenuProperty(BookmarkList);
+
+  /**
+   * Creates a new bookmark list item.
+   * @param {Object=} opt_propertyBag Optional properties.
+   * @constructor
+   * @extends {cr.ui.ListItem}
+   */
+  var BookmarkListItem = cr.ui.define('li');
+
+  BookmarkListItem.prototype = {
+    __proto__: ListItem.prototype,
+    /**
+     * Whether the user is currently able to edit the list item.
+     * @type {boolean}
+     */
+    get editing() {
+      return this.hasAttribute('editing');
+    },
+    set editing(editing) {
+      var oldEditing = this.editing;
+      if (oldEditing == editing)
+        return;
+
+      var url = this.bookmarkNode.url;
+      var title = this.bookmarkNode.title;
+      var isFolder = bmm.isFolder(this.bookmarkNode);
+      var listItem = this;
+      var labelEl = this.firstChild;
+      var urlEl = this.querySelector('.url');
+      var labelInput, urlInput;
+
+      // Handles enter and escape which trigger reset and commit respectively.
+      function handleKeydown(e) {
+        // Make sure that the tree does not handle the key.
+        e.stopPropagation();
+
+        // Calling list.focus blurs the input which will stop editing the list
+        // item.
+        switch (e.keyIdentifier) {
+          case 'U+001B':  // Esc
+            labelInput.value = title;
+            if (!isFolder)
+              urlInput.value = url;
+            // fall through
+            cr.dispatchSimpleEvent(listItem, 'canceledit', true);
+          case 'Enter':
+            if (listItem.parentNode)
+              listItem.parentNode.focus();
+        }
+      }
+
+      function handleBlur(e) {
+        // When the blur event happens we do not know who is getting focus so we
+        // delay this a bit since we want to know if the other input got focus
+        // before deciding if we should exit edit mode.
+        var doc = e.target.ownerDocument;
+        window.setTimeout(function() {
+          var activeElement = doc.activeElement;
+          if (activeElement != urlInput && activeElement != labelInput) {
+            listItem.editing = false;
+          }
+        }, 50);
+      }
+
+      var doc = this.ownerDocument;
+      if (editing) {
+        this.setAttribute('editing', '');
+        this.draggable = false;
+
+        labelInput = doc.createElement('input');
+        labelInput.placeholder =
+            localStrings.getString('name_input_placeholder');
+        replaceAllChildren(labelEl, labelInput);
+        labelInput.value = title;
+
+        if (!isFolder) {
+          // To use :invalid we need to put the input inside a form
+          // https://bugs.webkit.org/show_bug.cgi?id=34733
+          var form = doc.createElement('form');
+          urlInput = doc.createElement('input');
+          urlInput.type = 'url';
+          urlInput.required = true;
+          urlInput.placeholder =
+              localStrings.getString('url_input_placeholder');
+
+          // We also need a name for the input for the CSS to work.
+          urlInput.name = '-url-input-' + cr.createUid();
+          form.appendChild(urlInput);
+          replaceAllChildren(urlEl, form);
+          urlInput.value = url;
+        }
+
+        function stopPropagation(e) {
+          e.stopPropagation();
+        }
+
+        var eventsToStop = ['mousedown', 'mouseup', 'contextmenu', 'dblclick'];
+        eventsToStop.forEach(function(type) {
+          labelInput.addEventListener(type, stopPropagation);
+        });
+        labelInput.addEventListener('keydown', handleKeydown);
+        labelInput.addEventListener('blur', handleBlur);
+        cr.ui.limitInputWidth(labelInput, this, 200);
+        labelInput.focus();
+        labelInput.select();
+
+        if (!isFolder) {
+          eventsToStop.forEach(function(type) {
+            urlInput.addEventListener(type, stopPropagation);
+          });
+          urlInput.addEventListener('keydown', handleKeydown);
+          urlInput.addEventListener('blur', handleBlur);
+          cr.ui.limitInputWidth(urlInput, this, 200);
+        }
+
+      } else {
+
+        // Check that we have a valid URL and if not we do not change the
+        // editing mode.
+        if (!isFolder) {
+          var urlInput = this.querySelector('.url input');
+          var newUrl = urlInput.value;
+          if (!urlInput.validity.valid) {
+            // WebKit does not do URL fix up so we manually test if prepending
+            // 'http://' would make the URL valid.
+            // https://bugs.webkit.org/show_bug.cgi?id=29235
+            urlInput.value = 'http://' + newUrl;
+            if (!urlInput.validity.valid) {
+              // still invalid
+              urlInput.value = newUrl;
+
+              // In case the item was removed before getting here we should
+              // not alert.
+              if (listItem.parentNode) {
+                alert(localStrings.getString('invalid_url'));
+              }
+              urlInput.focus();
+              urlInput.select();
+              return;
+            }
+            newUrl = 'http://' + newUrl;
+          }
+          urlEl.textContent = this.bookmarkNode.url = newUrl;
+        }
+
+        this.removeAttribute('editing');
+        this.draggable = true;
+
+        labelInput = this.querySelector('.label input');
+        var newLabel = labelInput.value;
+        labelEl.textContent = this.bookmarkNode.title = newLabel;
+
+        if (isFolder) {
+          if (newLabel != title) {
+            cr.dispatchSimpleEvent(this, 'rename', true);
+          }
+        } else if (newLabel != title || newUrl != url) {
+          cr.dispatchSimpleEvent(this, 'edit', true);
+        }
+      }
+    }
+  };
+
+  function createListItem(bookmarkNode, showFolder) {
+    var li = listItemPromo.cloneNode(true);
+    BookmarkListItem.decorate(li);
+    updateListItem(li, bookmarkNode, showFolder);
+    li.bookmarkId = bookmarkNode.id;
+    li.bookmarkNode = bookmarkNode;
+    li.draggable = true;
+    listLookup[bookmarkNode.id] = li;
+    return li;
+  }
+
+  function updateListItem(el, bookmarkNode, showFolder) {
+    var labelEl = el.firstChild;
+    labelEl.textContent = bookmarkNode.title;
+    if (!bmm.isFolder(bookmarkNode)) {
+      labelEl.style.backgroundImage = url('chrome://favicon/' +
+                                          bookmarkNode.url);
+      var urlEl = el.childNodes[1].firstChild;
+      urlEl.textContent = urlEl.href = bookmarkNode.url;
+    } else {
+      el.className = 'folder';
+    }
+
+    var folderEl = el.lastChild.firstChild;
+    if (showFolder) {
+      folderEl.style.display = '';
+      folderEl.textContent = getFolder(bookmarkNode.parentId);
+      folderEl.href = '#' + bookmarkNode.parentId;
+    } else {
+      folderEl.style.display = 'none';
+    }
+  }
+
+  var listItemPromo = (function() {
+    var div = cr.doc.createElement('div');
+    div.innerHTML = '<div>' +
+        '<div class=label></div>' +
+        '<div><span class=url></span></div>' +
+        '<div><span class=folder></span></div>' +
+        '</div>';
+    return div.firstChild;
+  })();
+
+  return {
+    createListItem: createListItem,
+    BookmarkList: BookmarkList,
+    listLookup: listLookup
+  };
+});
diff --git a/resources/bookmark_manager/js/bmm/bookmarktree.js b/resources/bookmark_manager/js/bmm/bookmarktree.js
new file mode 100644
index 0000000..8acfa28
--- /dev/null
+++ b/resources/bookmark_manager/js/bmm/bookmarktree.js
@@ -0,0 +1,189 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+cr.define('bmm', function() {
+  const Tree = cr.ui.Tree;
+  const TreeItem = cr.ui.TreeItem;
+
+  var treeLookup = {};
+
+  /**
+   * Creates a new tree item for a bookmark node.
+   * @param {!Object} bookmarkNode The bookmark node.
+   * @return {!cr.ui.TreeItem} The newly created tree item.
+   */
+  function createTreeItem(bookmarkNode) {
+    var id = bookmarkNode.id;
+    var ti = new TreeItem({
+      bookmarkId: id,
+      bookmarkNode: bookmarkNode,
+      // Bookmark toolbar and Other bookmarks are not draggable.
+      draggable: bookmarkNode.parentId != ROOT_ID
+    });
+    treeLookup[id] = ti;
+    updateTreeItem(ti, bookmarkNode);
+    return ti;
+  }
+
+  /**
+   * Updates an existing tree item to match a bookmark node.
+   * @param {!cr.ui.TreeItem} el The tree item to update.
+   * @param {!Object} bookmarkNode The bookmark node describing the tree item.
+   */
+  function updateTreeItem(el, bookmarkNode) {
+    el.label = bookmarkNode.title;
+  }
+
+  /**
+   * Asynchronousy adds a tree item at the correct index based on the bookmark
+   * backend.
+   *
+   * Since the bookmark tree only contains folders the index we get from certain
+   * callbacks is not very useful so we therefore have this async call which
+   * gets the children of the parent and adds the tree item at the desired
+   * index.
+   *
+   * This also exoands the parent so that newly added children are revealed.
+   *
+   * @param {!cr.ui.TreeItem} parent The parent tree item.
+   * @param {!cr.ui.TreeItem} treeItem The tree item to add.
+   * @param {Function=} f A function which gets called after the item has been
+   *     added at the right index.
+   */
+  function addTreeItem(parent, treeItem, opt_f) {
+    chrome.bookmarks.getChildren(parent.bookmarkNode.id, function(children) {
+      var index = children.filter(bmm.isFolder).map(function(item) {
+        return item.id;
+      }).indexOf(treeItem.bookmarkNode.id);
+      parent.addAt(treeItem, index);
+      parent.expanded = true;
+      if (opt_f)
+        opt_f();
+    });
+  }
+
+
+  /**
+   * Creates a new bookmark list.
+   * @param {Object=} opt_propertyBag Optional properties.
+   * @constructor
+   * @extends {HTMLButtonElement}
+   */
+  var BookmarkTree = cr.ui.define('tree');
+
+  BookmarkTree.prototype = {
+    __proto__: Tree.prototype,
+
+    handleBookmarkChanged: function(id, changeInfo) {
+      var treeItem = treeLookup[id];
+      if (treeItem) {
+        treeItem.bookmarkNode.title = changeInfo.title;
+        updateTreeItem(treeItem, treeItem.bookmarkNode);
+      }
+    },
+
+    handleChildrenReordered: function(id, reorderInfo) {
+      var parentItem = treeLookup[id];
+      // The tree only contains folders.
+      var dirIds = reorderInfo.childIds.filter(function(id) {
+        return id in treeLookup;
+      }).forEach(function(id, i) {
+        parentItem.addAt(treeLookup[id], i);
+      });
+    },
+
+    handleCreated: function(id, bookmarkNode) {
+      if (bmm.isFolder(bookmarkNode)) {
+        var parentItem = treeLookup[bookmarkNode.parentId];
+        var newItem = createTreeItem(bookmarkNode);
+        addTreeItem(parentItem, newItem);
+      }
+    },
+
+    handleMoved: function(id, moveInfo) {
+      var treeItem = treeLookup[id];
+      if (treeItem) {
+        var oldParentItem = treeLookup[moveInfo.oldParentId];
+        oldParentItem.remove(treeItem);
+        var newParentItem = treeLookup[moveInfo.parentId];
+        // The tree only shows folders so the index is not the index we want. We
+        // therefore get the children need to adjust the index.
+        addTreeItem(newParentItem, treeItem);
+      }
+    },
+
+    handleRemoved: function(id, removeInfo) {
+      var parentItem = treeLookup[removeInfo.parentId];
+      var itemToRemove = treeLookup[id];
+      if (parentItem && itemToRemove) {
+        parentItem.remove(itemToRemove);
+      }
+    },
+
+    insertSubtree:function(folder) {
+      if (!bmm.isFolder(folder))
+        return;
+      var children = folder.children;
+      this.handleCreated(folder.id, folder);
+      for(var i = 0; i < children.length; i++) {
+        var child = children[i];
+        this.insertSubtree(child);
+      }
+    },
+
+    /**
+     * Returns the bookmark node with the given ID. The tree only maintains
+     * folder nodes.
+     * @param {string} id The ID of the node to find.
+     * @return {BookmarkTreeNode} The bookmark tree node or null if not found.
+     */
+    getBookmarkNodeById: function(id) {
+      var treeItem = treeLookup[id];
+      if (treeItem)
+        return treeItem.bookmarkNode;
+      return null;
+    },
+
+    /**
+     * Fetches the bookmark items and builds the tree control.
+     */
+    buildTree: function() {
+
+      /**
+       * Recursive helper function that adds all the directories to the
+       * parentTreeItem.
+       * @param {!cr.ui.Tree|!cr.ui.TreeItem} parentTreeItem The parent tree element
+       *     to append to.
+       * @param {!Array.<BookmarkTreeNode>} bookmarkNodes
+       * @return {boolean} Whether any directories where added.
+       */
+      function buildTreeItems(parentTreeItem, bookmarkNodes) {
+        var hasDirectories = false;
+        for (var i = 0, bookmarkNode; bookmarkNode = bookmarkNodes[i]; i++) {
+          if (bmm.isFolder(bookmarkNode)) {
+            hasDirectories = true;
+            var item = bmm.createTreeItem(bookmarkNode);
+            parentTreeItem.add(item);
+            var anyChildren = buildTreeItems(item, bookmarkNode.children);
+            item.expanded = anyChildren;
+          }
+        }
+        return hasDirectories;
+      }
+
+      var self = this;
+      chrome.bookmarks.getTree(function(root) {
+        buildTreeItems(self, root[0].children);
+        cr.dispatchSimpleEvent(self, 'load');
+      });
+    }
+  };
+
+  return {
+    BookmarkTree: BookmarkTree,
+    createTreeItem: createTreeItem,
+    treeLookup: treeLookup
+  };
+});
diff --git a/resources/bookmark_manager/js/bmm/treeiterator.js b/resources/bookmark_manager/js/bmm/treeiterator.js
new file mode 100644
index 0000000..042f24f
--- /dev/null
+++ b/resources/bookmark_manager/js/bmm/treeiterator.js
@@ -0,0 +1,113 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('bmm', function() {
+  /**
+   * An inorder (document order) iterator for iterating over a bookmark tree.
+   *
+   * <pre>
+   * var it = new TreeIterator(node);
+   * while (it.moveNext()) {
+   *   print(it.current.title);
+   * }
+   * </pre>
+   *
+   * @param {!BookmarkTreeNode} node The node to start at.
+   * @constructor
+   */
+  function TreeIterator(node) {
+    this.current_ = node;
+    this.parentStack_ = [];
+    this.indexStack_ = [];
+  }
+
+  /**
+   * Helper function for {@code TreeIterator.prototype.next}. This returns the
+   * next node in document order.
+   * @param {BookmarkTreeNode} node The current node.
+   * @param {!Array.<!BookmarkTreeNode>} parents A stack of parents.
+   * @param {!Array.<number>} index A stack of indexes.
+   * @return {BookmarkTreeNode} The next node or null if no more nodes can be
+   *     found.
+   */
+  function getNext(node, parents, index) {
+    var i, p;
+
+    if (!node)
+      return null;
+
+    // If the node has children return first child.
+    if (node.children && node.children.length) {
+      parents.push(node);
+      index.push(0);
+      return node.children[0];
+    }
+
+    if (!parents.length)
+      return null;
+
+    // Walk up the parent stack until we find a node that has a next sibling.
+    while (node) {
+      p = parents[parents.length - 1];
+      if (!p)
+        return null;
+      i = index[index.length - 1];
+      if (i + 1 < p.children.length)
+        break;
+      node = parents.pop();
+      index.pop();
+    }
+
+    // Walked out of subtree.
+    if (!parents.length || !node)
+      return null;
+
+    // Return next child.
+    i = ++index[index.length - 1];
+    p = parents[parents.length - 1];
+    return p.children[i];
+  }
+
+  TreeIterator.prototype = {
+    /**
+     * Whether the next move will be the first move.
+     * @type {boolean}
+     * @private
+     */
+    first_: true,
+
+    /**
+     * Moves the iterator to the next item.
+     * @return {boolean} Whether we succeeded moving to the next item. This
+     * returns false when we have moved off the end of the iterator.
+     */
+    moveNext: function() {
+      // The first call to this should move us to the first node.
+      if (this.first_) {
+        this.first_ = false;
+        return true;
+      }
+      this.current_ = getNext(this.current_, this.parentStack_,
+                              this.indexStack_);
+
+      return !!this.current_;
+    },
+
+    /**
+     * The current item. This throws an exception if trying to access after
+     * {@code moveNext} has returned false or before {@code moveNext} has been
+     * called.
+     * @type {!BookmarkTreeNode}
+     */
+    get current() {
+      if (!this.current_ || this.first_)
+        throw Error('No such element');
+      return this.current_;
+    }
+  };
+
+  return {
+    TreeIterator: TreeIterator
+  };
+});
diff --git a/resources/bookmark_manager/js/cr.js b/resources/bookmark_manager/js/cr.js
new file mode 100644
index 0000000..9de94da
--- /dev/null
+++ b/resources/bookmark_manager/js/cr.js
@@ -0,0 +1,314 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+const cr = (function() {
+
+  /**
+   * Whether we are using a Mac or not.
+   * @type {boolean}
+   */
+  const isMac = /Mac/.test(navigator.platform);
+
+  /**
+   * Builds an object structure for the provided namespace path,
+   * ensuring that names that already exist are not overwritten. For
+   * example:
+   * "a.b.c" -> a = {};a.b={};a.b.c={};
+   * @param {string} name Name of the object that this file defines.
+   * @param {*=} opt_object The object to expose at the end of the path.
+   * @param {Object=} opt_objectToExportTo The object to add the path to;
+   *     default is {@code window}.
+   * @private
+   */
+  function exportPath(name, opt_object, opt_objectToExportTo) {
+    var parts = name.split('.');
+    var cur = opt_objectToExportTo || window /* global */;
+
+    for (var part; parts.length && (part = parts.shift());) {
+      if (!parts.length && opt_object !== undefined) {
+        // last part and we have an object; use it
+        cur[part] = opt_object;
+      } else if (part in cur) {
+        cur = cur[part];
+      } else {
+        cur = cur[part] = {};
+      }
+    }
+    return cur;
+  };
+
+  /**
+   * Fires a property change event on the target.
+   * @param {EventTarget} target The target to dispatch the event on.
+   * @param {string} propertyName The name of the property that changed.
+   * @param {*} newValue The new value for the property.
+   * @param {*} oldValue The old value for the property.
+   */
+  function dispatchPropertyChange(target, propertyName, newValue, oldValue) {
+    // TODO(arv): Depending on cr.Event here is a bit ugly.
+    var e = new cr.Event(propertyName + 'Change');
+    e.propertyName = propertyName;
+    e.newValue = newValue;
+    e.oldValue = oldValue;
+    target.dispatchEvent(e);
+  }
+
+  /**
+   * The kind of property to define in {@code defineProperty}.
+   * @enum {number}
+   */
+  const PropertyKind = {
+    /**
+     * Plain old JS property where the backing data is stored as a "private"
+     * field on the object.
+     */
+    JS: 'js',
+
+    /**
+     * The property backing data is stored as an attribute on an element.
+     */
+    ATTR: 'attr',
+
+    /**
+     * The property backing data is stored as an attribute on an element. If the
+     * element has the attribute then the value is true.
+     */
+    BOOL_ATTR: 'boolAttr'
+  };
+
+  /**
+   * Helper function for defineProperty that returns the getter to use for the
+   * property.
+   * @param {string} name
+   * @param {cr.PropertyKind} kind
+   * @param {*} defaultValue The default value. This is only used for the ATTR
+   *    kind.
+   * @return {function():*} The getter for the property.
+   */
+  function getGetter(name, kind, defaultValue) {
+    switch (kind) {
+      case PropertyKind.JS:
+        var privateName = name + '_';
+        return function() {
+          return this[privateName];
+        };
+      case PropertyKind.ATTR:
+        // For attr with default value we return the default value if the
+        // element is missing the attribute.
+        if (defaultValue == undefined) {
+          return function() {
+            return this.getAttribute(name);
+          };
+        } else {
+          return function() {
+            // WebKit uses null for non existant attributes.
+            var value = this.getAttribute(name);
+            return value !== null ? value : defaultValue;
+          };
+        }
+      case PropertyKind.BOOL_ATTR:
+        // Boolean attributes don't support default values.
+        return function() {
+          return this.hasAttribute(name);
+        };
+    }
+  }
+
+  /**
+   * Helper function for defineProperty that returns the setter of the right
+   * kind.
+   * @param {string} name The name of the property we are defining the setter
+   *     for.
+   * @param {cr.PropertyKind} kind The kind of property we are getting the
+   *     setter for.
+   * @return {function(*):void} The function to use as a setter.
+   */
+  function getSetter(name, kind) {
+    switch (kind) {
+      case PropertyKind.JS:
+        var privateName = name + '_';
+        return function(value) {
+          var oldValue = this[privateName];
+          if (value !== oldValue) {
+            this[privateName] = value;
+            dispatchPropertyChange(this, name, value, oldValue);
+          }
+        };
+
+      case PropertyKind.ATTR:
+        return function(value) {
+          var oldValue = this[name];
+          if (value !== oldValue) {
+            this.setAttribute(name, value);
+            dispatchPropertyChange(this, name, value, oldValue);
+          }
+        };
+
+      case PropertyKind.BOOL_ATTR:
+        return function(value) {
+          var oldValue = this[name];
+          if (value !== oldValue) {
+            if (value)
+              this.setAttribute(name, name);
+            else
+              this.removeAttribute(name);
+            dispatchPropertyChange(this, name, value, oldValue);
+          }
+        };
+    }
+  }
+
+  /**
+   * Defines a property on an object. When the setter changes the value a
+   * property change event with the type {@code name + 'Change'} is fired.
+   * @param {!Object} The object to define the property for.
+   * @param {string} The name of the property.
+   * @param {cr.PropertyKind=} opt_kind What kind of underlying storage to use.
+   * @param {*} opt_defaultValue The default value.
+   */
+  function defineProperty(obj, name, opt_kind, opt_default) {
+    if (typeof obj == 'function')
+      obj = obj.prototype;
+
+    var kind = opt_kind || PropertyKind.JS;
+
+    if (!obj.__lookupGetter__(name)) {
+      // For js properties we set the default value on the prototype.
+      if (kind == PropertyKind.JS && arguments.length > 3)  {
+        var privateName = name + '_';
+        obj[privateName] = opt_default;
+      }
+      obj.__defineGetter__(name, getGetter(name, kind, opt_default));
+    }
+
+    if (!obj.__lookupSetter__(name)) {
+      obj.__defineSetter__(name, getSetter(name, kind));
+    }
+  }
+
+  /**
+   * Counter for use with createUid
+   */
+  var uidCounter = 1;
+
+  /**
+   * @return {number} A new unique ID.
+   */
+  function createUid() {
+    return uidCounter++;
+  }
+
+  /**
+   * Returns a unique ID for the item. This mutates the item so it needs to be
+   * an object
+   * @param {!Object} item The item to get the unique ID for.
+   * @return {number} The unique ID for the item.
+   */
+  function getUid(item) {
+    if (item.hasOwnProperty('uid'))
+      return item.uid;
+    return item.uid = createUid();
+  }
+
+  /**
+   * Partially applies this function to a particular 'this object' and zero or
+   * more arguments. The result is a new function with some arguments of the
+   * first function pre-filled and the value of |this| 'pre-specified'.
+   *
+   * Remaining arguments specified at call-time are appended to the pre-
+   * specified ones.
+   *
+   * Usage:
+   * <pre>var barMethBound = bind(myFunction, myObj, 'arg1', 'arg2');
+   * barMethBound('arg3', 'arg4');</pre>
+   *
+   * @param {Function} fn A function to partially apply.
+   * @param {Object|undefined} selfObj Specifies the object which |this| should
+   *     point to when the function is run. If the value is null or undefined,
+   *     it will default to the global object.
+   * @param {...*} var_args Additional arguments that are partially
+   *     applied to the function.
+   *
+   * @return {!Function} A partially-applied form of the function bind() was
+   *     invoked as a method of.
+   */
+  function bind(fn, selfObj, var_args) {
+    var boundArgs = Array.prototype.slice.call(arguments, 2);
+    return function() {
+      var args = Array.prototype.slice.call(arguments);
+      args.unshift.apply(args, boundArgs);
+      return fn.apply(selfObj, args);
+    }
+  }
+
+  /**
+   * Dispatches a simple event on an event target.
+   * @param {!EventTarget} target The event target to dispatch the event on.
+   * @param {string} type The type of the event.
+   * @param {boolean=} opt_bubbles Whether the event bubbles or not.
+   * @param {boolean=} opt_cancelable Whether the default action of the event
+   *     can be prevented.
+   * @return {boolean} If any of the listeners called {@code preventDefault}
+   *     during the dispatch this will return false.
+   */
+  function dispatchSimpleEvent(target, type, opt_bubbles, opt_cancelable) {
+    var e = new cr.Event(type, opt_bubbles, opt_cancelable);
+    return target.dispatchEvent(e);
+  }
+
+  /**
+   * @param {string} name
+   * @param {!Function} fun
+   */
+  function define(name, fun) {
+    var obj = exportPath(name);
+    var exports = fun();
+    for (var key in exports) {
+      obj[key] = exports[key];
+    }
+  }
+
+  /**
+   * Document used for various document related operations.
+   * @type {!Document}
+   */
+  var doc = document;
+
+
+  /**
+   * Allows you to run func in the context of a different document.
+   * @param {!Document} document The document to use.
+   * @param {function():*} func The function to call.
+   */
+  function withDoc(document, func) {
+    var oldDoc = doc;
+    doc = document;
+    try {
+      func();
+    } finally {
+      doc = oldDoc;
+    }
+  }
+
+  return {
+    isMac: isMac,
+    define: define,
+    defineProperty: defineProperty,
+    PropertyKind: PropertyKind,
+    createUid: createUid,
+    getUid: getUid,
+    bind: bind,
+    dispatchSimpleEvent: dispatchSimpleEvent,
+    dispatchPropertyChange: dispatchPropertyChange,
+
+    /**
+     * The document that we are currently using.
+     * @type {!Document}
+     */
+    get doc() {
+      return doc;
+    },
+    withDoc: withDoc
+  };
+})();
diff --git a/resources/bookmark_manager/js/cr/event.js b/resources/bookmark_manager/js/cr/event.js
new file mode 100644
index 0000000..19fee7e
--- /dev/null
+++ b/resources/bookmark_manager/js/cr/event.js
@@ -0,0 +1,40 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview This is a simple pure JS event class that can be used with
+ * {@code cr.ui.EventTarget}. It should not be used with DOM EventTargets.
+ */
+
+cr.define('cr', function() {
+
+  // cr.Event is called CustomEvent in here to prevent naming conflicts. We
+  // alse store the original Event in case someone does a global alias of
+  // cr.Event.
+
+  const DomEvent = Event;
+
+  /**
+   * Creates a new event to be used with cr.EventTarget or DOM EventTarget
+   * objects.
+   * @param {string} type The name of the event.
+   * @param {boolean=}
+   * @constructor
+   */
+  function CustomEvent(type, opt_bubbles, opt_capture) {
+    var e = cr.doc.createEvent('Event');
+    e.initEvent(type, !!opt_bubbles, !!opt_capture);
+    e.__proto__ = CustomEvent.prototype;
+    return e;
+  }
+
+  CustomEvent.prototype = {
+    __proto__: DomEvent.prototype
+  };
+
+  // Export
+  return {
+    Event: CustomEvent
+  };
+});
diff --git a/resources/bookmark_manager/js/cr/eventtarget.js b/resources/bookmark_manager/js/cr/eventtarget.js
new file mode 100644
index 0000000..f2bc733
--- /dev/null
+++ b/resources/bookmark_manager/js/cr/eventtarget.js
@@ -0,0 +1,96 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('cr', function() {
+
+  // TODO(arv): object.handleEvent
+
+  function EventTarget() {
+  }
+
+  EventTarget.prototype = {
+
+    /**
+     * Adds an event listener to the target.
+     * @param {string} type The name of the event.
+     * @param {!Function|{handleEvent:Function}} handler The handler for the
+     *     event. This is called when the event is dispatched.
+     */
+    addEventListener: function(type, handler) {
+      if (!this.listeners_)
+        this.listeners_ = {__proto__: null};
+      if (!(type in this.listeners_)) {
+        this.listeners_[type] = [handler];
+      } else {
+        var handlers = this.listeners_[type];
+        if (handlers.indexOf(handler) < 0)
+          handlers.push(handler);
+      }
+    },
+
+    /**
+     * Removes an event listener from the target.
+     * @param {string} type The name of the event.
+     * @param {!Function|{handleEvent:Function}} handler The handler for the
+     *     event.
+     */
+    removeEventListener: function(type, handler) {
+      if (!this.listeners_)
+        return;
+      if (type in this.listeners_) {
+        var handlers = this.listeners_[type];
+        var index = handlers.indexOf(handler);
+        if (index >= 0) {
+          // Clean up if this was the last listener.
+          if (handlers.length == 1)
+            delete this.listeners_[type];
+          else
+            handlers.splice(index, 1);
+        }
+      }
+    },
+
+    /**
+     * Dispatches an event and calls all the listeners that are listening to
+     * the type of the event.
+     * @param {!cr.event.Event} event The event to dispatch.
+     * @return {boolean} Whether the default action was prevented. If someone
+     *     calls preventDefault on the event object then this returns false.
+     */
+    dispatchEvent: function(event) {
+      if (!this.listeners_)
+        return true;
+
+      // Since we are using DOM Event objects we need to override some of the
+      // properties and methods so that we can emulate this correctly.
+      var self = this;
+      event.__defineGetter__('target', function() {
+        return self;
+      });
+      event.preventDefault = function() {
+        this.returnValue = false;
+      };
+
+      var type = event.type;
+      var prevented = 0;
+      if (type in this.listeners_) {
+        // Clone to prevent removal during dispatch
+        var handlers = this.listeners_[type].concat();
+        for (var i = 0, handler; handler = handlers[i]; i++) {
+          if (handler.handleEvent)
+            prevented |= handler.handleEvent.call(handler, event) === false;
+          else
+            prevented |= handler.call(this, event) === false;
+        }
+      }
+
+      return !prevented && event.returnValue;
+    }
+  };
+
+  // Export
+  return {
+    EventTarget: EventTarget
+  };
+});
diff --git a/resources/bookmark_manager/js/cr/promise.js b/resources/bookmark_manager/js/cr/promise.js
new file mode 100644
index 0000000..e0494a5
--- /dev/null
+++ b/resources/bookmark_manager/js/cr/promise.js
@@ -0,0 +1,173 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview This implementes a future promise class.
+ */
+
+cr.define('cr', function() {
+
+  /**
+   * Sentinel used to mark a value as pending.
+   */
+  const PENDING_VALUE = {};
+
+  /**
+   * Creates a future promise.
+   * @param {Function=} opt_callback Callback.
+   * @constructor
+   */
+  function Promise(opt_callback) {
+    /**
+     * An array of the callbacks.
+     * @type {!Array.<!Function>}
+     * @private
+     */
+    this.callbacks_ = opt_callback ? [opt_callback] : [];
+  }
+
+  Promise.prototype = {
+    /**
+     * The current value.
+     * @type {*}
+     * @private
+     */
+    value_: PENDING_VALUE,
+
+    /**
+     * The value of the future promise. Accessing this before the promise has
+     * been fulfilled will throw an error. If this is set to an exception
+     * accessing this will throw as well.
+     * @type {*}
+     */
+    get value() {
+      return this.done ? this.value_ : undefined;
+    },
+    set value(value) {
+      if (!this.done) {
+        this.value_ = value;
+        for (var i = 0; i < this.callbacks_.length; i++) {
+          this.callbacks_[i].call(null, value);
+        }
+        this.callbacks_.length = 0;
+      }
+    },
+
+    /**
+     * Whether the future promise has been fulfilled.
+     * @type {boolean}
+     */
+    get done() {
+      return this.value_ !== PENDING_VALUE;
+    },
+
+    /**
+     * Adds a listener to the future promise. The function will be called when
+     * the promise is fulfilled. If the promise is already fullfilled this will
+     * never call the function.
+     * @param {!Function} fun The function to call.
+     */
+    addListener: function(fun) {
+      if (this.done)
+        fun(this.value);
+      else
+        this.callbacks_.push(fun);
+    },
+
+    /**
+     * Removes a previously added listener from the future promise.
+     * @param {!Function} fun The function to remove.
+     */
+    removeListener: function(fun) {
+      var i = this.callbacks_.indexOf(fun);
+      if (i >= 0)
+        this.callbacks_.splice(i, 1);
+    },
+
+    /**
+     * If the promise is done then this returns the string representation of
+     * the value.
+     * @return {string} The string representation of the promise.
+     * @override
+     */
+    toString: function() {
+      if (this.done)
+        return String(this.value);
+      else
+        return '[object Promise]';
+    },
+
+    /**
+     * Override to allow arithmetic.
+     * @override
+     */
+    valueOf: function() {
+      return this.value;
+    }
+  };
+
+  /**
+   * When a future promise is done call {@code fun}. This also calls the
+   * function if the promise has already been fulfilled.
+   * @param {!Promise} p The promise.
+   * @param {!Function} fun The function to call when the promise is fulfilled.
+   */
+  Promise.when = function(p, fun) {
+    p.addListener(fun);
+  };
+
+  /**
+   * Creates a new promise the will be fulfilled after {@code t} ms.
+   * @param {number} t The time to wait before the promise is fulfilled.
+   * @param {*=} opt_value The value to return after the wait.
+   * @return {!Promise} The new future promise.
+   */
+  Promise.wait = function(t, opt_value) {
+    var p = new Promise;
+    window.setTimeout(function() {
+      p.value = opt_value;
+    }, t);
+    return p;
+  };
+
+  /**
+   * Creates a new future promise that is fulfilled when any of the promises are
+   * fulfilled.
+   * @param {...!Promise} var_args The promises used to build up the new
+   *     promise.
+   * @return {!Promise} The new promise that will be fulfilled when any of th
+   *     passed in promises are fulfilled.
+   */
+  Promise.any = function(var_args) {
+    var p = new Promise;
+    function f(v) {
+      p.value = v;
+    }
+    for (var i = 0; i < arguments.length; i++) {
+      arguments[i].addListener(f);
+    }
+    return p;
+  };
+
+  /**
+   * Wraps an event in a future promise.
+   * @param {!EventTarget} target The object that dispatches the event.
+   * @param {string} type The type of the event.
+   * @param {boolean=} opt_useCapture Whether to listen to the capture phase or
+   *     the bubble phase.
+   * @return {!Promise} The promise that will be fulfilled when the event is
+   *     dispatched.
+   */
+  Promise.event = function(target, type, opt_useCapture) {
+    var p = new Promise;
+    target.addEventListener(type, function(e) {
+      p.value = e;
+    }, opt_useCapture);
+    return p;
+  };
+
+  return {
+    Promise: Promise
+  };
+})();
diff --git a/resources/bookmark_manager/js/cr/ui.js b/resources/bookmark_manager/js/cr/ui.js
new file mode 100644
index 0000000..d87c04a
--- /dev/null
+++ b/resources/bookmark_manager/js/cr/ui.js
@@ -0,0 +1,173 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('cr.ui', function() {
+
+  /**
+   * Decorates elements as an instance of a class.
+   * @param {string|!Element} source The way to find the element(s) to decorate.
+   *     If this is a string then {@code querySeletorAll} is used to find the
+   *     elements to decorate.
+   * @param {!Function} constr The constructor to decorate with. The constr
+   *     needs to have a {@code decorate} function.
+   */
+  function decorate(source, constr) {
+    var elements;
+    if (typeof source == 'string')
+      elements = cr.doc.querySelectorAll(source);
+    else
+      elements = [source];
+
+    for (var i = 0, el; el = elements[i]; i++) {
+      if (!(el instanceof constr))
+        constr.decorate(el);
+    }
+  }
+
+  /**
+   * Helper function for creating new element for define.
+   */
+  function createElementHelper(tagName, opt_bag) {
+    // Allow passing in ownerDocument to create in a different document.
+    var doc;
+    if (opt_bag && opt_bag.ownerDocument)
+      doc = opt_bag.ownerDocument;
+    else
+      doc = cr.doc;
+    return doc.createElement(tagName);
+  }
+
+  /**
+   * Creates the constructor for a UI element class.
+   *
+   * Usage:
+   * <pre>
+   * var List = cr.ui.define('list');
+   * List.prototype = {
+   *   __proto__: HTMLUListElement.prototype,
+   *   decorate: function() {
+   *     ...
+   *   },
+   *   ...
+   * };
+   * </pre>
+   *
+   * @param {string|Function} tagNameOrFunction The tagName or
+   *     function to use for newly created elements. If this is a function it
+   *     needs to return a new element when called.
+   * @return {function(Object=):Element} The constructor function which takes
+   *     an optional property bag. The function also has a static
+   *     {@code decorate} method added to it.
+   */
+  function define(tagNameOrFunction) {
+    var createFunction, tagName;
+    if (typeof tagNameOrFunction == 'function') {
+      createFunction = tagNameOrFunction;
+      tagName = '';
+    } else {
+      createFunction = createElementHelper;
+      tagName = tagNameOrFunction;
+    }
+
+    /**
+     * Creates a new UI element constructor.
+     * @param {Object=} opt_propertyBag Optional bag of properties to set on the
+     *     object after created. The property {@code ownerDocument} is special
+     *     cased and it allows you to create the element in a different
+     *     document than the default.
+     * @constructor
+     */
+    function f(opt_propertyBag) {
+      var el = createFunction(tagName, opt_propertyBag);
+      f.decorate(el);
+      for (var propertyName in opt_propertyBag) {
+        el[propertyName] = opt_propertyBag[propertyName];
+      }
+      return el;
+    }
+
+    /**
+     * Decorates an element as a UI element class.
+     * @param {!Element} el The element to decorate.
+     */
+    f.decorate = function(el) {
+      el.__proto__ = f.prototype;
+      el.decorate();
+    };
+
+    return f;
+  }
+
+  /**
+   * Input elements do not grow and shrink with their content. This is a simple
+   * (and not very efficient) way of handling shrinking to content with support
+   * for min width and limited by the width of the parent element.
+   * @param {HTMLElement} el The element to limit the width for.
+   * @param {number} parentEl The parent element that should limit the size.
+   * @param {number} min The minimum width.
+   */
+  function limitInputWidth(el, parentEl, min) {
+    // Needs a size larger than borders
+    el.style.width = '10px';
+    var doc = el.ownerDocument;
+    var win = doc.defaultView;
+    var computedStyle = win.getComputedStyle(el);
+    var parentComputedStyle = win.getComputedStyle(parentEl);
+    var rtl = computedStyle.direction == 'rtl';
+
+    // To get the max width we get the width of the treeItem minus the position
+    // of the input.
+    var inputRect = el.getBoundingClientRect();  // box-sizing
+    var parentRect = parentEl.getBoundingClientRect();
+    var startPos = rtl ? parentRect.right - inputRect.right :
+        inputRect.left - parentRect.left;
+
+    // Add up border and padding of the input.
+    var inner = parseInt(computedStyle.borderLeftWidth, 10) +
+        parseInt(computedStyle.paddingLeft, 10) +
+        parseInt(computedStyle.paddingRight, 10) +
+        parseInt(computedStyle.borderRightWidth, 10);
+
+    // We also need to subtract the padding of parent to prevent it to overflow.
+    var parentPadding = rtl ? parseInt(parentComputedStyle.paddingLeft, 10) :
+        parseInt(parentComputedStyle.paddingRight, 10);
+
+    // The magic number 14 comes from trial and error :'( It consists of:
+    // border + padding + treeItem.paddingEnd + treeItem.borderEnd +
+    // tree.paddingEnd
+    var max = parentEl.clientWidth - startPos - inner - parentPadding;
+
+    var pcs = getComputedStyle(parentEl);
+    console.log('pcs', 'borderLeft', pcs.borderLeftWidth,
+                'paddingLeft', pcs.paddingLeft,
+                'paddingRight', pcs.paddingRight,
+                'borderRight', pcs.borderRightWidth,
+                'width', pcs.width,
+                'clientWidth', parentEl.clientWidth,
+                'offsetWidth', parentEl.offsetWidth);
+
+    function limit() {
+      if (el.scrollWidth > max) {
+        el.style.width = max + 'px';
+      } else {
+        el.style.width = 0;
+        var sw = el.scrollWidth;
+        if (sw < min) {
+          el.style.width = min + 'px';
+        } else {
+          el.style.width = sw + 'px';
+        }
+      }
+    }
+
+    el.addEventListener('input', limit);
+    limit();
+  }
+
+  return {
+    decorate: decorate,
+    define: define,
+    limitInputWidth: limitInputWidth
+  };
+});
diff --git a/resources/bookmark_manager/js/cr/ui/command.js b/resources/bookmark_manager/js/cr/ui/command.js
new file mode 100644
index 0000000..d1a0677
--- /dev/null
+++ b/resources/bookmark_manager/js/cr/ui/command.js
@@ -0,0 +1,265 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview A command is an abstraction of an action a user can do in the
+ * UI.
+ *
+ * When the focus changes in the document for each command a canExecute event
+ * is dispatched on the active element. By listening to this event you can
+ * enable and disable the command by setting the event.canExecute property.
+ *
+ * When a command is executed a command event is dispatched on the active
+ * element. Note that you should stop the propagation after you have handled the
+ * command if there might be other command listeners higher up in the DOM tree.
+ */
+
+cr.define('cr.ui', function() {
+
+  /**
+   * Creates a new command element.
+   * @constructor
+   * @extends {HTMLElement}
+   */
+  var Command = cr.ui.define('command');
+
+  Command.prototype = {
+    __proto__: HTMLElement.prototype,
+
+    /**
+     * Initializes the command.
+     */
+    decorate: function() {
+      CommandManager.init(this.ownerDocument);
+    },
+
+    /**
+     * Executes the command. This dispatches a command event on the active
+     * element. If the command is {@code disabled} this does nothing.
+     */
+    execute: function() {
+      if (this.disabled)
+        return;
+      var doc = this.ownerDocument;
+      if (doc.activeElement) {
+        var e = new cr.Event('command', true, false);
+        e.command = this;
+        doc.activeElement.dispatchEvent(e);
+      }
+    },
+
+    /**
+     * Call this when there have been changes that might change whether the
+     * command can be executed or not.
+     */
+    canExecuteChange: function() {
+      dispatchCanExecuteEvent(this, this.ownerDocument.activeElement);
+    },
+
+    /**
+     * The keyboard shortcut that triggers the command. This is a string
+     * consisting of a keyIdentifier (as reported by WebKit in keydown) as
+     * well as optional key modifiers joinded with a '-'.
+     * For example:
+     *   "F1"
+     *   "U+0008-Meta" for Apple command backspace.
+     *   "U+0041-Ctrl" for Control A
+     *
+     * @type {string}
+     */
+    shortcut_: null,
+    get shortcut() {
+      return this.shortcut_;
+    },
+    set shortcut(shortcut) {
+      var oldShortcut = this.shortcut_;
+      if (shortcut !== oldShortcut) {
+        this.shortcut_ = shortcut;
+
+        // TODO(arv): Multiple shortcuts?
+
+        var mods = {};
+        var ident = '';
+        shortcut.split('-').forEach(function(part) {
+          var partLc = part.toLowerCase();
+          switch (partLc) {
+            case 'alt':
+            case 'ctrl':
+            case 'meta':
+            case 'shift':
+              mods[partLc + 'Key'] = true;
+              break;
+            default:
+              if (ident)
+                throw Error('Multiple keyboard shortcuts are not supported');
+              ident = part;
+          }
+
+          this.keyIdentifier_ = ident;
+          this.keyModifiers_ = mods;
+        }, this);
+
+        cr.dispatchPropertyChange(this, 'shortcut', this.shortcut_,
+                                  oldShortcut);
+      }
+    },
+
+    /**
+     * Whether the event object matches the shortcut for this command.
+     * @param {!Event} e The key event object.
+     * @return {boolean} Whether it matched or not.
+     */
+    matchesEvent: function(e) {
+      if (!this.keyIdentifier_)
+        return false;
+
+      if (e.keyIdentifier == this.keyIdentifier_) {
+        // All keyboard modifiers needs to match.
+        var mods = this.keyModifiers_;
+        return ['altKey', 'ctrlKey', 'metaKey', 'shiftKey'].every(function(k) {
+          return e[k] == !!mods[k];
+        });
+      }
+      return false;
+    }
+  };
+
+  /**
+   * The label of the command.
+   * @type {string}
+   */
+  cr.defineProperty(Command, 'label', cr.PropertyKind.ATTR);
+
+  /**
+   * Whether the command is disabled or not.
+   * @type {boolean}
+   */
+  cr.defineProperty(Command, 'disabled', cr.PropertyKind.BOOL_ATTR);
+
+  /**
+   * Whether the command is hidden or not.
+   * @type {boolean}
+   */
+  cr.defineProperty(Command, 'hidden', cr.PropertyKind.BOOL_ATTR);
+
+  /**
+   * Dispatches a canExecute event on the target.
+   * @param {cr.ui.Command} command The command that we are testing for.
+   * @param {Element} target The target element to dispatch the event on.
+   */
+  function dispatchCanExecuteEvent(command, target) {
+    var e = new CanExecuteEvent(command, true)
+    target.dispatchEvent(e);
+    command.disabled = !e.canExecute;
+  }
+
+  /**
+   * The command managers for different documents.
+   */
+  var commandManagers = {};
+
+  /**
+   * Keeps track of the focused element and updates the commands when the focus
+   * changes.
+   * @param {!Document} doc The document that we are managing the commands for.
+   * @constructor
+   */
+  function CommandManager(doc) {
+    doc.addEventListener('focus', cr.bind(this.handleFocus_, this), true);
+    doc.addEventListener('keydown', cr.bind(this.handleKeyDown_, this), true);
+  }
+
+  /**
+   * Initializes a command manager for the document as needed.
+   * @param {!Document} doc The document to manage the commands for.
+   */
+  CommandManager.init = function(doc) {
+    var uid = cr.getUid(doc);
+    if (!(uid in commandManagers)) {
+      commandManagers[uid] = new CommandManager(doc);
+    }
+  },
+
+  CommandManager.prototype = {
+
+    /**
+     * Handles focus changes on the document.
+     * @param {Event} e The focus event object.
+     * @private
+     */
+    handleFocus_: function(e) {
+      var target = e.target;
+      var commands = Array.prototype.slice.call(
+          target.ownerDocument.querySelectorAll('command'));
+
+      commands.forEach(function(command) {
+        dispatchCanExecuteEvent(command, target);
+      });
+    },
+
+    /**
+     * Handles the keydown event and routes it to the right command.
+     * @param {!Event} e The keydown event.
+     */
+    handleKeyDown_: function(e) {
+      var target = e.target;
+      var commands = Array.prototype.slice.call(
+          target.ownerDocument.querySelectorAll('command'));
+
+      for (var i = 0, command; command = commands[i]; i++) {
+        if (!command.disabled && command.matchesEvent(e)) {
+          e.preventDefault();
+          // We do not want any other element to handle this.
+          e.stopPropagation();
+
+          command.execute();
+          return;
+        }
+      }
+    }
+  };
+
+  /**
+   * The event type used for canExecute events.
+   * @param {!cr.ui.Command} command The command that we are evaluating.
+   * @extends {Event}
+   */
+  function CanExecuteEvent(command) {
+    var e = command.ownerDocument.createEvent('Event');
+    e.initEvent('canExecute', true, false);
+    e.__proto__ = CanExecuteEvent.prototype;
+    e.command = command;
+    return e;
+  }
+
+  CanExecuteEvent.prototype = {
+    __proto__: Event.prototype,
+
+    /**
+     * The current command
+     * @type {cr.ui.Command}
+     */
+    command: null,
+
+    /**
+     * Whether the target can execute the command. Setting this also stops the
+     * propagation.
+     * @type {boolean}
+     */
+    canExecute_: false,
+    get canExecute() {
+      return this.canExecute_;
+    },
+    set canExecute(canExecute) {
+      this.canExecute_ = canExecute;
+      this.stopPropagation();
+    }
+  };
+
+  // Export
+  return {
+    Command: Command,
+    CanExecuteEvent: CanExecuteEvent
+  };
+});
diff --git a/resources/bookmark_manager/js/cr/ui/contextmenuhandler.js b/resources/bookmark_manager/js/cr/ui/contextmenuhandler.js
new file mode 100644
index 0000000..5ac0789
--- /dev/null
+++ b/resources/bookmark_manager/js/cr/ui/contextmenuhandler.js
@@ -0,0 +1,211 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('cr.ui', function() {
+
+  /**
+   * Handles context menus.
+   * @constructor
+   */
+  function ContextMenuHandler() {}
+
+  ContextMenuHandler.prototype = {
+
+    /**
+     * The menu that we are currently showing.
+     * @type {cr.ui.Menu}
+     */
+    menu_: null,
+    get menu() {
+      return this.menu_;
+    },
+
+    /**
+     * Shows a menu as a context menu.
+     * @param {!Event} e The event triggering the show (usally a contextmenu
+     *     event).
+     * @param {!cr.ui.Menu} menu The menu to show.
+     */
+    showMenu: function(e, menu) {
+      this.menu_ = menu;
+
+      menu.style.display = 'block';
+      // when the menu is shown we steal all keyboard events.
+      menu.ownerDocument.addEventListener('keydown', this, true);
+      menu.ownerDocument.addEventListener('mousedown', this, true);
+      menu.ownerDocument.addEventListener('blur', this, true);
+      menu.addEventListener('activate', this);
+      this.positionMenu_(e, menu);
+    },
+
+    /**
+     * Hide the currently shown menu.
+     */
+    hideMenu: function() {
+      var menu = this.menu;
+      if (!menu)
+        return;
+
+      menu.style.display = 'none';
+      menu.ownerDocument.removeEventListener('keydown', this, true);
+      menu.ownerDocument.removeEventListener('mousedown', this, true);
+      menu.ownerDocument.removeEventListener('blur', this, true);
+      menu.removeEventListener('activate', this);
+      menu.selectedIndex = -1;
+      this.menu_ = null;
+
+      // On windows we might hide the menu in a right mouse button up and if
+      // that is the case we wait some short period before we allow the menu
+      // to be shown again.
+      this.hideTimestamp_ = Date.now();
+    },
+
+    /**
+     * Positions the menu
+     * @param {!Event} e The event object triggering the showing.
+     * @param {!cr.ui.Menu} menu The menu to position.
+     * @private
+     */
+    positionMenu_: function(e, menu) {
+      // TODO(arv): Handle scrolled documents when needed.
+
+      var x, y;
+      // When the user presses the context menu key (on the keyboard) we need
+      // to detect this.
+      if (e.screenX == 0 && e.screenY == 0) {
+        var rect = e.currentTarget.getBoundingClientRect();
+        x = rect.left;
+        y = rect.top;
+      } else {
+        x = e.clientX;
+        y = e.clientY;
+      }
+
+      var menuRect = menu.getBoundingClientRect();
+      var bodyRect = menu.ownerDocument.body.getBoundingClientRect();
+
+      // Does menu fit below?
+      if (y + menuRect.height > bodyRect.height) {
+        // Does menu fit above?
+        if (y - menuRect.height >= 0) {
+          y -= menuRect.height;
+        } else {
+          // Menu did not fit above nor below.
+          y = 0;
+          // We could resize the menu here but lets not worry about that at this
+          // point.
+        }
+      }
+
+      // Does menu fit to the right?
+      if (x + menuRect.width > bodyRect.width) {
+        // Does menu fit to the left?
+        if (x - menuRect.width >= 0) {
+          x -= menuRect.width;
+        } else {
+          // Menu did not fit to the right nor to the left.
+          x = 0;
+          // We could resize the menu here but lets not worry about that at this
+          // point.
+        }
+      }
+
+      menu.style.left = x + 'px';
+      menu.style.top = y + 'px';
+    },
+
+    /**
+     * Handles event callbacks.
+     * @param {!Event} e The event object.
+     */
+    handleEvent: function(e) {
+      // Context menu is handled even when we have no menu.
+      if (e.type != 'contextmenu' && !this.menu)
+        return;
+
+      switch (e.type) {
+        case 'mousedown':
+          if (!this.menu.contains(e.target))
+            this.hideMenu();
+          else
+            e.preventDefault();
+          break;
+        case 'keydown':
+          // keyIdentifier does not report 'Esc' correctly
+          if (e.keyCode == 27 /* Esc */) {
+            this.hideMenu();
+
+          // If the menu is visible we let it handle all the keyboard events.
+          } else if (this.menu) {
+            this.menu.handleKeyDown(e);
+            e.preventDefault();
+            e.stopPropagation();
+          }
+          break;
+
+        case 'activate':
+        case 'blur':
+          this.hideMenu();
+          break;
+
+        case 'contextmenu':
+          if ((!this.menu || !this.menu.contains(e.target)) &&
+              (!this.hideTimestamp_ || Date.now() - this.hideTimestamp_ > 50))
+            this.showMenu(e, e.currentTarget.contextMenu);
+          e.preventDefault();
+          // Don't allow elements further up in the DOM to show their menus.
+          e.stopPropagation();
+          break;
+      }
+    },
+
+    /**
+     * Adds a contextMenu property to an element or element class.
+     * @param {!Element|!Function} element The element or class to add the
+     *     contextMenu property to.
+     */
+    addContextMenuProperty: function(element) {
+      if (typeof element == 'function')
+        element = element.prototype;
+
+      element.__defineGetter__('contextMenu', function() {
+        return this.contextMenu_;
+      });
+      element.__defineSetter__('contextMenu', function(menu) {
+        var oldContextMenu = this.contextMenu;
+
+        if (typeof menu == 'string' && menu[0] == '#') {
+          menu = this.ownerDocument.getElementById(menu.slice(1));
+          cr.ui.decorate(menu, Menu);
+        }
+
+        if (menu === oldContextMenu)
+          return;
+
+        if (oldContextMenu && !menu)
+          this.removeEventListener('contextmenu', contextMenuHandler);
+        if (menu && !oldContextMenu)
+          this.addEventListener('contextmenu', contextMenuHandler);
+
+        this.contextMenu_ = menu;
+
+        if (menu && menu.id)
+          this.setAttribute('contextmenu', '#' + menu.id);
+
+        cr.dispatchPropertyChange(this, 'contextMenu', menu, oldContextMenu);
+      });
+    }
+  };
+
+  /**
+   * The singleton context menu handler.
+   * @type {!ContextMenuHandler}
+   */
+  var contextMenuHandler = new ContextMenuHandler;
+
+  // Export
+  return {
+    contextMenuHandler: contextMenuHandler
+  };
+});
diff --git a/resources/bookmark_manager/js/cr/ui/list.js b/resources/bookmark_manager/js/cr/ui/list.js
new file mode 100644
index 0000000..9bdcd38
--- /dev/null
+++ b/resources/bookmark_manager/js/cr/ui/list.js
@@ -0,0 +1,235 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// require: listselectionmodel.js
+
+/**
+ * @fileoverview This implements a list control.
+ */
+
+cr.define('cr.ui', function() {
+  const ListSelectionModel = cr.ui.ListSelectionModel;
+
+  /**
+   * Creates a new list element.
+   * @param {Object=} opt_propertyBag Optional properties.
+   * @constructor
+   * @extends {HTMLUListElement}
+   */
+  var List = cr.ui.define('list');
+
+  List.prototype = {
+    __proto__: HTMLUListElement.prototype,
+
+    /**
+     * The selection model to use.
+     * @type {cr.ui.ListSelectionModel}
+     */
+    get selectionModel() {
+      return this.selectionModel_;
+    },
+    set selectionModel(sm) {
+      var oldSm = this.selectionModel_;
+      if (oldSm == sm)
+        return;
+
+      if (!this.boundHandleOnChange_) {
+        this.boundHandleOnChange_ = cr.bind(this.handleOnChange_, this);
+        this.boundHandleLeadChange_ = cr.bind(this.handleLeadChange_, this);
+      }
+
+      if (oldSm) {
+        oldSm.removeEventListener('change', this.boundHandleOnChange_);
+        oldSm.removeEventListener('leadItemChange', this.boundHandleLeadChange_);
+      }
+
+      this.selectionModel_ = sm;
+
+      if (sm) {
+        sm.addEventListener('change', this.boundHandleOnChange_);
+        sm.addEventListener('leadItemChange', this.boundHandleLeadChange_);
+      }
+    },
+
+    /**
+     * Convenience alias for selectionModel.selectedItem
+     * @type {cr.ui.ListItem}
+     */
+    get selectedItem() {
+      return this.selectionModel.selectedItem;
+    },
+    set selectedItem(selectedItem) {
+      this.selectionModel.selectedItem = selectedItem;
+    },
+
+    /**
+     * Convenience alias for selectionModel.selectedItems
+     * @type {!Array<cr.ui.ListItem>}
+     */
+    get selectedItems() {
+      return this.selectionModel.selectedItems;
+    },
+
+    /**
+     * The HTML elements representing the items. This is just all the element
+     * children but subclasses may override this to filter out certain elements.
+     * @type {HTMLCollection}
+     */
+    get items() {
+      return this.children;
+    },
+
+    add: function(listItem) {
+      this.appendChild(listItem);
+
+      var uid = cr.getUid(listItem);
+      this.uidToListItem_[uid] = listItem;
+
+      this.selectionModel.add(listItem);
+    },
+
+    addAt: function(listItem, index) {
+      this.insertBefore(listItem, this.items[index]);
+
+      var uid = cr.getUid(listItem);
+      this.uidToListItem_[uid] = listItem;
+
+      this.selectionModel.add(listItem);
+    },
+
+    remove: function(listItem) {
+      this.selectionModel.remove(listItem);
+
+      this.removeChild(listItem);
+
+      var uid = cr.getUid(listItem);
+      delete this.uidToListItem_[uid];
+    },
+
+    clear: function() {
+      this.innerHTML = '';
+      this.selectionModel.clear();
+    },
+
+    /**
+     * Initializes the element.
+     */
+    decorate: function() {
+      this.uidToListItem_ = {};
+
+      this.selectionModel = new ListSelectionModel(this);
+
+      this.addEventListener('mousedown', this.handleMouseDownUp_);
+      this.addEventListener('mouseup', this.handleMouseDownUp_);
+      this.addEventListener('keydown', this.handleKeyDown);
+      this.addEventListener('dblclick', this.handleDoubleClick_);
+
+      // Make list focusable
+      if (!this.hasAttribute('tabindex'))
+        this.tabIndex = 0;
+    },
+
+    /**
+     * Callback for mousedown and mouseup events.
+     * @param {Event} e The mouse event object.
+     * @private
+     */
+    handleMouseDownUp_: function(e) {
+      var target = e.target;
+      while (target && target.parentNode != this) {
+        target = target.parentNode;
+      }
+      this.selectionModel.handleMouseDownUp(e, target);
+    },
+
+    /**
+     * Callback for mousedown events.
+     * @param {Event} e The mouse event object.
+     * @private
+     */
+    handleMouseUp_: function(e) {
+      var target = e.target;
+      while (target && target.parentNode != this) {
+        target = target.parentNode;
+      }
+      if (target) {
+        this.selectionModel.handleMouseDown(e, target);
+      } else {
+        this.selectionModel.clear();
+      }
+    },
+
+
+    /**
+     * Handle a keydown event.
+     * @param {Event} e The keydown event.
+     * @return {boolean} Whether the key event was handled.
+     */
+    handleKeyDown: function(e) {
+      if (this.selectionModel.handleKeyDown(e))
+        return true;
+      if (e.keyIdentifier == 'Enter' && this.selectionModel.selectedItem) {
+        cr.dispatchSimpleEvent(this, 'activate');
+        return true;
+      }
+      return false;
+    },
+
+    /**
+     * Handler for double clicking. When the user double clicks on a selected
+     * item we dispatch an {@code activate} event.
+     * @param {Event} e The mouse event object.
+     * @private
+     */
+    handleDoubleClick_: function(e) {
+      if (e.button == 0 && this.selectionModel.selectedItem) {
+        cr.dispatchSimpleEvent(this, 'activate');
+      }
+    },
+
+    /**
+     * Callback from the selection model. We dispatch {@code change} events
+     * when the selection changes.
+     * @param {!cr.Event} e Event with change info.
+     * @private
+     */
+    handleOnChange_: function(ce) {
+      ce.changes.forEach(function(change) {
+        var listItem = this.uidToListItem_[change.uid];
+        listItem.selected = change.selected;
+      }, this);
+
+      cr.dispatchSimpleEvent(this, 'change');
+    },
+
+    /**
+     * Handles a change of the lead item from the selection model.
+     * @property {Event} pe The property change event.
+     * @private
+     */
+    handleLeadChange_: function(pe) {
+      if (pe.oldValue) {
+        pe.oldValue.lead = false;
+      }
+      if (pe.newValue) {
+        pe.newValue.lead = true;
+      }
+    },
+
+    /**
+     * Gets a unique ID for an item. This needs to be unique to the list but
+     * does not have to be gloabally unique. This uses {@code cr.getUid} by
+     * default. Override to provide a more efficient way to get the unique ID.
+     * @param {cr.ui.ListItem} item The item to get the unique ID for.
+     * @return
+     */
+    itemToUid: function(item) {
+      return cr.getUid(item);
+    }
+  };
+
+  return {
+    List: List
+  }
+});
diff --git a/resources/bookmark_manager/js/cr/ui/listitem.js b/resources/bookmark_manager/js/cr/ui/listitem.js
new file mode 100644
index 0000000..0cd8826
--- /dev/null
+++ b/resources/bookmark_manager/js/cr/ui/listitem.js
@@ -0,0 +1,58 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('cr.ui', function() {
+
+  /**
+   * Creates a new list item element.
+   * @param {string} opt_label The text label for the item.
+   * @constructor
+   * @extends {HTMLLIElement}
+   */
+  var ListItem = cr.ui.define('li');
+
+  ListItem.prototype = {
+    __proto__: HTMLLIElement.prototype,
+
+    /**
+     * Plain text label.
+     * @type {string}
+     */
+    get label() {
+      return this.textContent;
+    },
+    set label(label) {
+      this.textContent = label;
+    },
+
+    /**
+     * Whether the item is the lead in a selection. Setting this does not update
+     * the underlying selection model. This is only used for display purpose.
+     * @type {boolean}
+     */
+    get lead() {
+      return this.hasAttribute('lead');
+    },
+    set lead(lead) {
+      if (lead) {
+        this.setAttribute('lead', '');
+        this.scrollIntoViewIfNeeded(false);
+      } else {
+        this.removeAttribute('lead');
+      }
+    },
+
+    /**
+     * Called when an element is decorated as a list item.
+     */
+    decorate: function() {
+    }
+  };
+
+  cr.defineProperty(ListItem, 'selected', cr.PropertyKind.BOOL_ATTR);
+
+  return {
+    ListItem: ListItem
+  };
+});
diff --git a/resources/bookmark_manager/js/cr/ui/listselectionmodel.js b/resources/bookmark_manager/js/cr/ui/listselectionmodel.js
new file mode 100644
index 0000000..385c80f
--- /dev/null
+++ b/resources/bookmark_manager/js/cr/ui/listselectionmodel.js
@@ -0,0 +1,442 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('cr.ui', function() {
+  const Event = cr.Event;
+  const EventTarget = cr.EventTarget;
+
+  /**
+   * Creates a new selection model that is to be used with lists. This is
+   * implemented for vertical lists but changing the behavior for horizontal
+   * lists or icon views is a matter of overriding {@code getItemBefore},
+   * {@code getItemAfter}, {@code getItemAbove} as well as {@code getItemBelow}.
+   *
+   * @constructor
+   * @extends {!cr.EventTarget}
+   */
+  function ListSelectionModel(list) {
+    this.list = list;
+    this.selectedItems_ = {};
+  }
+
+  ListSelectionModel.prototype = {
+    __proto__: EventTarget.prototype,
+
+    /**
+     * Returns the item below (y axis) the given element.
+     * @param {*} item The item to get the item below.
+     * @return {*} The item below or null if not found.
+     */
+    getItemBelow: function(item) {
+      return item.nextElementSibling;
+    },
+
+    /**
+     * Returns the item above (y axis) the given element.
+     * @param {*} item The item to get the item above.
+     * @return {*} The item below or null if not found.
+     */
+    getItemAbove: function(item) {
+      return item.previousElementSibling;
+    },
+
+    /**
+     * Returns the item before (x axis) the given element. This returns null
+     * by default but override this for icon view and horizontal selection
+     * models.
+     *
+     * @param {*} item The item to get the item before.
+     * @return {*} The item before or null if not found.
+     */
+    getItemBefore: function(item) {
+      return null;
+    },
+
+    /**
+     * Returns the item after (x axis) the given element. This returns null
+     * by default but override this for icon view and horizontal selection
+     * models.
+     *
+     * @param {*} item The item to get the item after.
+     * @return {*} The item after or null if not found.
+     */
+    getItemAfter: function(item) {
+      return null;
+    },
+
+    /**
+     * Returns the next list item. This is the next logical and should not
+     * depend on any kind of layout of the list.
+     * @param {*} item The item to get the next item for.
+     * @return {*} The next item or null if not found.
+     */
+    getNextItem: function(item) {
+      return item.nextElementSibling;
+    },
+
+    /**
+     * Returns the prevous list item. This is the previous logical and should
+     * not depend on any kind of layout of the list.
+     * @param {*} item The item to get the previous item for.
+     * @return {*} The previous item or null if not found.
+     */
+    getPreviousItem: function(item) {
+      return item.previousElementSibling;
+    },
+
+    /**
+     * @return {*} The first item.
+     */
+    getFirstItem: function() {
+      return this.list.firstElementChild;
+    },
+
+    /**
+     * @return {*} The last item.
+     */
+    getLastItem: function() {
+      return this.list.lastElementChild;
+    },
+
+    /**
+     * Called by the view when the user does a mousedown or mouseup on the list.
+     * @param {!Event} e The browser mousedown event.
+     * @param {*} item The item that was under the mouse pointer, null if none.
+     */
+    handleMouseDownUp: function(e, item) {
+      var anchorItem = this.anchorItem;
+
+      this.beginChange_();
+
+      if (!item && !e.ctrlKey && !e.shiftKey && !e.metaKey) {
+        this.clear();
+      } else {
+        var isDown = e.type == 'mousedown';
+        if (!cr.isMac && e.ctrlKey) {
+          // Handle ctrlKey on mouseup
+          if (!isDown) {
+            // toggle the current one and make it anchor item
+            this.setItemSelected(item, !this.getItemSelected(item));
+            this.leadItem = item;
+            this.anchorItem = item;
+          }
+        } else if (e.shiftKey && anchorItem && anchorItem != item) {
+          // Shift is done in mousedown
+          if (isDown) {
+            this.clearAllSelected_();
+            this.leadItem = item;
+            this.selectRange(anchorItem, item);
+          }
+        } else {
+          // Right click for a context menu need to not clear the selection.
+          var isRightClick = e.button == 2;
+
+          // If the item is selected this is handled in mouseup.
+          var itemSelected = this.getItemSelected(item);
+          if ((itemSelected && !isDown || !itemSelected && isDown) &&
+              !(itemSelected && isRightClick)) {
+            this.clearAllSelected_();
+            this.setItemSelected(item, true);
+            this.leadItem = item;
+            this.anchorItem = item;
+          }
+        }
+      }
+
+      this.endChange_();
+    },
+
+    /**
+     * Called by the view when it recieves a keydown event.
+     * @param {Event} e The keydown event.
+     */
+    handleKeyDown: function(e) {
+      var newItem = null;
+      var leadItem = this.leadItem;
+      var prevent = true;
+
+      // Ctrl/Meta+A
+      if (e.keyCode == 65 &&
+          (cr.isMac && e.metaKey || !cr.isMac && e.ctrlKey)) {
+        this.selectAll();
+        e.preventDefault();
+        return;
+      }
+
+      // Space
+      if (e.keyCode == 32) {
+        if (leadItem != null) {
+          var selected = this.getItemSelected(leadItem);
+          if (e.ctrlKey || !selected) {
+            this.beginChange_();
+            this.setItemSelected(leadItem, !selected);
+            this.endChange_();
+            return;
+          }
+        }
+      }
+
+      switch (e.keyIdentifier) {
+        case 'Home':
+          newItem = this.getFirstItem();
+          break;
+        case 'End':
+          newItem = this.getLastItem();
+          break;
+        case 'Up':
+          newItem = !leadItem  ?
+              this.getLastItem() : this.getItemAbove(leadItem);
+          break;
+        case 'Down':
+          newItem = !leadItem ?
+              this.getFirstItem() : this.getItemBelow(leadItem);
+          break;
+        case 'Left':
+          newItem = !leadItem ?
+              this.getLastItem() : this.getItemBefore(leadItem);
+          break;
+        case 'Right':
+          newItem = !leadItem ?
+              this.getFirstItem() : this.getItemAfter(leadItem);
+          break;
+        default:
+          prevent = false;
+      }
+
+      if (newItem) {
+        this.beginChange_();
+
+        this.leadItem = newItem;
+        if (e.shiftKey) {
+          var anchorItem = this.anchorItem;
+          this.clearAllSelected_();
+          if (!anchorItem) {
+            this.setItemSelected(newItem, true);
+            this.anchorItem = newItem;
+          } else {
+            this.selectRange(anchorItem, newItem);
+          }
+        } else if (e.ctrlKey && !cr.isMac) {
+          // Setting the lead item is done above
+          // Mac does not allow you to change the lead.
+        } else {
+          this.clearAllSelected_();
+          this.setItemSelected(newItem, true);
+          this.anchorItem = newItem;
+        }
+
+        this.endChange_();
+
+        if (prevent)
+          e.preventDefault();
+      }
+    },
+
+    /**
+     * @type {!Array} The selected items.
+     */
+    get selectedItems() {
+      return Object.keys(this.selectedItems_).map(function(uid) {
+        return this.selectedItems_[uid];
+      }, this);
+    },
+    set selectedItems(selectedItems) {
+      this.beginChange_();
+      this.clearAllSelected_();
+      for (var i = 0; i < selectedItems.length; i++) {
+        this.setItemSelected(selectedItems[i], true);
+      }
+      this.leadItem = this.anchorItem = selectedItems[0] || null;
+      this.endChange_();
+    },
+
+    /**
+     * Convenience getter which returns the first selected item.
+     * @type {*}
+     */
+    get selectedItem() {
+      for (var uid in this.selectedItems_) {
+        return this.selectedItems_[uid];
+      }
+      return null;
+    },
+    set selectedItem(selectedItem) {
+      this.beginChange_();
+      this.clearAllSelected_();
+      if (selectedItem) {
+        this.selectedItems = [selectedItem];
+      } else {
+        this.leadItem = this.anchorItem = null;
+      }
+      this.endChange_();
+    },
+
+    /**
+     * Selects a range of items, starting with {@code start} and ends with
+     * {@code end}.
+     * @param {*} start The first item to select.
+     * @param {*} end The last item to select.
+     */
+    selectRange: function(start, end) {
+      // Swap if starts comes after end.
+      if (start.compareDocumentPosition(end) & Node.DOCUMENT_POSITION_PRECEDING) {
+        var tmp = start;
+        start = end;
+        end = tmp;
+      }
+
+      this.beginChange_();
+
+      for (var item = start; item != end; item = this.getNextItem(item)) {
+        this.setItemSelected(item, true);
+      }
+      this.setItemSelected(end, true);
+
+      this.endChange_();
+    },
+
+    /**
+     * Selects all items.
+     */
+    selectAll: function() {
+      this.selectRange(this.getFirstItem(), this.getLastItem());
+    },
+
+    /**
+     * Clears the selection
+     */
+    clear: function() {
+      this.beginChange_();
+      this.clearAllSelected_();
+      this.endChange_();
+    },
+
+    /**
+     * Clears the selection and updates the view.
+     * @private
+     */
+    clearAllSelected_: function() {
+      for (var uid in this.selectedItems_) {
+        this.setItemSelected(this.selectedItems_[uid], false);
+      }
+    },
+
+    /**
+     * Sets the selecte state for an item.
+     * @param {*} item The item to set the selected state for.
+     * @param {boolean} b Whether to select the item or not.
+     */
+    setItemSelected: function(item, b) {
+      var uid = this.list.itemToUid(item);
+      var oldSelected = uid in this.selectedItems_;
+      if (oldSelected == b)
+        return;
+
+      if (b)
+        this.selectedItems_[uid] = item;
+      else
+        delete this.selectedItems_[uid];
+
+      this.beginChange_();
+
+      // Changing back?
+      if (uid in this.changedUids_ && this.changedUids_[uid] == !b) {
+        delete this.changedUids_[uid];
+      } else {
+        this.changedUids_[uid] = b;
+      }
+
+      // End change dispatches an event which in turn may update the view.
+      this.endChange_();
+    },
+
+    /**
+     * Whether a given item is selected or not.
+     * @param {*} item The item to check.
+     * @return {boolean} Whether an item is selected.
+     */
+    getItemSelected: function(item) {
+      var uid = this.list.itemToUid(item);
+      return uid in this.selectedItems_;
+    },
+
+    /**
+     * This is used to begin batching changes. Call {@code endChange_} when you
+     * are done making changes.
+     * @private
+     */
+    beginChange_: function() {
+      if (!this.changeCount_) {
+        this.changeCount_ = 0;
+        this.changedUids_ = {};
+      }
+      this.changeCount_++;
+    },
+
+    /**
+     * Call this after changes are done and it will dispatch a change event if
+     * any changes were actually done.
+     * @private
+     */
+    endChange_: function() {
+      this.changeCount_--;
+      if (!this.changeCount_) {
+        var uids = Object.keys(this.changedUids_);
+        if (uids.length) {
+          var e = new Event('change');
+          e.changes = uids.map(function(uid) {
+            return {
+              uid: uid,
+              selected: this.changedUids_[uid]
+            };
+          }, this);
+          this.dispatchEvent(e);
+        }
+        delete this.changedUids_;
+        delete this.changeCount_;
+      }
+    },
+
+    /**
+     * Called when an item is removed from the lisst.
+     * @param {cr.ui.ListItem} item The list item that was removed.
+     */
+    remove: function(item) {
+      if (item == this.leadItem)
+        this.leadItem = this.getNextItem(item) || this.getPreviousItem(item);
+      if (item == this.anchorItem)
+        this.anchorItem = this.getNextItem(item) || this.getPreviousItem(item);
+
+      // Deselect when removing items.
+      if (this.getItemSelected(item))
+        this.setItemSelected(item, false);
+    },
+
+    /**
+     * Called when an item was added to the list.
+     * @param {cr.ui.ListItem} item The list item to add.
+     */
+    add: function(item) {
+      // We could (should?) check if the item is selected here and update the
+      // selection model.
+    }
+  };
+
+  /**
+   * The anchorItem is used with multiple selection.
+   * @type {*}
+   */
+  cr.defineProperty(ListSelectionModel, 'anchorItem', cr.PropertyKind.JS, null);
+
+  /**
+   * The leadItem is used with multiple selection and it is the item that the
+   * user is moving uysing the arrow keys.
+   * @type {*}
+   */
+  cr.defineProperty(ListSelectionModel, 'leadItem', cr.PropertyKind.JS, null);
+
+  return {
+    ListSelectionModel: ListSelectionModel
+  };
+});
diff --git a/resources/bookmark_manager/js/cr/ui/menu.js b/resources/bookmark_manager/js/cr/ui/menu.js
new file mode 100644
index 0000000..1145d0f
--- /dev/null
+++ b/resources/bookmark_manager/js/cr/ui/menu.js
@@ -0,0 +1,157 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('cr.ui', function() {
+
+  const MenuItem = cr.ui.MenuItem;
+
+  /**
+   * Creates a new menu element.
+   * @param {Object=} opt_propertyBag Optional properties.
+   * @constructor
+   * @extends {HTMLMenuElement}
+   */
+  var Menu = cr.ui.define('menu');
+
+  Menu.prototype = {
+    __proto__: HTMLMenuElement.prototype,
+
+    /**
+     * Initializes the menu element.
+     */
+    decorate: function() {
+      this.addEventListener('mouseover', this.handleMouseOver_);
+      this.addEventListener('mouseout', this.handleMouseOut_);
+
+      // Decorate the children as menu items.
+      var children = this.children;
+      for (var i = 0, child; child = children[i]; i++) {
+        cr.ui.decorate(child, MenuItem);
+      }
+    },
+
+    /**
+     * Walks up the ancestors until a menu item belonging to this menu is found.
+     * @param {Element} el
+     * @return {cr.ui.MenuItem} The found menu item or null.
+     * @private
+     */
+    findMenuItem_: function(el) {
+      while (el && el.parentNode != this) {
+        el = el.parentNode;
+      }
+      return el;
+    },
+
+    /**
+     * Handles mouseover events and selects the hovered item.
+     * @param {Event} e The mouseover event.
+     * @private
+     */
+    handleMouseOver_: function(e) {
+      var overItem = this.findMenuItem_(e.target);
+      this.selectedItem = overItem;
+    },
+
+    /**
+     * Handles mouseout events and deselects any selected item.
+     * @param {Event} e The mouseout event.
+     * @private
+     */
+    handleMouseOut_: function(e) {
+      this.selectedItem = null;
+    },
+
+    /**
+     * The index of the selected item.
+     * @type {boolean}
+     */
+    // getter and default value is defined using cr.defineProperty.
+    set selectedIndex(selectedIndex) {
+      if (this.selectedIndex_ != selectedIndex) {
+        var oldSelectedItem = this.selectedItem;
+        this.selectedIndex_ = selectedIndex;
+        if (oldSelectedItem)
+          oldSelectedItem.selected = false;
+        var item = this.selectedItem;
+        if (item)
+          item.selected = true;
+
+        cr.dispatchSimpleEvent(this, 'change');
+      }
+    },
+
+    /**
+     * The selected menu item or null if none.
+     * @type {cr.ui.MenuItem}
+     */
+    get selectedItem() {
+      return this.children[this.selectedIndex];
+    },
+    set selectedItem(item) {
+      var index = Array.prototype.indexOf.call(this.children, item);
+      this.selectedIndex = index;
+    },
+
+    /**
+     * This is the function that handles keyboard navigation. This is usually
+     * called by the element responsible for managing the menu.
+     * @param {Event} e The keydown event object.
+     * @return {boolean} Whether the event was handled be the menu.
+     */
+    handleKeyDown: function(e) {
+      var item = this.selectedItem;
+
+      var self = this;
+      function selectNextVisible(m) {
+        var children = self.children;
+        var len = children.length;
+        var i = self.selectedIndex;
+        if (i == -1 && m == -1) {
+          // Edge case when we need to go the last item fisrt.
+          i = 0;
+        }
+        while (true) {
+          i = (i + m + len) % len;
+          item = children[i];
+          if (item && !item.isSeparator() && !item.hidden)
+            break;
+        }
+        if (item)
+          self.selectedIndex = i;
+      }
+
+      switch (e.keyIdentifier) {
+        case 'Down':
+          selectNextVisible(1);
+          return true;
+        case 'Up':
+          selectNextVisible(-1);
+          return true;
+        case 'Enter':
+        case 'U+0020': // Space
+          if (item) {
+            if (cr.dispatchSimpleEvent(item, 'activate', true, true)) {
+              if (item.command)
+                item.command.execute();
+            }
+          }
+          return true;
+      }
+
+      return false;
+    }
+  };
+
+  /**
+   * The selected menu item.
+   * @type {number}
+   */
+  cr.defineProperty(Menu, 'selectedIndex', cr.PropertyKind.JS, -1);
+
+  // Export
+  return {
+    Menu: Menu
+  };
+});
diff --git a/resources/bookmark_manager/js/cr/ui/menubutton.js b/resources/bookmark_manager/js/cr/ui/menubutton.js
new file mode 100644
index 0000000..469cfd8
--- /dev/null
+++ b/resources/bookmark_manager/js/cr/ui/menubutton.js
@@ -0,0 +1,166 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('cr.ui', function() {
+  const Menu = cr.ui.Menu;
+
+  /**
+   * Creates a new menu button element.
+   * @param {Object=} opt_propertyBag Optional properties.
+   * @constructor
+   * @extends {HTMLButtonElement}
+   */
+  var MenuButton = cr.ui.define('button');
+
+  MenuButton.prototype = {
+    __proto__: HTMLButtonElement.prototype,
+
+    /**
+     * Initializes the menu button.
+     */
+    decorate: function() {
+      this.addEventListener('mousedown', this);
+      this.addEventListener('keydown', this);
+
+      var menu;
+      if ((menu = this.getAttribute('menu')))
+        this.menu = menu;
+    },
+
+    /**
+     * The menu associated with the menu button.
+     * @type {cr.ui.Menu}
+     */
+    get menu() {
+      return this.menu_;
+    },
+    set menu(menu) {
+      if (typeof menu == 'string' && menu[0] == '#') {
+        menu = this.ownerDocument.getElementById(menu.slice(1));
+        cr.ui.decorate(menu, Menu);
+      }
+
+      this.menu_ = menu;
+      if (menu) {
+        if (menu.id)
+          this.setAttribute('menu', '#' + menu.id);
+      }
+    },
+
+    /**
+     * Handles event callbacks.
+     * @param {Event} e The event object.
+     */
+    handleEvent: function(e) {
+      if (!this.menu)
+        return;
+
+      switch (e.type) {
+        case 'mousedown':
+          if (e.currentTarget == this.ownerDocument) {
+            if (!this.contains(e.target) && !this.menu.contains(e.target))
+              this.hideMenu();
+            else
+              e.preventDefault();
+          } else {
+            if (this.isMenuShown()) {
+              this.hideMenu();
+            } else {
+              this.showMenu();
+              // Prevent the button from stealing focus on mousedown.
+              e.preventDefault();
+            }
+          }
+          break;
+        case 'keydown':
+          this.handleKeyDown(e);
+          // If the menu is visible we let it handle all the keyboard events.
+          if (this.isMenuShown() && e.currentTarget == this.ownerDocument) {
+            this.menu.handleKeyDown(e);
+            e.preventDefault();
+            e.stopPropagation();
+          }
+          break;
+
+        case 'activate':
+        case 'blur':
+          this.hideMenu();
+          break;
+      }
+    },
+
+    /**
+     * Shows the menu.
+     */
+    showMenu: function() {
+      this.menu.style.display = 'block';
+      // when the menu is shown we steal all keyboard events.
+      this.ownerDocument.addEventListener('keydown', this, true);
+      this.ownerDocument.addEventListener('mousedown', this, true);
+      this.ownerDocument.addEventListener('blur', this, true);
+      this.menu.addEventListener('activate', this);
+      this.positionMenu_();
+    },
+
+    /**
+     * Hides the menu.
+     */
+    hideMenu: function() {
+      this.menu.style.display = 'none';
+      this.ownerDocument.removeEventListener('keydown', this, true);
+      this.ownerDocument.removeEventListener('mousedown', this, true);
+      this.ownerDocument.removeEventListener('blur', this, true);
+      this.menu.removeEventListener('activate', this);
+      this.menu.selectedIndex = -1;
+    },
+
+    /**
+     * Whether the menu is shown.
+     */
+    isMenuShown: function() {
+      return window.getComputedStyle(this.menu).display != 'none';
+    },
+
+    /**
+     * Positions the menu below the menu button. At this point we do not use any
+     * advanced positioning logic to ensure the menu fits in the viewport.
+     * @private
+     */
+    positionMenu_: function() {
+      var buttonRect = this.getBoundingClientRect();
+      this.menu.style.top = buttonRect.bottom + 'px';
+      if (getComputedStyle(this).direction == 'rtl') {
+        var menuRect = this.menu.getBoundingClientRect();
+        this.menu.style.left = buttonRect.right - menuRect.width + 'px';
+      } else {
+        this.menu.style.left = buttonRect.left + 'px';
+      }
+    },
+
+    /**
+     * Handles the keydown event for the menu button.
+     */
+    handleKeyDown: function(e) {
+      switch (e.keyIdentifier) {
+        case 'Down':
+        case 'Up':
+        case 'Enter':
+        case 'U+0020': // Space
+          if (!this.isMenuShown())
+            this.showMenu();
+          e.preventDefault();
+          break;
+        case 'Esc':
+        case 'U+001B': // Maybe this is remote desktop playing a prank?
+          this.hideMenu();
+          break;
+      }
+    }
+  };
+
+  // Export
+  return {
+    MenuButton: MenuButton
+  };
+});
diff --git a/resources/bookmark_manager/js/cr/ui/menuitem.js b/resources/bookmark_manager/js/cr/ui/menuitem.js
new file mode 100644
index 0000000..5c66f17
--- /dev/null
+++ b/resources/bookmark_manager/js/cr/ui/menuitem.js
@@ -0,0 +1,147 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('cr.ui', function() {
+  const Command = cr.ui.Command;
+
+  /**
+   * Creates a new menu item element.
+   * @param {Object=} opt_propertyBag Optional properties.
+   * @constructor
+   * @extends {HTMLButtonElement}
+   */
+  var MenuItem = cr.ui.define('button');
+
+  /**
+   * Creates a new menu separator element.
+   * @return {cr.ui.MenuItem}
+   */
+  MenuItem.createSeparator = function() {
+    var el = cr.doc.createElement('hr');
+    MenuItem.decorate(el);
+    return el;
+  };
+
+  MenuItem.prototype = {
+    __proto__: HTMLButtonElement.prototype,
+
+    /**
+     * Initializes the menu item.
+     */
+    decorate: function() {
+      var commandId;
+      if ((commandId = this.getAttribute('command')))
+        this.command = commandId;
+
+      this.addEventListener('mouseup', this.handleMouseUp_);
+    },
+
+    /**
+     * The command associated with this menu item. If this is set to a string
+     * of the form "#element-id" then the element is looked up in the document
+     * of the command.
+     * @type {cr.ui.Command}
+     */
+    command_: null,
+    get command() {
+      return this.command_;
+    },
+    set command(command) {
+      if (this.command_) {
+        this.command_.removeEventListener('labelChange', this);
+        this.command_.removeEventListener('disabledChange', this);
+        this.command_.removeEventListener('hiddenChange', this);
+      }
+
+      if (typeof command == 'string' && command[0] == '#') {
+        command = this.ownerDocument.getElementById(command.slice(1));
+        cr.ui.decorate(command, Command);
+      }
+
+      this.command_ = command;
+      if (command) {
+        if (command.id)
+          this.setAttribute('command', '#' + command.id);
+
+        this.label = command.label;
+        this.disabled = command.disabled;
+        this.hidden = command.hidden;
+
+        this.command_.addEventListener('labelChange', this);
+        this.command_.addEventListener('disabledChange', this);
+        this.command_.addEventListener('hiddenChange', this);
+      }
+    },
+
+    /**
+     * The text label.
+     * @type {string}
+     */
+    get label() {
+      return this.textContent;
+    },
+    set label(label) {
+      this.textContent = label;
+    },
+
+    /**
+     * @return {boolean} Whether the menu item is a separator.
+     */
+    isSeparator: function() {
+      return this.tagName == 'HR';
+    },
+
+    /**
+     * Handles mouseup events. This dispatches an active event and if there
+     * is an assiciated command then that is executed.
+     * @param {Event} The mouseup event object.
+     * @private
+     */
+    handleMouseUp_: function(e) {
+      if (!this.disabled && !this.isSeparator()) {
+        // Dispatch command event followed by executing the command object.
+        if (cr.dispatchSimpleEvent(this, 'activate', true, true)) {
+          var command = this.command;
+          if (command)
+            command.execute();
+        }
+      }
+    },
+
+    /**
+     * Handles changes to the associated command.
+     * @param {Event} e The event object.
+     */
+    handleEvent: function(e) {
+      switch (e.type) {
+        case 'disabledChange':
+          this.disabled = this.command.disabled;
+          break;
+        case 'hiddenChange':
+          this.hidden = this.command.hidden;
+          break;
+        case 'labelChange':
+          this.label = this.command.label;
+          break;
+      }
+    }
+  };
+
+  /**
+   * Whether the menu item is hidden or not.
+   * @type {boolean}
+   */
+  cr.defineProperty(MenuItem, 'hidden', cr.PropertyKind.BOOL_ATTR);
+
+  /**
+   * Whether the menu item is selected or not.
+   * @type {boolean}
+   */
+  cr.defineProperty(MenuItem, 'selected', cr.PropertyKind.BOOL_ATTR);
+
+  // Export
+  return {
+    MenuItem: MenuItem
+  };
+});
diff --git a/resources/bookmark_manager/js/cr/ui/tree.js b/resources/bookmark_manager/js/cr/ui/tree.js
new file mode 100644
index 0000000..6f7088f
--- /dev/null
+++ b/resources/bookmark_manager/js/cr/ui/tree.js
@@ -0,0 +1,597 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('cr.ui', function() {
+  // require cr.ui.define
+  // require cr.ui.limitInputWidth
+
+  /**
+   * Helper function that finds the first ancestor tree item.
+   * @param {!Element} el The element to start searching from.
+   * @return {cr.ui.TreeItem} The found tree item or null if not found.
+   */
+  function findTreeItem(el) {
+    while (el && !(el instanceof TreeItem)) {
+      el = el.parentNode;
+    }
+    return el;
+  }
+
+  /**
+   * Creates a new tree element.
+   * @param {Object=} opt_propertyBag Optional properties.
+   * @constructor
+   * @extends {HTMLElement}
+   */
+  var Tree = cr.ui.define('tree');
+
+  Tree.prototype = {
+    __proto__: HTMLElement.prototype,
+
+    /**
+     * Initializes the element.
+     */
+    decorate: function() {
+      // Make list focusable
+      if (!this.hasAttribute('tabindex'))
+        this.tabIndex = 0;
+
+      this.addEventListener('click', this.handleClick);
+      this.addEventListener('mousedown', this.handleMouseDown);
+      this.addEventListener('dblclick', this.handleDblClick);
+      this.addEventListener('keydown', this.handleKeyDown);
+    },
+
+    /**
+     * Returns the tree item that are children of this tree.
+     */
+    get items() {
+      return this.children;
+    },
+
+    /**
+     * Adds a tree item to the tree.
+     * @param {!cr.ui.TreeItem} treeItem The item to add.
+     */
+    add: function(treeItem) {
+      this.appendChild(treeItem);
+    },
+
+    /**
+     * Adds a tree item at the given index.
+     * @param {!cr.ui.TreeItem} treeItem The item to add.
+     * @param {number} index The index where we want to add the item.
+     */
+    addAt: function(treeItem, index) {
+      this.insertBefore(treeItem, this.children[index]);
+    },
+
+    /**
+     * Removes a tree item child.
+     * @param {!cr.ui.TreeItem} treeItem The tree item to remove.
+     */
+    remove: function(treeItem) {
+      this.removeChild(treeItem);
+    },
+
+    /**
+     * Handles click events on the tree and forwards the event to the relevant
+     * tree items as necesary.
+     * @param {Event} e The click event object.
+     */
+    handleClick: function(e) {
+      var treeItem = findTreeItem(e.target);
+      if (treeItem)
+        treeItem.handleClick(e);
+    },
+
+    handleMouseDown: function(e) {
+      if (e.button == 2) // right
+        this.handleClick(e);
+    },
+
+    /**
+     * Handles double click events on the tree.
+     * @param {Event} e The dblclick event object.
+     */
+    handleDblClick: function(e) {
+      var treeItem = findTreeItem(e.target);
+      if (treeItem)
+        treeItem.expanded = !treeItem.expanded;
+    },
+
+    /**
+     * Handles keydown events on the tree and updates selection and exanding
+     * of tree items.
+     * @param {Event} e The click event object.
+     */
+    handleKeyDown: function(e) {
+      var itemToSelect;
+      if (e.ctrlKey)
+        return;
+
+      var item = this.selectedItem;
+
+      var rtl = window.getComputedStyle(item).direction == 'rtl';
+
+      switch (e.keyIdentifier) {
+        case 'Up':
+          itemToSelect = item ? getPrevious(item) :
+              this.items[this.items.length - 1];
+          break;
+        case 'Down':
+          itemToSelect = item ? getNext(item) :
+              this.items[0];
+          break;
+        case 'Left':
+        case 'Right':
+          // Don't let back/forward keyboard shortcuts be used.
+          if (!cr.isMac && e.altKey || cr.isMac && e.metaKey)
+            break;
+
+          if (e.keyIdentifier == 'Left' && !rtl ||
+              e.keyIdentifier == 'Right' && rtl) {
+            if (item.expanded)
+              item.expanded = false;
+            else
+              itemToSelect = findTreeItem(item.parentNode);
+          } else {
+            if (!item.expanded)
+              item.expanded = true;
+            else
+              itemToSelect = item.items[0];
+          }
+          break;
+        case 'Home':
+          itemToSelect = this.items[0];
+          break;
+        case 'End':
+          itemToSelect = this.items[this.items.length - 1];
+          break;
+      }
+
+      if (itemToSelect) {
+        itemToSelect.selected = true;
+        e.preventDefault();
+      }
+    },
+
+    /**
+     * The selected tree item or null if none.
+     * @type {cr.ui.TreeItem}
+     */
+    get selectedItem() {
+      return this.selectedItem_ || null;
+    },
+    set selectedItem(item) {
+      var oldSelectedItem = this.selectedItem_;
+      if (oldSelectedItem != item) {
+        // Set the selectedItem_ before deselecting the old item since we only
+        // want one change when moving between items.
+        this.selectedItem_ = item;
+
+        if (oldSelectedItem)
+          oldSelectedItem.selected = false;
+
+        if (item)
+          item.selected = true;
+
+        cr.dispatchSimpleEvent(this, 'change');
+      }
+    }
+  };
+
+  /**
+   * This is used as a blueprint for new tree item elements.
+   * @type {!HTMLElement}
+   */
+  var treeItemProto = (function() {
+    var treeItem = cr.doc.createElement('div');
+    treeItem.className = 'tree-item';
+    treeItem.innerHTML = '<div class=tree-row>' +
+        '<span class=expand-icon></span>' +
+        '<span class=tree-label></span>' +
+        '</div>' +
+        '<div class=tree-children></div>';
+    return treeItem;
+  })();
+
+  /**
+   * Creates a new tree item.
+   * @param {Object=} opt_propertyBag Optional properties.
+   * @constructor
+   * @extends {HTMLElement}
+   */
+  var TreeItem = cr.ui.define(function() {
+    return treeItemProto.cloneNode(true);
+  });
+
+  TreeItem.prototype = {
+    __proto__: HTMLElement.prototype,
+
+    /**
+     * Initializes the element.
+     */
+    decorate: function() {
+
+    },
+
+    /**
+     * The tree items children.
+     */
+    get items() {
+      return this.lastElementChild.children;
+    },
+
+    /**
+     * Adds a tree item as a child.
+     * @param {!cr.ui.TreeItem} child The child to add.
+     */
+    add: function(child) {
+      this.addAt(child, 0xffffffff);
+    },
+
+    /**
+     * Adds a tree item as a child at a given index.
+     * @param {!cr.ui.TreeItem} child The child to add.
+     * @param {number} index The index where to add the child.
+     */
+    addAt: function(child, index) {
+      this.lastElementChild.insertBefore(child, this.items[index]);
+      if (this.items.length == 1)
+        this.hasChildren_ = true;
+    },
+
+    /**
+     * Removes a child.
+     * @param {!cr.ui.TreeItem} child The tree item child to remove.
+     */
+    remove: function(child) {
+      // If we removed the selected item we should become selected.
+      var tree = this.tree;
+      var selectedItem = tree.selectedItem;
+      if (selectedItem && child.contains(selectedItem))
+        this.selected = true;
+
+      this.lastElementChild.removeChild(child);
+      if (this.items.length == 0)
+        this.hasChildren_ = false;
+    },
+
+    /**
+     * The parent tree item.
+     * @type {!cr.ui.Tree|cr.ui.TreeItem}
+     */
+    get parentItem() {
+      var p = this.parentNode;
+      while (p && !(p instanceof TreeItem) && !(p instanceof Tree)) {
+        p = p.parentNode;
+      }
+      return p;
+    },
+
+    /**
+     * The tree that the tree item belongs to or null of no added to a tree.
+     * @type {cr.ui.Tree}
+     */
+    get tree() {
+      var t = this.parentItem;
+      while (t && !(t instanceof Tree)) {
+        t = t.parentItem;
+      }
+      return t;
+    },
+
+    /**
+     * Whether the tree item is expanded or not.
+     * @type {boolean}
+     */
+    get expanded() {
+      return this.hasAttribute('expanded');
+    },
+    set expanded(b) {
+      if (this.expanded == b)
+        return;
+
+      var treeChildren = this.lastElementChild;
+
+      if (b) {
+        if (this.mayHaveChildren_) {
+          this.setAttribute('expanded', '');
+          treeChildren.setAttribute('expanded', '');
+          cr.dispatchSimpleEvent(this, 'expand', true);
+          this.scrollIntoViewIfNeeded(false);
+        }
+      } else {
+        var tree = this.tree;
+        if (tree && !this.selected) {
+          var oldSelected = tree.selectedItem;
+          if (oldSelected && this.contains(oldSelected))
+            this.selected = true;
+        }
+        this.removeAttribute('expanded');
+        treeChildren.removeAttribute('expanded');
+        cr.dispatchSimpleEvent(this, 'collapse', true);
+      }
+    },
+
+    /**
+     * Expands all parent items.
+     */
+    reveal: function() {
+      var pi = this.parentItem;
+      while (pi && !(pi instanceof Tree)) {
+        pi.expanded = true;
+        pi = pi.parentItem;
+      }
+    },
+
+    /**
+     * The element representing the row that gets highlighted.
+     * @type {!HTMLElement}
+     */
+    get rowElement() {
+      return this.firstElementChild;
+    },
+
+    /**
+     * The element containing the label text and the icon.
+     * @type {!HTMLElement}
+     */
+    get labelElement() {
+      return this.firstElementChild.lastElementChild;
+    },
+
+    /**
+     * The label text.
+     * @type {string}
+     */
+    get label() {
+      return this.labelElement.textContent;
+    },
+    set label(s) {
+      this.labelElement.textContent = s;
+    },
+
+    /**
+     * The URL for the icon.
+     * @type {string}
+     */
+    get icon() {
+      return window.getComputedStyle(this.labelElement).
+          backgroundImage.slice(4, -1);
+    },
+    set icon(icon) {
+      return this.labelElement.style.backgroundImage = url(icon);
+    },
+
+    /**
+     * Whether the tree item is selected or not.
+     * @type {boolean}
+     */
+    get selected() {
+      return this.hasAttribute('selected');
+    },
+    set selected(b) {
+      if (this.selected == b)
+        return;
+      var rowItem = this.firstElementChild;
+      var tree = this.tree;
+      if (b) {
+        this.setAttribute('selected', '');
+        rowItem.setAttribute('selected', '');
+        this.labelElement.scrollIntoViewIfNeeded(false);
+        if (tree)
+          tree.selectedItem = this;
+      } else {
+        this.removeAttribute('selected');
+        rowItem.removeAttribute('selected');
+        if (tree && tree.selectedItem == this)
+          tree.selectedItem = null;
+      }
+    },
+
+    /**
+     * Whether the tree item has children.
+     * @type {boolean}
+     */
+    get mayHaveChildren_() {
+      return this.hasAttribute('may-have-children');
+    },
+    set mayHaveChildren_(b) {
+      var rowItem = this.firstElementChild;
+      if (b) {
+        this.setAttribute('may-have-children', '');
+        rowItem.setAttribute('may-have-children', '');
+      } else {
+        this.removeAttribute('may-have-children');
+        rowItem.removeAttribute('may-have-children');
+      }
+    },
+
+    /**
+     * Whether the tree item has children.
+     * @type {boolean}
+     */
+    get hasChildren() {
+      return !!this.items[0];
+    },
+
+    /**
+     * Whether the tree item has children.
+     * @type {boolean}
+     * @private
+     */
+    set hasChildren_(b) {
+      var rowItem = this.firstElementChild;
+      this.setAttribute('has-children', b);
+      rowItem.setAttribute('has-children', b);
+      if (b)
+        this.mayHaveChildren_ = true;
+    },
+
+    /**
+     * Called when the user clicks on a tree item. This is forwarded from the
+     * cr.ui.Tree.
+     * @param {Event} e The click event.
+     */
+    handleClick: function(e) {
+      if (e.target.className == 'expand-icon')
+        this.expanded = !this.expanded;
+      else
+        this.selected = true;
+    },
+
+    /**
+     * Makes the tree item user editable. If the user renamed the item a
+     * bubbling {@code rename} event is fired.
+     * @type {boolean}
+     */
+    set editing(editing) {
+      var oldEditing = this.editing;
+      if (editing == oldEditing)
+        return;
+
+      var self = this;
+      var labelEl = this.labelElement;
+      var text = this.label;
+      var input;
+
+      // Handles enter and escape which trigger reset and commit respectively.
+      function handleKeydown(e) {
+        // Make sure that the tree does not handle the key.
+        e.stopPropagation();
+
+        // Calling tree.focus blurs the input which will make the tree item
+        // non editable.
+        switch (e.keyIdentifier) {
+          case 'U+001B':  // Esc
+            input.value = text;
+            // fall through
+          case 'Enter':
+            self.tree.focus();
+        }
+      }
+
+      function stopPropagation(e) {
+        e.stopPropagation();
+      }
+
+      if (editing) {
+        this.selected = true;
+        this.setAttribute('editing', '');
+        this.draggable = false;
+
+        // We create an input[type=text] and copy over the label value. When
+        // the input loses focus we set editing to false again.
+        input = this.ownerDocument.createElement('input');
+        input.value = text;
+        if (labelEl.firstChild)
+          labelEl.replaceChild(input, labelEl.firstChild);
+        else
+          labelEl.appendChild(input);
+
+        input.addEventListener('keydown', handleKeydown);
+        input.addEventListener('blur', cr.bind(function() {
+          this.editing = false;
+        }, this));
+
+        // Make sure that double clicks do not expand and collapse the tree
+        // item.
+        var eventsToStop = ['mousedown', 'mouseup', 'contextmenu', 'dblclick'];
+        eventsToStop.forEach(function(type) {
+          input.addEventListener(type, stopPropagation);
+        });
+
+        input.focus();
+        input.select();
+        cr.ui.limitInputWidth(input, this.rowElement, 20);
+            // the padding and border of the tree-row
+
+        this.oldLabel_ = text;
+      } else {
+        this.removeAttribute('editing');
+        this.draggable = true;
+        input = labelEl.firstChild;
+        var value = input.value;
+        if (/^\s*$/.test(value)) {
+          labelEl.textContent = this.oldLabel_;
+        } else {
+          labelEl.textContent = value;
+          if (value != this.oldLabel_) {
+            cr.dispatchSimpleEvent(this, 'rename', true);
+          }
+        }
+        delete this.oldLabel_;
+      }
+    },
+
+    get editing() {
+      return this.hasAttribute('editing');
+    }
+  };
+
+  /**
+   * Helper function that returns the next visible tree item.
+   * @param {cr.ui.TreeItem} item The tree item.
+   * @retrun {cr.ui.TreeItem} The found item or null.
+   */
+  function getNext(item) {
+    if (item.expanded) {
+      var firstChild = item.items[0];
+      if (firstChild) {
+        return firstChild;
+      }
+    }
+
+    return getNextHelper(item);
+  }
+
+  /**
+   * Another helper function that returns the next visible tree item.
+   * @param {cr.ui.TreeItem} item The tree item.
+   * @retrun {cr.ui.TreeItem} The found item or null.
+   */
+  function getNextHelper(item) {
+    if (!item)
+      return null;
+
+    var nextSibling = item.nextElementSibling;
+    if (nextSibling) {
+      return nextSibling;
+    }
+    return getNextHelper(item.parentItem);
+  }
+
+  /**
+   * Helper function that returns the previous visible tree item.
+   * @param {cr.ui.TreeItem} item The tree item.
+   * @retrun {cr.ui.TreeItem} The found item or null.
+   */
+  function getPrevious(item) {
+    var previousSibling = item.previousElementSibling;
+    return previousSibling ? getLastHelper(previousSibling) : item.parentItem;
+  }
+
+  /**
+   * Helper function that returns the last visible tree item in the subtree.
+   * @param {cr.ui.TreeItem} item The item to find the last visible item for.
+   * @return {cr.ui.TreeItem} The found item or null.
+   */
+  function getLastHelper(item) {
+    if (!item)
+      return null;
+    if (item.expanded && item.hasChildren) {
+      var lastChild = item.items[item.items.length - 1];
+      return getLastHelper(lastChild);
+    }
+    return item;
+  }
+
+  // Export
+  return {
+    Tree: Tree,
+    TreeItem: TreeItem
+  };
+});
diff --git a/resources/bookmark_manager/js/i18ntemplate.js b/resources/bookmark_manager/js/i18ntemplate.js
new file mode 100644
index 0000000..8166ddc
--- /dev/null
+++ b/resources/bookmark_manager/js/i18ntemplate.js
@@ -0,0 +1,104 @@
+/**
+ * @fileoverview This is a simple template engine inspired by JsTemplates
+ * optimized for i18n.
+ *
+ * It currently supports two handlers:
+ *
+ *   * i18n-content which sets the textContent of the element
+ *
+ *     <span i18n-content="myContent"></span>
+ *     i18nTemplate.process(element, {'myContent': 'Content'});
+ *
+ *   * i18n-values is a list of attribute-value or property-value pairs.
+ *     Properties are prefixed with a '.' and can contain nested properties.
+ *
+ *     <span i18n-values="title:myTitle;.style.fontSize:fontSize"></span>
+ *     i18nTemplate.process(element, {
+ *       'myTitle': 'Title',
+ *       'fontSize': '13px'
+ *     });
+ */
+
+var i18nTemplate = (function() {
+  /**
+   * This provides the handlers for the templating engine. The key is used as
+   * the attribute name and the value is the function that gets called for every
+   * single node that has this attribute.
+   * @type {Object}
+   */
+  var handlers = {
+    /**
+     * This handler sets the textContent of the element.
+     */
+    'i18n-content': function(element, attributeValue, obj) {
+      element.textContent = obj[attributeValue];
+    },
+
+    /**
+     * This is used to set HTML attributes and DOM properties,. The syntax is:
+     *   attributename:key;
+     *   .domProperty:key;
+     *   .nested.dom.property:key
+     */
+    'i18n-values': function(element, attributeValue, obj) {
+      var parts = attributeValue.replace(/\s/g, '').split(/;/);
+      for (var j = 0; j < parts.length; j++) {
+        var a = parts[j].match(/^([^:]+):(.+)$/);
+        if (a) {
+          var propName = a[1];
+          var propExpr = a[2];
+
+          // Ignore missing properties
+          if (propExpr in obj) {
+            var value = obj[propExpr];
+            if (propName.charAt(0) == '.') {
+              var path = propName.slice(1).split('.');
+              var object = element;
+              while (object && path.length > 1) {
+                object = object[path.shift()];
+              }
+              if (object) {
+                object[path] = value;
+                // In case we set innerHTML (ignoring others) we need to
+                // recursively check the content
+                if (path == 'innerHTML') {
+                  process(element, obj);
+                }
+              }
+            } else {
+              element.setAttribute(propName, value);
+            }
+          } else {
+            console.warn('i18n-values: Missing value for "' + propExpr + '"');
+          }
+        }
+      }
+    }
+  };
+
+  var attributeNames = [];
+  for (var key in handlers) {
+    attributeNames.push(key);
+  }
+  var selector = '[' + attributeNames.join('],[') + ']';
+
+  /**
+   * Processes a DOM tree with the {@code obj} map.
+   */
+  function process(node, obj) {
+    var elements = node.querySelectorAll(selector);
+    for (var element, i = 0; element = elements[i]; i++) {
+      for (var j = 0; j < attributeNames.length; j++) {
+        var name = attributeNames[j];
+        var att = element.getAttribute(name);
+        if (att != null) {
+          handlers[name](element, att, obj);
+        }
+      }
+    }
+  }
+
+  return {
+    process: process
+  };
+})();
diff --git a/resources/bookmark_manager/js/localstrings.js b/resources/bookmark_manager/js/localstrings.js
new file mode 100644
index 0000000..86f888b
--- /dev/null
+++ b/resources/bookmark_manager/js/localstrings.js
@@ -0,0 +1,55 @@
+// Copyright (c) 2009-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// TODO(arv): Namespace and share code with DOMUI
+
+/**
+ * The local strings get injected into the page usig a varaible named
+ * {@code templateData}. This class provides a simpler interface to access those
+ * strings.
+ * @constructor
+ */
+function LocalStrings() {
+}
+
+LocalStrings.prototype = {
+
+  /**
+   * The template data object.
+   * @type {Object}
+   */
+  templateData: null,
+
+  /**
+   * Gets a localized string by its id.
+   * @param {string} s The id of the string we want.
+   * @return {string} The localized string.
+   */
+  getString: function(id) {
+    return this.templateData[id] || '';
+  },
+
+  /**
+   * Returns a formatted localized string where all %s contents are replaced
+   * by the second argument and where $1 to $9 are replaced by the second to
+   * tenths arguments.
+   * @param {string} id The ID of the string we want.
+   * @param {string} v The string to include in the formatted string.
+   * @param {...string} The extra values to include in the fomatted output.
+   * @return {string} The formatted string.
+   */
+  getStringF: function(id, v, var_args) {
+    // The localized messages should contain $n but they also use %s from time
+    // to time so we support both until all the messages have been unified.
+    var s = this.getString(id);
+    var args = arguments;
+    return s.replace(/%s|\$[$1-9]/g, function(m) {
+      if (m == '%s')
+        return v;
+      if (m == '$$')
+        return '$';
+      return args[m[1]];
+    });
+  }
+};
diff --git a/resources/bookmark_manager/js/util.js b/resources/bookmark_manager/js/util.js
new file mode 100644
index 0000000..3fef5d2
--- /dev/null
+++ b/resources/bookmark_manager/js/util.js
@@ -0,0 +1,57 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * The global object.
+ * @param {!Object}
+ */
+const global = this;
+
+/**
+ * Alias for document.getElementById.
+ * @param {string} id The ID of the element to find.
+ * @return {HTMLElement} The found element or null if not found.
+ */
+function $(id) {
+  return document.getElementById(id);
+}
+
+/**
+ * Calls chrome.send with a callback and restores the original afterwards.
+ * @param {string} name The name of the message to send.
+ * @param {!Array} params The parameters to send.
+ * @param {string} callbackName The name of the function that the backend calls.
+ * @param {!Function} The function to call.
+ */
+function chromeSend(name, params, callbackName, callback) {
+  var old = global[callbackName];
+  global[callbackName] = function() {
+    // restore
+    global[callbackName] = old;
+
+    var args = Array.prototype.slice.call(arguments);
+    return callback.apply(global, args);
+  };
+  chrome.send(name, params);
+}
+
+
+/**
+ * Generates a CSS url string.
+ * @param {string} s The URL to generate the CSS url for.
+ * @return {string} The CSS url string.
+ */
+function url(s) {
+  // http://www.w3.org/TR/css3-values/#uris
+  // Parentheses, commas, whitespace characters, single quotes (') and double
+  // quotes (") appearing in a URI must be escaped with a backslash
+  var s2 = s.replace(/(\(|\)|\,|\s|\'|\"|\\)/g, '\\$1');
+  // WebKit has a bug when it comes to URLs that end with \
+  // https://bugs.webkit.org/show_bug.cgi?id=28885
+  if (/\\\\$/.test(s2)) {
+    // Add a space to work around the WebKit bug.
+    s2 += ' ';
+  }
+  return 'url("' + s2 + '")';
+}
diff --git a/resources/bookmark_manager/main.html b/resources/bookmark_manager/main.html
new file mode 100644
index 0000000..b36b6c0
--- /dev/null
+++ b/resources/bookmark_manager/main.html
@@ -0,0 +1,1587 @@
+<!DOCTYPE html>
+<html i18n-values="dir:textdirection">
+<!--
+
+Copyright (c) 2010 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+
+
+This is work in progress:
+
+Favicons: chrome-extension: is not allowed to access chrome://favicon. We need
+to whitelist it or expose a way to get the data URI for the favicon (slow and
+sucky).
+
+Favicon of bmm does not work. No icon is showed.
+
+-->
+<head>
+<title i18n-content="title"></title>
+
+<link rel="stylesheet" href="css/list.css">
+<link rel="stylesheet" href="css/tree.css">
+<link rel="stylesheet" href="css/menu.css">
+<link rel="stylesheet" href="css/bmm.css">
+
+<script src="css/tree.css.js"></script>
+<script src="css/bmm.css.js"></script>
+
+<script src="js/cr.js"></script>
+<script src="js/cr/event.js"></script>
+<script src="js/cr/eventtarget.js"></script>
+<script src="js/cr/promise.js"></script>
+<script src="js/cr/ui.js"></script>
+<script src="js/cr/ui/listselectionmodel.js"></script>
+<script src="js/cr/ui/listitem.js"></script>
+<script src="js/cr/ui/list.js"></script>
+<script src="js/cr/ui/tree.js"></script>
+<script src="js/cr/ui/command.js"></script>
+<script src="js/cr/ui/menuitem.js"></script>
+<script src="js/cr/ui/menu.js"></script>
+<script src="js/cr/ui/menubutton.js"></script>
+<script src="js/cr/ui/contextmenuhandler.js"></script>
+
+<script src="js/util.js"></script>
+<script src="js/localstrings.js"></script>
+<script src="js/i18ntemplate.js"></script>
+
+<script src="js/bmm/treeiterator.js"></script>
+<script src="js/bmm.js"></script>
+<script src="js/bmm/bookmarklist.js"></script>
+<script src="js/bmm/bookmarktree.js"></script>
+
+<script>
+
+// Sometimes the extension API is not initialized.
+if (!chrome.bookmarks)
+  window.location.reload();
+
+// Allow platform specific CSS rules.
+if (cr.isMac)
+  document.documentElement.setAttribute('os', 'mac');
+
+</script>
+</head>
+<body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
+
+<div class="header">
+  <button onclick="resetSearch()" class="logo" tabindex=3></button>
+  <div>
+    <form onsubmit="setSearch(this.term.value); return false;"
+        class="form">
+      <input type="text" id="term" tabindex=1 autofocus>
+      <input type="submit" i18n-values=".value:search_button" tabindex=1>
+    </form>
+    <div class=toolbar>
+      <button menu="#organize-menu" tabindex="-1" i18n-content="organize_menu"></button>
+      <button menu="#tools-menu" tabindex="-1" i18n-content="tools_menu"></button>
+    </div>
+  </div>
+</div>
+
+<div class=main>
+  <div id=tree-container>
+    <tree id=tree tabindex=2></tree>
+  </div>
+  <list id=list tabindex=2></list>
+</div>
+
+
+<script>
+
+const BookmarkList = bmm.BookmarkList;
+const BookmarkTree = bmm.BookmarkTree;
+const ListItem = cr.ui.ListItem;
+const TreeItem = cr.ui.TreeItem;
+
+/**
+ * The id of the bookmark root.
+ * @type {number}
+ */
+const ROOT_ID = '0';
+
+var bookmarkCache = {
+  /**
+   * This returns a reference to the bookmark node that is cached by the tree
+   * or list. Use this funciton when we need to update the local cachea after
+   * changes. It only returns bookmarks that are used by the tree and/or the
+   * list.
+   * @param {string} The ID of the bookmark that we want to get.
+   * @return {BookmarkTreeNode}
+   */
+  getById: function(id) {
+    var el = bmm.treeLookup[id] || bmm.listLookup[id];
+    return el && el.bookmarkNode;
+  },
+
+  /**
+   * Removes the cached item from both the list and tree lookups.
+   */
+  remove: function(id) {
+    delete bmm.listLookup[id];
+
+    var treeItem = bmm.treeLookup[id];
+    if (treeItem) {
+      var items = treeItem.items; // is an HTMLCollection
+      for (var i = 0, item; item = items[i]; i++) {
+        var bookmarkNode = item.bookmarkNode;
+        delete bmm.treeLookup[bookmarkNode.id];
+      }
+      delete bmm.treeLookup[id];
+    }
+  },
+
+  /**
+   * Updates the underlying bookmark node for the tree items and list items by
+   * querying the bookmark backend.
+   * @param {string} id The id of the node to update the children for.
+   * @param {Function=} opt_f A funciton to call when done.
+   */
+  updateChildren: function(id, opt_f) {
+    function updateItem(bookmarkNode) {
+      var treeItem = bmm.treeLookup[bookmarkNode.id];
+      if (treeItem) {
+        treeItem.bookmarkNode = bookmarkNode;
+      }
+      var listItem = bmm.listLookup[bookmarkNode.id];
+      if (listItem) {
+        listItem.bookmarkNode = bookmarkNode;
+      }
+    }
+
+    chrome.bookmarks.getChildren(id, function(children) {
+      children.forEach(updateItem);
+
+      if (opt_f)
+        opt_f(children);
+    });
+  }
+};
+
+</script>
+<script>
+
+BookmarkList.decorate(list);
+
+var searchTreeItem = new TreeItem({
+  label: 'Search',
+  icon: 'images/bookmark_manager_search.png',
+  bookmarkId: 'q='
+});
+bmm.treeLookup[searchTreeItem.bookmarkId] = searchTreeItem;
+
+var recentTreeItem = new TreeItem({
+  label: 'Recent',
+  icon: 'images/bookmark_manager_recent.png',
+  bookmarkId: 'recent'
+});
+bmm.treeLookup[recentTreeItem.bookmarkId] = recentTreeItem;
+
+BookmarkTree.decorate(tree);
+
+tree.addEventListener('change', function() {
+  navigateTo(tree.selectedItem.bookmarkId);
+});
+
+/**
+ * Navigates to a bookmark ID.
+ * @param {string} id The ID to navigate to.
+ */
+function navigateTo(id) {
+  console.info('navigateTo', window.location.hash, id);
+  // Update the location hash using a timer to prevent reentrancy. This is how
+  // often we add history entries and the time here is a bit arbitrary but was
+  // picked as the smallest time a human perceives as instant.
+  clearTimeout(navigateTo.timer_);
+  navigateTo.timer_ = setTimeout(function() {
+    window.location.hash = tree.selectedItem.bookmarkId;
+  }, 300);
+  updateParentId(id);
+}
+
+/**
+ * Updates the parent ID of the bookmark list and selects the correct tree item.
+ * @param {string} id The id.
+ */
+function updateParentId(id) {
+  list.parentId = id;
+  if (id in bmm.treeLookup)
+    tree.selectedItem = bmm.treeLookup[id];
+}
+
+// We listen to hashchange so that we can update the currently shown folder when
+// the user goes back and forward in the history.
+window.onhashchange = function(e) {
+  var id = window.location.hash.slice(1);
+
+  var valid = false;
+
+  // In case we got a search hash update the text input and the bmm.treeLookup
+  // to use the new id.
+  if (/^q=/.test(id)) {
+    delete bmm.treeLookup[searchTreeItem.bookmarkId];
+    $('term').value = id.slice(2);
+    searchTreeItem.bookmarkId = id;
+    bmm.treeLookup[id] = searchTreeItem;
+    valid = true;
+  } else if (id == 'recent') {
+    valid = true;
+  }
+
+  if (valid) {
+    updateParentId(id);
+  } else {
+    // We need to verify that this is a correct ID.
+    chrome.bookmarks.get(id, function(items) {
+      if (items && items.length == 1)
+        updateParentId(id);
+    });
+  }
+};
+
+list.addEventListener('activate', function(e) {
+  var bookmarkNodes = getSelectedBookmarkNodes();
+
+  // If we double clicked or pressed enter on a single folder navigate to it.
+  if (bookmarkNodes.length == 1 && bmm.isFolder(bookmarkNodes[0])) {
+    navigateTo(bookmarkNodes[0].id);
+  } else {
+    var command = $('open-in-new-tab-command');
+    command.execute();
+  }
+});
+
+// The list dispatches an event when the user clicks on the URL or the Show in
+// folder part.
+list.addEventListener('urlClicked', function(e) {
+  openUrls([e.url], e.kind);
+});
+
+/**
+ * Timer id used for delaying find-as-you-type
+ */
+var inputDelayTimer;
+
+// Capture input changes to the search term input element and delay searching
+// for 250ms to reduce flicker.
+$('term').oninput = function(e) {
+  clearTimeout(inputDelayTimer);
+  inputDelayTimer = setTimeout(function() {
+    setSearch($('term').value);
+  }, 250);
+};
+
+/**
+ * Navigates to the search results for the search text.
+ * @para {string} searchText The text to search for.
+ */
+function setSearch(searchText) {
+  navigateTo('q=' + searchText);
+}
+
+/**
+ * Clears the search.
+ */
+function resetSearch() {
+  $('term').value = '';
+  setSearch('');
+  $('term').focus();
+}
+
+/**
+ * Called when the title of a bookmark changes.
+ * @param {string} id
+ * @param {!Object} changeInfo
+ */
+function handleBookmarkChanged(id, changeInfo) {
+  // console.log('handleBookmarkChanged', id, changeInfo);
+  list.handleBookmarkChanged(id, changeInfo);
+  tree.handleBookmarkChanged(id, changeInfo);
+}
+
+/**
+ * Callback for when the user reorders by title.
+ * @param {string} id The id of the bookmark folder that was reordered.
+ * @param {!Object} reorderInfo The information about how the items where
+ *     reordered.
+ */
+function handleChildrenReordered(id, reorderInfo) {
+  // console.info('handleChildrenReordered', id, reorderInfo);
+  list.handleChildrenReordered(id, reorderInfo);
+  tree.handleChildrenReordered(id, reorderInfo);
+  bookmarkCache.updateChildren(id);
+}
+
+/**
+ * Callback for when a bookmark node is created.
+ * @param {string} id The id of the newly created bookmark node.
+ * @param {!Object} bookmarkNode The new bookmark node.
+ */
+function handleCreated(id, bookmarkNode) {
+  // console.info('handleCreated', id, bookmarkNode);
+  list.handleCreated(id, bookmarkNode);
+  tree.handleCreated(id, bookmarkNode);
+  bookmarkCache.updateChildren(bookmarkNode.parentId);
+}
+
+function handleMoved(id, moveInfo) {
+  // console.info('handleMoved', id, moveInfo);
+  list.handleMoved(id, moveInfo);
+  tree.handleMoved(id, moveInfo);
+
+  bookmarkCache.updateChildren(moveInfo.parentId);
+  if (moveInfo.parentId != moveInfo.oldParentId)
+    bookmarkCache.updateChildren(moveInfo.oldParentId);
+}
+
+function handleRemoved(id, removeInfo) {
+  // console.info('handleRemoved', id, removeInfo);
+  list.handleRemoved(id, removeInfo);
+  tree.handleRemoved(id, removeInfo);
+
+  bookmarkCache.updateChildren(removeInfo.parentId);
+  bookmarkCache.remove(id);
+}
+
+function handleImportBegan() {
+  chrome.bookmarks.onCreated.removeListener(handleCreated);
+}
+
+function handleImportEnded() {
+  chrome.bookmarks.onCreated.addListener(handleCreated);
+  var p = bmm.loadTree();
+  p.addListener(function(node) {
+    var otherBookmarks = node.children[1].children;
+    var importedFolder = otherBookmarks[otherBookmarks.length - 1];
+    var importId = importedFolder.id;
+    tree.insertSubtree(importedFolder);
+    navigateTo(importId)
+  });
+}
+
+/**
+ * Adds the listeners for the bookmark model change events.
+ */
+function addBookmarkModelListeners() {
+  chrome.bookmarks.onChanged.addListener(handleBookmarkChanged);
+  chrome.bookmarks.onChildrenReordered.addListener(handleChildrenReordered);
+  chrome.bookmarks.onCreated.addListener(handleCreated);
+  chrome.bookmarks.onMoved.addListener(handleMoved);
+  chrome.bookmarks.onRemoved.addListener(handleRemoved);
+  chrome.experimental.bookmarkManager.onImportBegan.addListener(
+      handleImportBegan);
+  chrome.experimental.bookmarkManager.onImportEnded.addListener(
+      handleImportEnded);
+}
+
+/**
+ * This returns the user visible path to the folder where the bookmark is
+ * located.
+ * @param {number} parentId The ID of the parent folder.
+ * @return {string} The path to the the bookmark,
+ */
+function getFolder(parentId) {
+  var parentNode = tree.getBookmarkNodeById(parentId);
+  if (parentNode) {
+    var s = parentNode.title;
+    if (parentNode.parentId != ROOT_ID) {
+      return getFolder(parentNode.parentId) + '/' + s;
+    }
+    return s;
+  }
+}
+
+tree.addEventListener('load', function(e) {
+  // Add hard coded tree items
+  tree.add(recentTreeItem);
+  tree.add(searchTreeItem);
+
+  // Now we can select a tree item.
+  var hash = window.location.hash.slice(1);
+  if (!hash) {
+    // If we do not have a hash select first item in the tree.
+    hash = tree.items[0].bookmarkId;
+  }
+
+  if (/^q=/.test(hash))
+    $('term').value = hash.slice(2);
+  navigateTo(hash);
+});
+
+tree.buildTree();
+addBookmarkModelListeners();
+
+var dnd = {
+  DND_EFFECT_COPY: 'copy',
+  DND_EFFECT_MOVE: cr.isMac ? 'move' : 'copy', // http://crbug.com/14654
+
+  dragData: null,
+
+  getBookmarkElement: function(el) {
+    while (el && !el.bookmarkNode) {
+      el = el.parentNode;
+    }
+    return el;
+  },
+
+  // If we are over the list and the list is showing recent or search result
+  // we cannot drop.
+  isOverRecentOrSearch: function(overElement) {
+    return (list.isRecent() || list.isSearch()) && list.contains(overElement);
+  },
+
+  checkEvery_: function(f, overBookmarkNode, overElement) {
+    return this.dragData.elements.every(function(element) {
+      return f.call(this, element, overBookmarkNode, overElement);
+    }, this);
+  },
+
+  /**
+   * @return {boolean} Whether we are currently dragging any folders.
+   */
+  isDraggingFolders: function() {
+    return !!this.dragData && this.dragData.elements.some(function(node) {
+      return !node.url;
+    });
+  },
+
+  /**
+   * This is a first pass wether we can drop the dragged items.
+   *
+   * @param {!BookmarkTreeNode} overBookmarkNode The bookmark that we are
+   *     currently dragging over.
+   * @param {!HTMLElement} overElement The element that we are currently
+   *     dragging over.
+   * @return {boolean} If this returns false then we know we should not drop
+   *     the items. If it returns true we still have to call canDropOn,
+   *     canDropAbove and canDropBelow.
+   */
+  canDrop: function(overBookmarkNode, overElement) {
+    var dragData = this.dragData;
+    if (!dragData)
+      return false;
+
+    if (this.isOverRecentOrSearch(overElement))
+      return false;
+
+    if (!dragData.sameProfile)
+      return true;
+
+    return this.checkEvery_(this.canDrop_, overBookmarkNode, overElement);
+  },
+
+  /**
+   * Helper for canDrop that only checks one bookmark node.
+   * @private
+   */
+  canDrop_: function(dragNode, overBookmarkNode, overElement) {
+    var dragId = dragNode.id;
+
+    if (overBookmarkNode.id == dragId)
+      return false;
+
+    // If we are dragging a folder we cannot drop it on any of its descendants
+    var dragBookmarkItem = bmm.treeLookup[dragId];
+    var dragBookmarkNode = dragBookmarkItem && dragBookmarkItem.bookmarkNode;
+    if (dragBookmarkNode && bmm.contains(dragBookmarkNode, overBookmarkNode)) {
+      return false;
+    }
+
+    return true;
+  },
+
+  /**
+   * Whether we can drop the dragged items above the drop target.
+   *
+   * @param {!BookmarkTreeNode} overBookmarkNode The bookmark that we are
+   *     currently dragging over.
+   * @param {!HTMLElement} overElement The element that we are currently
+   *     dragging over.
+   * @return {boolean} Whether we can drop the dragged items above the drop
+   *     target.
+   */
+  canDropAbove: function(overBookmarkNode, overElement) {
+    if (overElement instanceof BookmarkList)
+      return false;
+
+    // We cannot drop between Bookmarks bar and Other bookmarks
+    if (overBookmarkNode.parentId == ROOT_ID)
+      return false;
+
+    var isOverTreeItem = overElement instanceof TreeItem;
+
+    // We can only drop between items in the tree if we have any folders.
+    if (isOverTreeItem && !this.isDraggingFolders())
+      return false;
+
+    if (!this.dragData.sameProfile)
+      return this.isDraggingFolders() || !isOverTreeItem;
+
+    return this.checkEvery_(this.canDropAbove_, overBookmarkNode, overElement);
+  },
+
+  /**
+   * Helper for canDropAbove that only checks one bookmark node.
+   * @private
+   */
+  canDropAbove_: function(dragNode, overBookmarkNode, overElement) {
+    var dragId = dragNode.id;
+
+    // We cannot drop above if the item below is already in the drag source
+    var previousElement = overElement.previousElementSibling;
+    if (previousElement &&
+        previousElement.bookmarkId == dragId)
+      return false;
+
+    return true;
+  },
+
+  /**
+   * Whether we can drop the dragged items below the drop target.
+   *
+   * @param {!BookmarkTreeNode} overBookmarkNode The bookmark that we are
+   *     currently dragging over.
+   * @param {!HTMLElement} overElement The element that we are currently
+   *     dragging over.
+   * @return {boolean} Whether we can drop the dragged items below the drop
+   *     target.
+   */
+  canDropBelow: function(overBookmarkNode, overElement) {
+    if (overElement instanceof BookmarkList)
+      return false;
+
+    // We cannot drop between Bookmarks bar and Other bookmarks
+    if (overBookmarkNode.parentId == ROOT_ID)
+      return false;
+
+    // We can only drop between items in the tree if we have any folders.
+    if (!this.isDraggingFolders() && overElement instanceof TreeItem)
+      return false;
+
+    var isOverTreeItem = overElement instanceof TreeItem;
+
+    // Don't allow dropping below an expanded tree item since it is confusing
+    // to the user anyway.
+    if (isOverTreeItem && overElement.expanded)
+      return false;
+
+    if (!this.dragData.sameProfile)
+      return this.isDraggingFolders() || !isOverTreeItem;
+
+    return this.checkEvery_(this.canDropBelow_, overBookmarkNode, overElement);
+  },
+
+  /**
+   * Helper for canDropBelow that only checks one bookmark node.
+   * @private
+   */
+  canDropBelow_: function(dragNode, overBookmarkNode, overElement) {
+    var dragId = dragNode.id;
+
+    // We cannot drop below if the item below is already in the drag source
+    var nextElement = overElement.nextElementSibling;
+    if (nextElement &&
+        nextElement.bookmarkId == dragId)
+      return false;
+
+    return true;
+  },
+
+  /**
+   * Whether we can drop the dragged items on the drop target.
+   *
+   * @param {!BookmarkTreeNode} overBookmarkNode The bookmark that we are
+   *     currently dragging over.
+   * @param {!HTMLElement} overElement The element that we are currently
+   *     dragging over.
+   * @return {boolean} Whether we can drop the dragged items on the drop
+   *     target.
+   */
+  canDropOn: function(overBookmarkNode, overElement) {
+    // We can only drop on a folder.
+    if (!bmm.isFolder(overBookmarkNode))
+      return false;
+
+    if (!this.dragData.sameProfile)
+      return true;
+
+    return this.checkEvery_(this.canDropOn_, overBookmarkNode, overElement);
+  },
+
+  /**
+   * Helper for canDropOn that only checks one bookmark node.
+   * @private
+   */
+  canDropOn_: function(dragNode, overBookmarkNode, overElement) {
+    var dragId = dragNode.id;
+
+    if (overElement instanceof BookmarkList) {
+      // We are trying to drop an item after the last item in the list. This
+      // is allowed if the item is different from the last item in the list
+      var listItems = list.items;
+      var len = listItems.length;
+      if (len == 0 ||
+          listItems[len - 1].bookmarkId != dragId) {
+        return true;
+      }
+    }
+
+    // Cannot drop on current parent.
+    if (overBookmarkNode.id == dragNode.parentId)
+      return false;
+
+    return true;
+  },
+
+  /**
+   * Callback for the dragstart event.
+   * @param {Event} e The dragstart event.
+   */
+  handleDragStart: function(e) {
+    // console.log(e.type);
+
+    // Determine the selected bookmarks.
+    var target = e.target;
+    var draggedItems = [];
+    if (target instanceof ListItem) {
+      // Use selected items.
+      draggedItems = target.parentNode.selectedItems;
+    } else if (target instanceof TreeItem) {
+      draggedItems.push(target);
+    }
+
+    // We manage starting the drag by using the extension API.
+    e.preventDefault();
+
+    if (draggedItems.length) {
+      // If we are dragging a single link we can do the *Link* effect, otherwise
+      // we only allow copy and move.
+      var effectAllowed;
+      if (draggedItems.length == 1 &&
+          !bmm.isFolder(draggedItems[0].bookmarkNode)) {
+        effectAllowed = 'copyMoveLink';
+      } else {
+        effectAllowed = 'copyMove';
+      }
+      e.dataTransfer.effectAllowed = effectAllowed;
+
+      var ids = draggedItems.map(function(el) {
+        return el.bookmarkId;
+      });
+
+      chrome.experimental.bookmarkManager.startDrag(ids);
+    }
+  },
+
+  handleDragEnter: function(e) {
+    // console.log(e.type);
+
+    e.preventDefault();
+  },
+
+  /**
+   * Calback for the dragover event.
+   * @param {Event} e The dragover event.
+   */
+  handleDragOver: function(e) {
+    // console.log(e.type);
+
+    // The default operation is to allow dropping links etc to do navigation.
+    // We never want to do that for the bookmark manager.
+    e.preventDefault();
+
+    if (!this.dragData)
+      return;
+
+    var overElement = this.getBookmarkElement(e.target);
+    if (!overElement && e.target == list)
+      overElement = list;
+
+    if (!overElement)
+      return;
+
+    var overBookmarkNode = overElement.bookmarkNode;
+
+    if (!this.canDrop(overBookmarkNode, overElement))
+      return;
+
+    var bookmarkNode = overElement.bookmarkNode;
+
+    var canDropAbove = this.canDropAbove(overBookmarkNode, overElement);
+    var canDropOn = this.canDropOn(overBookmarkNode, overElement);
+    var canDropBelow = this.canDropBelow(overBookmarkNode, overElement);
+
+    if (!canDropAbove && !canDropOn && !canDropBelow)
+      return;
+
+    // Now we know that we can drop. Determine if we will drop above, on or
+    // below based on mouse position etc.
+
+    var dropPos;
+
+    e.dataTransfer.dropEffect = this.dragData.sameProfile ?
+        this.DND_EFFECT_MOVE : this.DND_EFFECT_COPY;
+
+    var rect;
+    if (overElement instanceof TreeItem) {
+      // We only want the rect of the row representing the item and not
+      // its children
+      rect = overElement.rowElement.getBoundingClientRect();
+    } else {
+      rect = overElement.getBoundingClientRect();
+    }
+
+    var dy = e.clientY - rect.top;
+    var yRatio = dy / rect.height;
+
+    //  above
+    if (canDropAbove &&
+        (yRatio <= .25 || yRatio <= .5 && !(canDropBelow && canDropOn))) {
+      dropPos = 'above';
+
+    // below
+    } else if (canDropBelow &&
+               (yRatio > .75 || yRatio > .5 && !(canDropAbove && canDropOn))) {
+      dropPos = 'below';
+
+    // on
+    } else if (canDropOn) {
+      dropPos = 'on';
+
+    // none
+    } else {
+      // No drop can happen. Exit now.
+      e.dataTransfer.dropEffect = 'none';
+      return;
+    }
+
+    function cloneClientRect(rect) {
+      var newRect = {};
+      for (var key in rect) {
+        newRect[key] = rect[key];
+      }
+      return newRect;
+    }
+
+    // If we are dropping above or below a tree item adjust the width so
+    // that it is clearer where the item will be dropped.
+    if ((dropPos == 'above' || dropPos == 'below') &&
+        overElement instanceof TreeItem) {
+      // ClientRect is read only so clone in into a read-write object.
+      rect = cloneClientRect(rect);
+      var rtl = getComputedStyle(overElement).direction == 'rtl';
+      var labelElement = overElement.labelElement;
+      var labelRect = labelElement.getBoundingClientRect();
+      if (rtl) {
+        rect.width = labelRect.left + labelRect.width - rect.left;
+      } else {
+        rect.left = labelRect.left;
+        rect.width -= rect.left
+      }
+    }
+
+    var overlayType = dropPos;
+
+    // If we are dropping on a list we want to show a overlay drop line after
+    // the last element
+    if (overElement instanceof BookmarkList) {
+      overlayType = 'below';
+
+      // Get the rect of the last list item.
+      var items = overElement.items;
+      var length = items.length;
+      if (length) {
+        dropPos = 'below';
+        overElement = items[length - 1];
+        rect = overElement.getBoundingClientRect();
+      } else {
+        // If there are no items, collapse the height of the rect
+        rect = cloneClientRect(rect);
+        rect.height = 0;
+        // We do not use bottom so we don't care to adjust it.
+      }
+    }
+
+    this.showDropOverlay_(rect, overlayType);
+
+    this.dropDestination = {
+      dropPos: dropPos,
+      relatedNode: overElement.bookmarkNode
+    };
+  },
+
+  /**
+   * Shows and positions the drop marker overlay.
+   * @param {ClientRect} targetRect The drop target rect
+   * @param {string} overlayType The position relative to the target rect.
+   * @private
+   */
+  showDropOverlay_: function(targetRect, overlayType) {
+    window.clearTimeout(this.hideDropOverlayTimer_);
+    var overlay = $('drop-overlay');
+    if (overlayType == 'on') {
+      overlay.className = '';
+      overlay.style.top = targetRect.top + 'px';
+      overlay.style.height = targetRect.height + 'px';
+    } else {
+      overlay.className = 'line';
+      overlay.style.height = '';
+    }
+    overlay.style.width = targetRect.width + 'px';
+    overlay.style.left = targetRect.left + 'px';
+    overlay.style.display = 'block';
+
+    if (overlayType != 'on') {
+      var overlayRect = overlay.getBoundingClientRect();
+      if (overlayType == 'above') {
+        overlay.style.top = targetRect.top - overlayRect.height / 2 + 'px';
+      } else {
+        overlay.style.top = targetRect.top + targetRect.height -
+            overlayRect.height / 2 + 'px';
+      }
+    }
+  },
+
+  /**
+   * Hides the drop overlay element.
+   * @private
+   */
+  hideDropOverlay_: function() {
+    // Hide the overlay in a timeout to reduce flickering as we move between
+    // valid drop targets.
+    window.clearTimeout(this.hideDropOverlayTimer_);
+    this.hideDropOverlayTimer_ = window.setTimeout(function() {
+      $('drop-overlay').style.display = '';
+    }, 100);
+  },
+
+  handleDragLeave: function(e) {
+    // console.log(e.type);
+
+    this.hideDropOverlay_();
+  },
+
+  handleDrop: function(e) {
+    // console.log(e.type);
+
+    if (this.dropDestination && this.dragData) {
+      var dropPos = this.dropDestination.dropPos;
+      var relatedNode = this.dropDestination.relatedNode;
+      var parentId = dropPos == 'on' ? relatedNode.id : relatedNode.parentId;
+
+      var index;
+      if (dropPos == 'above')
+        index = relatedNode.index;
+      else if (dropPos == 'below')
+        index = relatedNode.index + 1;
+
+      if (index != undefined)
+        chrome.experimental.bookmarkManager.drop(parentId, index);
+      else
+        chrome.experimental.bookmarkManager.drop(parentId);
+
+      // TODO(arv): Select the newly dropped items.
+    }
+    this.dropDestination = null;
+    this.hideDropOverlay_();
+  },
+
+  handleDrag: function(e) {
+    // console.log(e.type);
+  },
+
+  handleDragEnd: function(e) {
+    // console.log(e.type);
+
+    var self = this;
+    // Chromium Win incorrectly fires the dragend event before the drop event.
+    // http://code.google.com/p/chromium/issues/detail?id=31292
+    window.setTimeout(function() {
+      self.dragData = null;
+    }, 1)
+  },
+
+  handleChromeDragEnter: function(dragData) {
+    this.dragData = dragData;
+  },
+
+  init: function() {
+    document.addEventListener('dragstart', cr.bind(this.handleDragStart, this));
+    document.addEventListener('dragenter', cr.bind(this.handleDragEnter, this));
+    document.addEventListener('dragover', cr.bind(this.handleDragOver, this));
+    document.addEventListener('dragleave', cr.bind(this.handleDragLeave, this));
+    document.addEventListener('drop', cr.bind(this.handleDrop, this));
+    document.addEventListener('dragend', cr.bind(this.handleDragEnd, this));
+    document.addEventListener('drag', cr.bind(this.handleDrag, this));
+
+    chrome.experimental.bookmarkManager.onDragEnter.addListener(cr.bind(
+        this.handleChromeDragEnter, this));
+  }
+
+};
+
+dnd.init();
+
+</script>
+
+<!-- Organize menu -->
+<command i18n-values=".label:rename_folder" id="rename-folder-command"></command>
+<command i18n-values=".label:edit" id="edit-command"></command>
+<command i18n-values=".label:delete" id="delete-command"></command>
+<command i18n-values=".label:show_in_folder" id="show-in-folder-command"></command>
+<command i18n-values=".label:cut" id="cut-command"></command>
+<command i18n-values=".label:copy" id="copy-command"></command>
+<command i18n-values=".label:paste" id="paste-command"></command>
+<command i18n-values=".label:sort" id="sort-command"></command>
+<command i18n-values=".label:add_new_bookmark" id="add-new-bookmark-command"></command>
+<command i18n-values=".label:new_folder" id="new-folder-command"></command>
+
+<!-- Tools menu -->
+<command i18n-values=".label:import_menu" id="import-menu-command"></command>
+<command i18n-values=".label:export_menu" id="export-menu-command"></command>
+
+<!-- open * are handled in canExecute handler -->
+<command id="open-in-new-tab-command"></command>
+<command id="open-in-new-window-command"></command>
+<command id="open-incognito-window-command"></command>
+
+<!-- TODO(arv): I think the commands might be better created in code? -->
+
+<menu id="organize-menu">
+  <button command="#rename-folder-command"></button>
+  <button command="#edit-command"></button>
+  <button command="#delete-command"></button>
+  <button command="#show-in-folder-command"></button>
+  <hr>
+  <button command="#cut-command"></button>
+  <button command="#copy-command"></button>
+  <button command="#paste-command"></button>
+  <hr>
+  <button command="#sort-command"></button>
+  <hr>
+  <button command="#add-new-bookmark-command"></button>
+  <button command="#new-folder-command"></button>
+</menu>
+
+<menu id="tools-menu">
+  <button command="#import-menu-command"></button>
+  <button command="#export-menu-command"></button>
+</menu>
+
+<menu id="context-menu">
+  <button command="#open-in-new-tab-command"></button>
+  <button command="#open-in-new-window-command"></button>
+  <button command="#open-incognito-window-command"></button>
+  <hr>
+  <button command="#rename-folder-command"></button>
+  <button command="#edit-command"></button>
+  <button command="#delete-command"></button>
+  <button command="#show-in-folder-command"></button>
+  <hr>
+  <button command="#cut-command"></button>
+  <button command="#copy-command"></button>
+  <button command="#paste-command"></button>
+  <hr>
+  <button command="#add-new-bookmark-command"></button>
+  <button command="#new-folder-command"></button>
+</menu>
+
+<script>
+
+// Commands
+
+const Command = cr.ui.Command;
+const CommandBinding = cr.ui.CommandBinding;
+const Menu = cr.ui.Menu;
+const MenuButton  = cr.ui.MenuButton;
+
+cr.ui.decorate('menu', Menu);
+cr.ui.decorate('button[menu]', MenuButton);
+cr.ui.decorate('command', Command);
+
+cr.ui.contextMenuHandler.addContextMenuProperty(tree);
+list.contextMenu = $('context-menu');
+tree.contextMenu = $('context-menu');
+
+/**
+ * Helper function that updates the canExecute and labels for the open like
+ * commands.
+ * @param {!cr.ui.CanExecuteEvent} e The event fired by the command system.
+ * @param {!cr.ui.Command} command The command we are currently precessing.
+ */
+function updateOpenCommands(e, command) {
+  var selectedItem = e.target.selectedItem;
+  var selectionCount;
+  if (e.target == tree)
+    selectionCount = selectedItem ? 1 : 0;
+  else
+    selectionCount = e.target.selectedItems.length;
+
+  var isFolder = selectionCount == 1 &&
+                 selectedItem.bookmarkNode &&
+                 bmm.isFolder(selectedItem.bookmarkNode);
+  var multiple = selectionCount != 1 || isFolder;
+
+  function hasBookmarks(node) {
+    var it = new bmm.TreeIterator(node);
+    while (it.moveNext()) {
+      if (!bmm.isFolder(it.current))
+        return true;
+    }
+    return false;
+  }
+
+  switch (command.id) {
+    case 'open-in-new-tab-command':
+      command.label = localStrings.getString(multiple ?
+          'open_all' : 'open_in_new_tab');
+      break;
+
+    case 'open-in-new-window-command':
+      command.label = localStrings.getString(multiple ?
+          'open_all_new_window' : 'open_in_new_window');
+      break;
+    case 'open-incognito-window-command':
+      command.label = localStrings.getString(multiple ?
+          'open_all_incognito' : 'open_incognito');
+      break;
+  }
+  e.canExecute = selectionCount > 0 && !!selectedItem.bookmarkNode;
+  if (isFolder && e.canExecute) {
+    // We need to get all the bookmark items in this tree. If the tree does not
+    // contain any non-folders we need to disable the command.
+    var p = bmm.loadSubtree(selectedItem.bookmarkId);
+    p.addListener(function(node) {
+      command.disabled = !node || !hasBookmarks(node);
+    });
+  }
+}
+
+/**
+ * Calls the backend to figure out if we can paste the clipboard into the active
+ * folder.
+ * @param {Function=} opt_f Function to call after the state has been
+ *     updated.
+ */
+function updatePasteCommand(opt_f) {
+  function update(canPaste) {
+    var command = $('paste-command');
+    command.disabled = !canPaste;
+    if (opt_f)
+      opt_f();
+  }
+  // We cannot paste into search and recent view.
+  if (list.isSearch() || list.isRecent()) {
+    update(false);
+  } else {
+    chrome.experimental.bookmarkManager.canPaste(list.parentId, update);
+  }
+}
+
+// We can always execute the import-menu and export-menu commands.
+document.addEventListener('canExecute', function(e) {
+  var command = e.command;
+  var commandId = command.id;
+  if (commandId == 'import-menu-command' || commandId == 'export-menu-command') {
+    e.canExecute = true;
+  }
+});
+
+// Update canExecute for the commands when the list is the active element.
+list.addEventListener('canExecute', function(e) {
+  if (e.target != list) return;
+
+  var command = e.command;
+  var commandId = command.id;
+
+  function hasSelected() {
+    return !!e.target.selectedItem;
+  }
+
+  function hasSingleSelected() {
+    return e.target.selectedItems.length == 1;
+  }
+
+  function isRecentOrSearch() {
+    return list.isRecent() || list.isSearch();
+  }
+
+  switch (commandId) {
+    case 'rename-folder-command':
+      // Show rename if a single folder is selected
+      var items = e.target.selectedItems;
+      if (items.length != 1) {
+        e.canExecute = false;
+        command.hidden = true;
+      } else {
+        var isFolder = bmm.isFolder(items[0].bookmarkNode);
+        e.canExecute = isFolder;
+        command.hidden = !isFolder;
+      }
+      break;
+
+    case 'edit-command':
+      // Show the edit command if not a folder
+      var items = e.target.selectedItems;
+      if (items.length != 1) {
+        e.canExecute = false;
+        command.hidden = false;
+      } else {
+        var isFolder = bmm.isFolder(items[0].bookmarkNode);
+        e.canExecute = !isFolder;
+        command.hidden = isFolder;
+      }
+      break;
+
+    case 'show-in-folder-command':
+      e.canExecute = isRecentOrSearch() && hasSingleSelected();
+      break;
+
+    case 'delete-command':
+    case 'cut-command':
+    case 'copy-command':
+      e.canExecute = hasSelected();
+      break;
+
+    case 'paste-command':
+      updatePasteCommand();
+      break;
+
+    case 'sort-command':
+    case 'add-new-bookmark-command':
+    case 'new-folder-command':
+      e.canExecute = !isRecentOrSearch();
+      break;
+
+    case 'open-in-new-tab-command':
+    case 'open-in-new-window-command':
+    case 'open-incognito-window-command':
+      updateOpenCommands(e, command);
+      break;
+  }
+});
+
+// Update canExecute for the commands when the tree is the active element.
+tree.addEventListener('canExecute', function(e) {
+  if (e.target != tree) return;
+
+  var command = e.command;
+  var commandId = command.id;
+
+  function hasSelected() {
+    return !!e.target.selectedItem;
+  }
+
+  function isRecentOrSearch() {
+    var item = e.target.selectedItem;
+    return item == recentTreeItem || item == searchTreeItem;
+  }
+
+  function isTopLevelItem() {
+    return e.target.selectedItem.parentNode == tree;
+  }
+
+  switch (commandId) {
+    case 'rename-folder-command':
+      command.hidden = false;
+      e.canExecute = hasSelected() && !isTopLevelItem();
+      break;
+
+    case 'edit-command':
+      command.hidden = true;
+      e.canExecute = false;
+      break;
+
+    case 'delete-command':
+    case 'cut-command':
+    case 'copy-command':
+      e.canExecute = hasSelected() && !isTopLevelItem();
+      break;
+
+    case 'paste-command':
+      updatePasteCommand();
+      break;
+
+    case 'sort-command':
+    case 'add-new-bookmark-command':
+    case 'new-folder-command':
+      e.canExecute = !isRecentOrSearch();
+      break;
+
+    case 'open-in-new-tab-command':
+    case 'open-in-new-window-command':
+    case 'open-incognito-window-command':
+      updateOpenCommands(e, command);
+      break;
+  }
+});
+
+/**
+ * Update the canExecute state of the commands when the selection changes.
+ * @param {Event} e The change event object.
+ */
+function updateCommandsBasedOnSelection(e) {
+  if (e.target == document.activeElement) {
+    // Paste only needs to updated when the tree selection changes.
+    var commandNames = ['copy', 'cut', 'delete', 'rename-folder', 'edit',
+        'add-new-bookmark', 'new-folder', 'open-in-new-tab',
+        'open-in-new-window', 'open-incognito-window'];
+
+    if (e.target == tree) {
+      commandNames.push('paste', 'show-in-folder', 'sort');
+    }
+
+    commandNames.forEach(function(baseId) {
+      $(baseId + '-command').canExecuteChange();
+    });
+  }
+}
+
+list.addEventListener('change', updateCommandsBasedOnSelection);
+tree.addEventListener('change', updateCommandsBasedOnSelection);
+
+document.addEventListener('command', function(e) {
+  var command = e.command;
+  var commandId = command.id;
+  console.log(command.id, 'executed', 'on', e.target);
+  if (commandId == 'import-menu-command') {
+    chrome.experimental.bookmarkManager.import();
+  } else if (command.id == 'export-menu-command') {
+    chrome.experimental.bookmarkManager.export();
+  }
+});
+
+function handleRename(e) {
+  var item = e.target;
+  var bookmarkNode = item.bookmarkNode;
+  chrome.bookmarks.update(bookmarkNode.id, {title: item.label});
+}
+
+tree.addEventListener('rename', handleRename);
+list.addEventListener('rename', handleRename);
+
+list.addEventListener('edit', function(e) {
+  var item = e.target;
+  var bookmarkNode = item.bookmarkNode;
+  var context = {
+    title: bookmarkNode.title
+  };
+  if (!bmm.isFolder(bookmarkNode))
+    context.url = bookmarkNode.url;
+
+  if (bookmarkNode.id == 'new') {
+    // New page
+    context.parentId = bookmarkNode.parentId;
+    chrome.bookmarks.create(context, function(node) {
+      list.remove(item);
+      list.selectedItem = bmm.listLookup[node.id];
+    });
+  } else {
+    // Edit
+    chrome.bookmarks.update(bookmarkNode.id, context);
+  }
+});
+
+list.addEventListener('canceledit', function(e) {
+  var item = e.target;
+  var bookmarkNode = item.bookmarkNode;
+  if (bookmarkNode.id == 'new') {
+    list.remove(item);
+    list.selectionModel.leadItem = list.lastChild;
+    list.selectionModel.anchorItem = list.lastChild;
+    list.focus();
+  }
+});
+
+/**
+ * Navigates to the folder that the selected item is in and selects it. This is
+ * used for the show-in-folder command.
+ */
+function showInFolder() {
+  var bookmarkId = list.selectedItem.bookmarkNode.id;
+  var parentId = list.selectedItem.bookmarkNode.parentId;
+
+  // After the list is loaded we should select the revealed item.
+  var f = function(e) {
+    var item = bmm.listLookup[bookmarkId];
+    if (item) {
+      list.selectionModel.leadItem = item;
+      item.selected = true;
+    }
+    list.removeEventListener('load', f);
+  }
+  list.addEventListener('load', f);
+  var treeItem = bmm.treeLookup[parentId];
+  treeItem.reveal();
+
+  navigateTo(parentId);
+}
+
+/**
+ * Opens URLs in new tab, window or incognito mode.
+ * @param {!Array.<string>} urls The URLs to open.
+ * @param {string} kind The kind is either 'tab', 'window', or 'incognito'.
+ */
+function openUrls(urls, kind) {
+  if (urls.length < 1)
+    return;
+
+  if (urls.length > 15) {
+    if (!confirm(localStrings.getStringF('should_open_all', urls.length)))
+      return;
+  }
+
+  // Fix '#124' URLs since open those in a new window does not work. We prepend
+  // the base URL when we encounter those.
+  var base = window.location.href.split('#')[0];
+  urls = urls.map(function(url) {
+    return url[0] == '#' ? base + url : url;
+  });
+
+  // Incognito mode is not yet supported by the extensions APIs.
+  // http://code.google.com/p/chromium/issues/detail?id=12658
+  if (kind == 'window') {
+    chrome.windows.create({url: urls[0]}, function(window) {
+      urls.forEach(function(url, i) {
+        if (i > 0)
+          chrome.tabs.create({url: url, windowId: window.id, selected: false});
+      });
+    });
+  } else if (kind == 'tab') {
+    urls.forEach(function(url, i) {
+      chrome.tabs.create({url: url, selected: !i});
+    });
+  } else {
+    window.location.href = urls[0];
+  }
+}
+
+/**
+ * Returns the selected bookmark nodes of the active element. Only call this
+ * if the list or the tree is focused.
+ * @return {!Array} Array of bookmark nodes.
+ */
+function getSelectedBookmarkNodes() {
+  if (document.activeElement == list) {
+    return list.selectedItems.map(function(item) {
+      return item.bookmarkNode;
+    });
+  } else if (document.activeElement == tree) {
+    return [tree.selectedItem.bookmarkNode];
+  } else {
+    throw Error('getSelectedBookmarkNodes called when wrong element focused.');
+  }
+}
+
+/**
+ * @return {!Array.<string>} An array of the selected bookmark IDs.
+ */
+function getSelectedBookmarkIds() {
+  return getSelectedBookmarkNodes().map(function(node) {
+    return node.id;
+  });
+}
+
+/**
+ * Opens the selected bookmarks.
+ */
+function openBookmarks(kind) {
+  // If we have selected any folders we need to find all items recursively.
+  // We can do several async calls to getChildren but instead we do a single
+  // call to getTree and only add the subtrees of the selected items.
+
+  var urls = [];
+  var idMap = {};
+
+  // Traverses the tree until it finds a node tree that should be added. Then
+  // we switch over to use addNodes. We could merge these two functions into
+  // one but that would make the code less readable.
+  function traverseNodes(node) {
+    // This is not using the iterator since it uses breadth first search.
+    if (node.id in idMap) {
+      addNodes(node);
+    } else if (node.children) {
+      for (var i = 0; i < node.children.length; i++) {
+        traverseNodes(node.children[i]);
+      }
+    }
+  }
+
+  // Adds the node and all the descendants
+  function addNodes(node) {
+    var it = new bmm.TreeIterator(node);
+    while (it.moveNext()) {
+      var n = it.current;
+      if (!bmm.isFolder(n))
+        urls.push(n.url);
+    }
+  }
+
+  var nodes = getSelectedBookmarkNodes();
+
+  // Create a map for simpler lookup later.
+  nodes.forEach(function(node) {
+    idMap[node.id] = true;
+  });
+  var p = bmm.loadTree();
+  p.addListener(function(node) {
+    traverseNodes(node);
+    openUrls(urls, kind);
+  });
+}
+
+/**
+ * Deletes the selected bookmarks.
+ */
+function deleteBookmarks() {
+  getSelectedBookmarkIds().forEach(function(id) {
+    chrome.bookmarks.removeTree(id);
+  });
+}
+
+/**
+ * Callback for the new folder command. This creates a new folder and starts
+ * a rename of it.
+ */
+function newFolder() {
+  var parentId = list.parentId;
+  var isTree = document.activeElement == tree;
+  chrome.bookmarks.create({
+    title: localStrings.getString('new_folder_name'),
+    parentId: parentId
+  }, function(newNode) {
+    // We need to do this in a timeout to be able to focus the newly created
+    // item.
+    setTimeout(function() {
+      var newItem = isTree ? bmm.treeLookup[newNode.id] :
+          bmm.listLookup[newNode.id];
+      document.activeElement.selectedItem = newItem;
+      newItem.editing = true;
+    });
+  });
+}
+
+/**
+ * Adds a page to the current folder. This is called by the
+ * add-new-bookmark-command handler.
+ */
+function addPage() {
+  var parentId = list.parentId;
+  var fakeNode = {
+    title: '',
+    url: '',
+    parentId: parentId,
+    id: 'new'
+  };
+  var newListItem = bmm.createListItem(fakeNode, false);
+  list.add(newListItem);
+  list.selectedItem = newListItem;
+  newListItem.editing = true;
+}
+
+/**
+ * Handler for the command event. This is used both for the tree and the list.
+ * @param {!Event} e The event object.
+ */
+function handleCommand(e) {
+  var command = e.command;
+  var commandId = command.id;
+  switch (commandId) {
+    case 'show-in-folder-command':
+      showInFolder();
+      break;
+    case 'open-in-new-tab-command':
+      openBookmarks('tab');
+      break;
+    case 'open-in-new-window-command':
+      openBookmarks('window');
+      break;
+    case 'open-in-new-incognito-command':
+      openBookmarks('incognito');
+      break;
+    case 'delete-command':
+      deleteBookmarks();
+      break;
+    case 'copy-command':
+      chrome.experimental.bookmarkManager.copy(getSelectedBookmarkIds());
+      break;
+    case 'cut-command':
+      chrome.experimental.bookmarkManager.cut(getSelectedBookmarkIds());
+      break;
+    case 'paste-command':
+      chrome.experimental.bookmarkManager.paste(list.parentId);
+      break;
+    case 'sort-command':
+      chrome.experimental.bookmarkManager.sortChildren(list.parentId);
+      break;
+    case 'rename-folder-command':
+    case 'edit-command':
+      document.activeElement.selectedItem.editing = true;
+      break;
+    case 'new-folder-command':
+      newFolder();
+      break;
+    case 'add-new-bookmark-command':
+      addPage();
+      break;
+  }
+}
+
+// TODO(arv): Move shortcut to HTML?
+
+// Meta+Backspace on Mac, Del on other platforms.
+$('delete-command').shortcut = cr.isMac ? 'U+0008-meta' : 'U+007F';
+
+list.addEventListener('command', handleCommand);
+tree.addEventListener('command', handleCommand);
+
+// Execute the copy, cut and paste commands when those events are dispatched by
+// the browser. This allows us to rely on the browser to handle the keyboard
+// shortcuts for these commands.
+(function() {
+  function handle(id) {
+    return function(e) {
+      var command = $(id);
+      if (!command.disabled) {
+        command.execute();
+        e.preventDefault(); // Prevent the system beep
+      }
+    };
+  }
+
+  // Listen to copy, cut and paste events and execute the associated commands.
+  document.addEventListener('copy', handle('copy-command'));
+  document.addEventListener('cut', handle('cut-command'));
+
+  var pasteHandler = handle('paste-command');
+  document.addEventListener('paste', function(e) {
+    // Paste is a bit special since we need to do an async call to see if we can
+    // paste because the paste command might not be up to date.
+    updatePasteCommand(pasteHandler);
+  });
+})();
+
+/**
+ * The local strings object which is used to do the translation.
+ * @type {!LocalStrings}
+ */
+var localStrings = new LocalStrings;
+
+// Get the localized strings from the backend.
+chrome.experimental.bookmarkManager.getStrings(function setTemplateData(data) {
+  // The strings may contain & which we need to strip.
+  for (var key in data) {
+    data[key] = data[key].replace(/&/, '');
+  }
+
+  localStrings.templateData = data;
+  i18nTemplate.process(document, data);
+});
+
+</script>
+
+<div id="drop-overlay"></div>
+
+</body>
+</html>
diff --git a/resources/bookmark_manager/manifest.json b/resources/bookmark_manager/manifest.json
new file mode 100644
index 0000000..070bf6f
--- /dev/null
+++ b/resources/bookmark_manager/manifest.json
@@ -0,0 +1,17 @@
+{
+  "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQcByy+eN9jzazWF/DPn7NW47sW7lgmpk6eKc0BQM18q8hvEM3zNm2n7HkJv/R6fU+X5mtqkDuKvq5skF6qqUF4oEyaleWDFhd1xFwV7JV+/DU7bZ00w2+6gzqsabkerFpoP33ZRIw7OviJenP0c0uWqDWF8EGSyMhB3txqhOtiQIDAQAB",
+  "name": "Bookmark Manager",
+  "version": "0.1",
+  "description": "Bookmark Manager",
+  "icons": {
+    "16": "images/bookmarks_favicon.png"
+  },
+  "permissions": [
+    "bookmarks",
+    "experimental",
+    "tabs"
+  ],
+  "chrome_url_overrides": {
+    "bookmarks": "main.html"
+  }
+}
diff --git a/resources/inspector/BottomUpProfileDataGridTree.js b/resources/inspector/BottomUpProfileDataGridTree.js
deleted file mode 100755
index 41a8a3a..0000000
--- a/resources/inspector/BottomUpProfileDataGridTree.js
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright (C) 2009 280 North Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-// Bottom Up Profiling shows the entire callstack backwards:
-// The root node is a representation of each individual function called, and each child of that node represents
-// a reverse-callstack showing how many of those calls came from it. So, unlike top-down, the statistics in
-// each child still represent the root node. We have to be particularly careful of recursion with this mode
-// because a root node can represent itself AND an ancestor.
-
-WebInspector.BottomUpProfileDataGridNode = function(/*ProfileView*/ profileView, /*ProfileNode*/ profileNode, /*BottomUpProfileDataGridTree*/ owningTree)
-{
-    // In bottom up mode, our parents are our children since we display an inverted tree.
-    // However, we don't want to show the very top parent since it is redundant.
-    var hasChildren = !!(profileNode.parent && profileNode.parent.parent);
-
-    WebInspector.ProfileDataGridNode.call(this, profileView, profileNode, owningTree, hasChildren);
-
-    this._remainingNodeInfos = [];
-}
-
-WebInspector.BottomUpProfileDataGridNode.prototype = {
-    _takePropertiesFromProfileDataGridNode: function(/*ProfileDataGridNode*/ profileDataGridNode)
-    {
-        this._save();
-
-        this.selfTime = profileDataGridNode.selfTime;
-        this.totalTime = profileDataGridNode.totalTime;
-        this.numberOfCalls = profileDataGridNode.numberOfCalls;
-    },
-
-    // When focusing, we keep just the members of the callstack.
-    _keepOnlyChild: function(/*ProfileDataGridNode*/ child)
-    {
-        this._save();
-
-        this.removeChildren();
-        this.appendChild(child);
-    },
-
-    _exclude: function(aCallUID)
-    {
-        if (this._remainingNodeInfos)
-            this._populate();
-
-        this._save();
-
-        var children = this.children;
-        var index = this.children.length;
-
-        while (index--)
-            children[index]._exclude(aCallUID);
-
-        var child = this.childrenByCallUID[aCallUID];
-
-        if (child)
-            this._merge(child, true);
-    },
-
-    _merge: function(/*ProfileDataGridNode*/ child, /*Boolean*/ shouldAbsorb)
-    {
-        this.selfTime -= child.selfTime;
-
-        WebInspector.ProfileDataGridNode.prototype._merge.call(this, child, shouldAbsorb);
-    },
-
-    _sharedPopulate: function()
-    {
-        var remainingNodeInfos = this._remainingNodeInfos;
-        var count = remainingNodeInfos.length;
-
-        for (var index = 0; index < count; ++index) {
-            var nodeInfo = remainingNodeInfos[index];
-            var ancestor = nodeInfo.ancestor;
-            var focusNode = nodeInfo.focusNode;
-            var child = this.findChild(ancestor);
-
-            // If we already have this child, then merge the data together.
-            if (child) {
-                var totalTimeAccountedFor = nodeInfo.totalTimeAccountedFor;
-
-                child.selfTime += focusNode.selfTime;
-                child.numberOfCalls += focusNode.numberOfCalls;
-
-                if (!totalTimeAccountedFor)
-                    child.totalTime += focusNode.totalTime;
-            } else {
-                // If not, add it as a true ancestor.
-                // In heavy mode, we take our visual identity from ancestor node...
-                var child = new WebInspector.BottomUpProfileDataGridNode(this.profileView, ancestor, this.tree);
-
-                if (ancestor !== focusNode) {
-                    // but the actual statistics from the "root" node (bottom of the callstack).
-                    child.selfTime = focusNode.selfTime;
-                    child.totalTime = focusNode.totalTime;
-                    child.numberOfCalls = focusNode.numberOfCalls;
-                }
-
-                this.appendChild(child);
-            }
-
-            var parent = ancestor.parent;
-            if (parent && parent.parent) {
-                nodeInfo.ancestor = parent;
-                child._remainingNodeInfos.push(nodeInfo);
-            }
-        }
-
-        delete this._remainingNodeInfos;
-    }
-}
-
-WebInspector.BottomUpProfileDataGridNode.prototype.__proto__ = WebInspector.ProfileDataGridNode.prototype;
-
-WebInspector.BottomUpProfileDataGridTree = function(/*ProfileView*/ aProfileView, /*ProfileNode*/ aProfileNode)
-{
-    WebInspector.ProfileDataGridTree.call(this, aProfileView, aProfileNode);
-
-    // Iterate each node in pre-order.
-    var profileNodeUIDs = 0;
-    var profileNodeGroups = [[], [aProfileNode]];
-    var visitedProfileNodesForCallUID = {};
-
-    this._remainingNodeInfos = [];
-
-    for (var profileNodeGroupIndex = 0; profileNodeGroupIndex < profileNodeGroups.length; ++profileNodeGroupIndex) {
-        var parentProfileNodes = profileNodeGroups[profileNodeGroupIndex];
-        var profileNodes = profileNodeGroups[++profileNodeGroupIndex];
-        var count = profileNodes.length;
-
-        for (var index = 0; index < count; ++index) {
-            var profileNode = profileNodes[index];
-
-            if (!profileNode.UID)
-                profileNode.UID = ++profileNodeUIDs;
-
-            if (profileNode.head && profileNode !== profileNode.head) {
-                // The total time of this ancestor is accounted for if we're in any form of recursive cycle.
-                var visitedNodes = visitedProfileNodesForCallUID[profileNode.callUID];
-                var totalTimeAccountedFor = false;
-
-                if (!visitedNodes) {
-                    visitedNodes = {}
-                    visitedProfileNodesForCallUID[profileNode.callUID] = visitedNodes;
-                } else {
-                    // The total time for this node has already been accounted for iff one of it's parents has already been visited.
-                    // We can do this check in this style because we are traversing the tree in pre-order.
-                    var parentCount = parentProfileNodes.length;
-                    for (var parentIndex = 0; parentIndex < parentCount; ++parentIndex) {
-                        if (visitedNodes[parentProfileNodes[parentIndex].UID]) {
-                            totalTimeAccountedFor = true;
-                            break;
-                        }
-                    }
-                }
-
-                visitedNodes[profileNode.UID] = true;
-
-                this._remainingNodeInfos.push({ ancestor:profileNode, focusNode:profileNode, totalTimeAccountedFor:totalTimeAccountedFor });
-            }
-
-            var children = profileNode.children;
-            if (children.length) {
-                profileNodeGroups.push(parentProfileNodes.concat([profileNode]))
-                profileNodeGroups.push(children);
-            }
-        }
-    }
-
-    // Populate the top level nodes.
-    WebInspector.BottomUpProfileDataGridNode.prototype._populate.call(this);
-
-    return this;
-}
-
-WebInspector.BottomUpProfileDataGridTree.prototype = {
-    // When focusing, we keep the entire callstack up to this ancestor.
-    focus: function(/*ProfileDataGridNode*/ profileDataGridNode)
-    {
-        if (!profileDataGridNode)
-            return;
-
-        this._save();
-
-        var currentNode = profileDataGridNode;
-        var focusNode = profileDataGridNode;
-
-        while (currentNode.parent && (currentNode instanceof WebInspector.ProfileDataGridNode)) {
-            currentNode._takePropertiesFromProfileDataGridNode(profileDataGridNode);
-
-            focusNode = currentNode;
-            currentNode = currentNode.parent;
-
-            if (currentNode instanceof WebInspector.ProfileDataGridNode)
-                currentNode._keepOnlyChild(focusNode);
-        }
-
-        this.children = [focusNode];
-        this.totalTime = profileDataGridNode.totalTime;
-    },
-
-    exclude: function(/*ProfileDataGridNode*/ profileDataGridNode)
-    {
-        if (!profileDataGridNode)
-            return;
-
-        this._save();
-
-        var excludedCallUID = profileDataGridNode.callUID;
-        var excludedTopLevelChild = this.childrenByCallUID[excludedCallUID];
-
-        // If we have a top level node that is excluded, get rid of it completely (not keeping children),
-        // since bottom up data relies entirely on the root node.
-        if (excludedTopLevelChild)
-            this.children.remove(excludedTopLevelChild);
-
-        var children = this.children;
-        var count = children.length;
-
-        for (var index = 0; index < count; ++index)
-            children[index]._exclude(excludedCallUID);
-
-        if (this.lastComparator)
-            this.sort(this.lastComparator, true);
-    },
-
-    _sharedPopulate: WebInspector.BottomUpProfileDataGridNode.prototype._sharedPopulate
-}
-
-WebInspector.BottomUpProfileDataGridTree.prototype.__proto__ = WebInspector.ProfileDataGridTree.prototype;
-
diff --git a/resources/inspector/Breakpoint.js b/resources/inspector/Breakpoint.js
deleted file mode 100755
index 292975a..0000000
--- a/resources/inspector/Breakpoint.js
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WebInspector.Breakpoint = function(url, line, sourceID, condition)
-{
-    this.url = url;
-    this.line = line;
-    this.sourceID = sourceID;
-    this._enabled = true;
-    this._sourceText = "";
-    this._condition = condition || "";
-}
-
-WebInspector.Breakpoint.prototype = {
-    get enabled()
-    {
-        return this._enabled;
-    },
-
-    set enabled(x)
-    {
-        if (this._enabled === x)
-            return;
-
-        this._enabled = x;
-
-        if (this._enabled)
-            this.dispatchEventToListeners("enabled");
-        else
-            this.dispatchEventToListeners("disabled");
-    },
-
-    get sourceText()
-    {
-        return this._sourceText;
-    },
-
-    set sourceText(text)
-    {
-        this._sourceText = text;
-        this.dispatchEventToListeners("text-changed");
-    },
-
-    get label()
-    {
-        var displayName = (this.url ? WebInspector.displayNameForURL(this.url) : WebInspector.UIString("(program)"));
-        return displayName + ":" + this.line;
-    },
-
-    get id()
-    {
-        return this.sourceID + ":" + this.line;
-    },
-
-    get condition()
-    {
-        return this._condition;
-    },
-
-    set condition(c)
-    {
-        c = c || "";
-        if (this._condition === c)
-            return;
-
-        this._condition = c;
-        this.dispatchEventToListeners("condition-changed");
-
-        if (this.enabled)
-            InspectorController.updateBreakpoint(this.sourceID, this.line, c);
-    }
-}
-
-WebInspector.Breakpoint.prototype.__proto__ = WebInspector.Object.prototype;
diff --git a/resources/inspector/BreakpointsSidebarPane.js b/resources/inspector/BreakpointsSidebarPane.js
deleted file mode 100755
index e6edece..0000000
--- a/resources/inspector/BreakpointsSidebarPane.js
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WebInspector.BreakpointsSidebarPane = function()
-{
-    WebInspector.SidebarPane.call(this, WebInspector.UIString("Breakpoints"));
-
-    this.breakpoints = {};
-
-    this.listElement = document.createElement("ol");
-    this.listElement.className = "breakpoint-list";
-
-    this.emptyElement = document.createElement("div");
-    this.emptyElement.className = "info";
-    this.emptyElement.textContent = WebInspector.UIString("No Breakpoints");
-
-    this.bodyElement.appendChild(this.emptyElement);
-}
-
-WebInspector.BreakpointsSidebarPane.prototype = {
-    addBreakpoint: function(breakpoint)
-    {
-        if (this.breakpoints[breakpoint.id])
-            return;
-
-        this.breakpoints[breakpoint.id] = breakpoint;
-
-        breakpoint.addEventListener("enabled", this._breakpointEnableChanged, this);
-        breakpoint.addEventListener("disabled", this._breakpointEnableChanged, this);
-        breakpoint.addEventListener("text-changed", this._breakpointTextChanged, this);
-
-        this._appendBreakpointElement(breakpoint);
-
-        if (this.emptyElement.parentElement) {
-            this.bodyElement.removeChild(this.emptyElement);
-            this.bodyElement.appendChild(this.listElement);
-        }
-
-        if (!InspectorController.debuggerEnabled() || !breakpoint.sourceID)
-            return;
-
-        if (breakpoint.enabled)
-            InspectorController.addBreakpoint(breakpoint.sourceID, breakpoint.line, breakpoint.condition);
-    },
-
-    _appendBreakpointElement: function(breakpoint)
-    {
-        function checkboxClicked()
-        {
-            breakpoint.enabled = !breakpoint.enabled;
-        }
-
-        function labelClicked()
-        {
-            var script = WebInspector.panels.scripts.scriptOrResourceForID(breakpoint.sourceID);
-            if (script)
-                WebInspector.panels.scripts.showScript(script, breakpoint.line);
-        }
-
-        var breakpointElement = document.createElement("li");
-        breakpoint._breakpointListElement = breakpointElement;
-        breakpointElement._breakpointObject = breakpoint;
-
-        var checkboxElement = document.createElement("input");
-        checkboxElement.className = "checkbox-elem";
-        checkboxElement.type = "checkbox";
-        checkboxElement.checked = breakpoint.enabled;
-        checkboxElement.addEventListener("click", checkboxClicked, false);
-        breakpointElement.appendChild(checkboxElement);
-
-        var labelElement = document.createElement("a");
-        labelElement.textContent = breakpoint.label;
-        labelElement.addEventListener("click", labelClicked, false);
-        breakpointElement.appendChild(labelElement);
-
-        var sourceTextElement = document.createElement("div");
-        sourceTextElement.textContent = breakpoint.sourceText;
-        sourceTextElement.className = "source-text";
-        breakpointElement.appendChild(sourceTextElement);
-
-        var currentElement = this.listElement.firstChild;
-        while (currentElement) {
-            var currentBreak = currentElement._breakpointObject;
-            if (currentBreak.url > breakpoint.url) {
-                this.listElement.insertBefore(breakpointElement, currentElement);
-                return;
-            } else if (currentBreak.url == breakpoint.url && currentBreak.line > breakpoint.line) {
-                this.listElement.insertBefore(breakpointElement, currentElement);
-                return;
-            }
-            currentElement = currentElement.nextSibling;
-        }
-        this.listElement.appendChild(breakpointElement);
-    },
-
-    removeBreakpoint: function(breakpoint)
-    {
-        if (!this.breakpoints[breakpoint.id])
-            return;
-        delete this.breakpoints[breakpoint.id];
-
-        breakpoint.removeEventListener("enabled", null, this);
-        breakpoint.removeEventListener("disabled", null, this);
-        breakpoint.removeEventListener("text-changed", null, this);
-
-        var element = breakpoint._breakpointListElement;
-        element.parentElement.removeChild(element);
-
-        if (!this.listElement.firstChild) {
-            this.bodyElement.removeChild(this.listElement);
-            this.bodyElement.appendChild(this.emptyElement);
-        }
-
-        if (!InspectorController.debuggerEnabled() || !breakpoint.sourceID)
-            return;
-
-        InspectorController.removeBreakpoint(breakpoint.sourceID, breakpoint.line);
-    },
-
-    _breakpointEnableChanged: function(event)
-    {
-        var breakpoint = event.target;
-
-        var checkbox = breakpoint._breakpointListElement.firstChild;
-        checkbox.checked = breakpoint.enabled;
-
-        if (!InspectorController.debuggerEnabled() || !breakpoint.sourceID)
-            return;
-
-        if (breakpoint.enabled)
-            InspectorController.addBreakpoint(breakpoint.sourceID, breakpoint.line, breakpoint.condition);
-        else
-            InspectorController.removeBreakpoint(breakpoint.sourceID, breakpoint.line);
-    },
-
-    _breakpointTextChanged: function(event)
-    {
-        var breakpoint = event.target;
-
-        var sourceTextElement = breakpoint._breakpointListElement.firstChild.nextSibling.nextSibling;
-        sourceTextElement.textContent = breakpoint.sourceText;
-    }
-}
-
-WebInspector.BreakpointsSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype;
diff --git a/resources/inspector/CallStackSidebarPane.js b/resources/inspector/CallStackSidebarPane.js
deleted file mode 100755
index 2fe4315..0000000
--- a/resources/inspector/CallStackSidebarPane.js
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WebInspector.CallStackSidebarPane = function()
-{
-    WebInspector.SidebarPane.call(this, WebInspector.UIString("Call Stack"));
-    
-    this._shortcuts = {};
-
-    var shortcut = WebInspector.KeyboardShortcut.makeKey(WebInspector.KeyboardShortcut.KeyCodes.Period,
-                                                         WebInspector.KeyboardShortcut.Modifiers.Ctrl);
-    this._shortcuts[shortcut] = this._selectNextCallFrameOnStack.bind(this);
-
-    var shortcut = WebInspector.KeyboardShortcut.makeKey(WebInspector.KeyboardShortcut.KeyCodes.Comma,
-                                                         WebInspector.KeyboardShortcut.Modifiers.Ctrl);
-    this._shortcuts[shortcut] = this._selectPreviousCallFrameOnStack.bind(this);
-}
-
-WebInspector.CallStackSidebarPane.prototype = {
-    update: function(callFrames, sourceIDMap)
-    {
-        this.bodyElement.removeChildren();
-
-        this.placards = [];
-        delete this._selectedCallFrame;
-
-        if (!callFrames) {
-            var infoElement = document.createElement("div");
-            infoElement.className = "info";
-            infoElement.textContent = WebInspector.UIString("Not Paused");
-            this.bodyElement.appendChild(infoElement);
-            return;
-        }
-
-        var title;
-        var subtitle;
-        var scriptOrResource;
-
-        for (var i = 0; i < callFrames.length; ++i) {
-            var callFrame = callFrames[i];
-            switch (callFrame.type) {
-            case "function":
-                title = callFrame.functionName || WebInspector.UIString("(anonymous function)");
-                break;
-            case "program":
-                title = WebInspector.UIString("(program)");
-                break;
-            }
-
-            scriptOrResource = sourceIDMap[callFrame.sourceID];
-            subtitle = WebInspector.displayNameForURL(scriptOrResource.sourceURL || scriptOrResource.url);
-
-            if (callFrame.line > 0) {
-                if (subtitle)
-                    subtitle += ":" + callFrame.line;
-                else
-                    subtitle = WebInspector.UIString("line %d", callFrame.line);
-            }
-
-            var placard = new WebInspector.Placard(title, subtitle);
-            placard.callFrame = callFrame;
-
-            placard.element.addEventListener("click", this._placardSelected.bind(this), false);
-
-            this.placards.push(placard);
-            this.bodyElement.appendChild(placard.element);
-        }
-    },
-
-    get selectedCallFrame()
-    {
-        return this._selectedCallFrame;
-    },
-
-    set selectedCallFrame(x)
-    {
-        if (this._selectedCallFrame === x)
-            return;
-
-        this._selectedCallFrame = x;
-
-        for (var i = 0; i < this.placards.length; ++i) {
-            var placard = this.placards[i];
-            placard.selected = (placard.callFrame === this._selectedCallFrame);
-        }
-
-        this.dispatchEventToListeners("call frame selected");
-    },
-
-    handleKeyEvent: function(event)
-    {
-        var shortcut = WebInspector.KeyboardShortcut.makeKeyFromEvent(event);
-        var handler = this._shortcuts[shortcut];
-        if (handler) {
-            handler(event);
-            event.preventDefault();
-            event.handled = true;
-        }
-    },
-
-    _selectNextCallFrameOnStack: function()
-    {
-        var index = this._selectedCallFrameIndex();
-        if (index == -1)
-            return;
-        this._selectedPlacardByIndex(index + 1);
-    },
-
-    _selectPreviousCallFrameOnStack: function()
-    {
-        var index = this._selectedCallFrameIndex();
-        if (index == -1)
-            return;
-        this._selectedPlacardByIndex(index - 1);
-    },
-
-    _selectedPlacardByIndex: function(index)
-    {
-        if (index < 0 || index >= this.placards.length)
-            return;
-        var placard = this.placards[index];
-        this.selectedCallFrame = placard.callFrame
-    },
-
-    _selectedCallFrameIndex: function()
-    {
-        if (!this._selectedCallFrame)
-            return -1;
-        for (var i = 0; i < this.placards.length; ++i) {
-            var placard = this.placards[i];
-            if (placard.callFrame === this._selectedCallFrame)
-                return i;
-        }
-        return -1;
-    },
-
-    _placardSelected: function(event)
-    {
-        var placardElement = event.target.enclosingNodeOrSelfWithClass("placard");
-        this.selectedCallFrame = placardElement.placard.callFrame;
-    }
-}
-
-WebInspector.CallStackSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype;
diff --git a/resources/inspector/Callback.js b/resources/inspector/Callback.js
deleted file mode 100755
index 8ae7f95..0000000
--- a/resources/inspector/Callback.js
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WebInspector.Callback = function()
-{
-    this._lastCallbackId = 1;
-    this._callbacks = {};
-}
-
-WebInspector.Callback.prototype = {
-    wrap: function(callback)
-    {
-        var callbackId = this._lastCallbackId++;
-        this._callbacks[callbackId] = callback || function() {};
-        return callbackId;
-    },
-
-    processCallback: function(callbackId, opt_vararg)
-    {
-        var args = Array.prototype.slice.call(arguments, 1);
-        var callback = this._callbacks[callbackId];
-        callback.apply(null, args);
-        delete this._callbacks[callbackId];
-    }
-}
-
-WebInspector.Callback._INSTANCE = new WebInspector.Callback();
-WebInspector.Callback.wrap = WebInspector.Callback._INSTANCE.wrap.bind(WebInspector.Callback._INSTANCE);
-WebInspector.Callback.processCallback = WebInspector.Callback._INSTANCE.processCallback.bind(WebInspector.Callback._INSTANCE);
diff --git a/resources/inspector/ChangesView.js b/resources/inspector/ChangesView.js
deleted file mode 100755
index 802fdba..0000000
--- a/resources/inspector/ChangesView.js
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2007, 2008 Apple Inc.  All rights reserved.
- * Copyright (C) 2009 Joseph Pecoraro
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer. 
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution. 
- * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- *     its contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission. 
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WebInspector.ChangesView = function(drawer)
-{
-    WebInspector.View.call(this);
-    this.element.innerHTML = "<div style=\"bottom:25%;color:rgb(192,192,192);font-size:12px;height:65px;left:0px;margin:auto;position:absolute;right:0px;text-align:center;top:0px;\"><h1>Not Implemented Yet</h1></div>";
-
-    this.drawer = drawer;
-
-    this.clearButton = document.createElement("button");
-    this.clearButton.id = "clear-changes-status-bar-item";
-    this.clearButton.title = WebInspector.UIString("Clear changes log.");
-    this.clearButton.className = "status-bar-item";
-    this.clearButton.addEventListener("click", this._clearButtonClicked.bind(this), false);
-
-    this.toggleChangesButton = document.getElementById("changes-status-bar-item");
-    this.toggleChangesButton.title = WebInspector.UIString("Show changes view.");
-    this.toggleChangesButton.addEventListener("click", this._toggleChangesButtonClicked.bind(this), false);
-    var anchoredStatusBar = document.getElementById("anchored-status-bar-items");
-    anchoredStatusBar.appendChild(this.toggleChangesButton);
-}
-
-WebInspector.ChangesView.prototype = {
-    _clearButtonClicked: function()
-    {
-        // Not Implemented Yet
-    },
-
-    _toggleChangesButtonClicked: function()
-    {
-        this.drawer.visibleView = this;
-    },
-
-    attach: function(mainElement, statusBarElement)
-    {
-        mainElement.appendChild(this.element);
-        statusBarElement.appendChild(this.clearButton);
-    },
-
-    show: function()
-    {
-        this.toggleChangesButton.addStyleClass("toggled-on");
-        this.toggleChangesButton.title = WebInspector.UIString("Hide changes view.");
-    },
-
-    hide: function()
-    {
-        this.toggleChangesButton.removeStyleClass("toggled-on");
-        this.toggleChangesButton.title = WebInspector.UIString("Show changes view.");
-    }
-}
-
-WebInspector.ChangesView.prototype.__proto__ = WebInspector.View.prototype;
diff --git a/resources/inspector/Color.js b/resources/inspector/Color.js
deleted file mode 100755
index 9d9cd76..0000000
--- a/resources/inspector/Color.js
+++ /dev/null
@@ -1,661 +0,0 @@
-/*
- * Copyright (C) 2009 Apple Inc.  All rights reserved.
- * Copyright (C) 2009 Joseph Pecoraro
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- *     its contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WebInspector.Color = function(str)
-{
-    this.value = str;
-    this._parse();
-}
-
-WebInspector.Color.prototype = {
-    get shorthex()
-    {
-        if ("_short" in this)
-            return this._short;
-
-        if (!this.simple)
-            return null;
-
-        var hex = this.hex;
-        if (hex.charAt(0) === hex.charAt(1) && hex.charAt(2) === hex.charAt(3) && hex.charAt(4) === hex.charAt(5))
-            this._short = hex.charAt(0) + hex.charAt(2) + hex.charAt(4);
-        else
-            this._short = hex;
-
-        return this._short;
-    },
-
-    get hex()
-    {
-        if (!this.simple)
-            return null;
-
-        return this._hex;
-    },
-
-    set hex(x)
-    {
-        this._hex = x;
-    },
-
-    get rgb()
-    {
-        if ("_rgb" in this)
-            return this._rgb;
-
-        if (this.simple)
-            this._rgb = this._hexToRGB(this.hex);
-        else {
-            var rgba = this.rgba;
-            this._rgb = [rgba[0], rgba[1], rgba[2]];
-        }
-
-        return this._rgb;
-    },
-
-    set rgb(x)
-    {
-        this._rgb = x;
-    },
-
-    get hsl()
-    {
-        if ("_hsl" in this)
-            return this._hsl;
-
-        this._hsl = this._rgbToHSL(this.rgb);
-        return this._hsl;
-    },
-
-    set hsl(x)
-    {
-        this._hsl = x;
-    },
-
-    get nickname()
-    {
-        if (typeof this._nickname !== "undefined") // would be set on parse if there was a nickname
-            return this._nickname;
-        else
-            return null;
-    },
-
-    set nickname(x)
-    {
-        this._nickname = x;
-    },
-
-    get rgba()
-    {
-        return this._rgba;
-    },
-
-    set rgba(x)
-    {
-        this._rgba = x;
-    },
-
-    get hsla()
-    {
-        return this._hsla;
-    },
-
-    set hsla(x)
-    {
-        this._hsla = x;
-    },
-
-    hasShortHex: function()
-    {
-        var shorthex = this.shorthex;
-        return (shorthex && shorthex.length === 3);
-    },
-
-    toString: function(format)
-    {
-        if (!format)
-            format = this.format;
-
-        switch (format) {
-            case "rgb":
-                return "rgb(" + this.rgb.join(", ") + ")";
-            case "rgba":
-                return "rgba(" + this.rgba.join(", ") + ")";
-            case "hsl":
-                var hsl = this.hsl;
-                return "hsl(" + hsl[0] + ", " + hsl[1] + "%, " + hsl[2] + "%)";
-            case "hsla":
-                var hsla = this.hsla;
-                return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, " + hsla[3] + ")";
-            case "hex":
-                return "#" + this.hex;
-            case "shorthex":
-                return "#" + this.shorthex;
-            case "nickname":
-                return this.nickname;
-        }
-
-        throw "invalid color format";
-    },
-
-    _rgbToHex: function(rgb)
-    {
-        var r = parseInt(rgb[0]).toString(16);
-        var g = parseInt(rgb[1]).toString(16);
-        var b = parseInt(rgb[2]).toString(16);
-        if (r.length === 1)
-            r = "0" + r;
-        if (g.length === 1)
-            g = "0" + g;
-        if (b.length === 1)
-            b = "0" + b;
-
-        return (r + g + b).toUpperCase();
-    },
-
-    _hexToRGB: function(hex)
-    {
-        var r = parseInt(hex.substring(0,2), 16);
-        var g = parseInt(hex.substring(2,4), 16);
-        var b = parseInt(hex.substring(4,6), 16);
-
-        return [r, g, b];
-    },
-
-    _rgbToHSL: function(rgb)
-    {
-        var r = parseInt(rgb[0]) / 255;
-        var g = parseInt(rgb[1]) / 255;
-        var b = parseInt(rgb[2]) / 255;
-        var max = Math.max(r, g, b);
-        var min = Math.min(r, g, b);
-        var diff = max - min;
-        var add = max + min;
-
-        if (min === max)
-            var h = 0;
-        else if (r === max)
-            var h = ((60 * (g - b) / diff) + 360) % 360;
-        else if (g === max)
-            var h = (60 * (b - r) / diff) + 120;
-        else
-            var h = (60 * (r - g) / diff) + 240;
-
-        var l = 0.5 * add;
-
-        if (l === 0)
-            var s = 0;
-        else if (l === 1)
-            var s = 1;
-        else if (l <= 0.5)
-            var s = diff / add;
-        else
-            var s = diff / (2 - add);
-
-        h = Math.round(h);
-        s = Math.round(s*100);
-        l = Math.round(l*100);
-
-        return [h, s, l];
-    },
-
-    _hslToRGB: function(hsl)
-    {
-        var h = parseFloat(hsl[0]) / 360;
-        var s = parseFloat(hsl[1]) / 100;
-        var l = parseFloat(hsl[2]) / 100;
-
-        if (l <= 0.5)
-            var q = l * (1 + s);
-        else
-            var q = l + s - (l * s);
-
-        var p = 2 * l - q;
-
-        var tr = h + (1 / 3);
-        var tg = h;
-        var tb = h - (1 / 3);
-
-        var r = Math.round(hueToRGB(p, q, tr) * 255);
-        var g = Math.round(hueToRGB(p, q, tg) * 255);
-        var b = Math.round(hueToRGB(p, q, tb) * 255);
-        return [r, g, b];
-
-        function hueToRGB(p, q, h) {
-            if (h < 0)
-                h += 1;
-            else if (h > 1)
-                h -= 1;
-
-            if ((h * 6) < 1)
-                return p + (q - p) * h * 6;
-            else if ((h * 2) < 1)
-                return q;
-            else if ((h * 3) < 2)
-                return p + (q - p) * ((2 / 3) - h) * 6;
-            else
-                return p;
-        }
-    },
-
-    _rgbaToHSLA: function(rgba)
-    {
-        var alpha = rgba[3];
-        var hsl = this._rgbToHSL(rgba)
-        hsl.push(alpha);
-        return hsl;
-    },
-
-    _hslaToRGBA: function(hsla)
-    {
-        var alpha = hsla[3];
-        var rgb = this._hslToRGB(hsla);
-        rgb.push(alpha);
-        return rgb;
-    },
-
-    _parse: function()
-    {
-        // Special Values - Advanced but Must Be Parsed First - transparent
-        var value = this.value.toLowerCase().replace(/%|\s+/g, "");
-        if (value in WebInspector.Color.AdvancedNickNames) {
-            this.format = "nickname";
-            var set = WebInspector.Color.AdvancedNickNames[value];
-            this.simple = false;
-            this.rgba = set[0];
-            this.hsla = set[1];
-            this.nickname = set[2];
-            this.alpha = set[0][3];
-            return;
-        }
-
-        // Simple - #hex, rgb(), nickname, hsl()
-        var simple = /^(?:#([0-9a-f]{3,6})|rgb\(([^)]+)\)|(\w+)|hsl\(([^)]+)\))$/i;
-        var match = this.value.match(simple);
-        if (match) {
-            this.simple = true;
-
-            if (match[1]) { // hex
-                var hex = match[1].toUpperCase();
-                if (hex.length === 3) {
-                    this.format = "shorthex";
-                    this.hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2);
-                } else {
-                    this.format = "hex";
-                    this.hex = hex;
-                }
-            } else if (match[2]) { // rgb
-                this.format = "rgb";
-                var rgb = match[2].split(/\s*,\s*/);
-                this.rgb = rgb;
-                this.hex = this._rgbToHex(rgb);
-            } else if (match[3]) { // nickname
-                var nickname = match[3].toLowerCase();
-                if (nickname in WebInspector.Color.Nicknames) {
-                    this.format = "nickname";
-                    this.hex = WebInspector.Color.Nicknames[nickname];
-                } else // unknown name
-                    throw "unknown color name";
-            } else if (match[4]) { // hsl
-                this.format = "hsl";
-                var hsl = match[4].replace(/%g/, "").split(/\s*,\s*/);
-                this.hsl = hsl;
-                this.rgb = this._hslToRGB(hsl);
-                this.hex = this._rgbToHex(this.rgb);
-            }
-
-            // Fill in the values if this is a known hex color
-            var hex = this.hex;
-            if (hex && hex in WebInspector.Color.HexTable) {
-                var set = WebInspector.Color.HexTable[hex];
-                this.rgb = set[0];
-                this.hsl = set[1];
-                this.nickname = set[2];
-            }
-
-            return;
-        }
-
-        // Advanced - rgba(), hsla()
-        var advanced = /^(?:rgba\(([^)]+)\)|hsla\(([^)]+)\))$/;
-        match = this.value.match(advanced);
-        if (match) {
-            this.simple = false;
-            if (match[1]) { // rgba
-                this.format = "rgba";
-                this.rgba = match[1].split(/\s*,\s*/);
-                this.hsla = this._rgbaToHSLA(this.rgba);
-                this.alpha = this.rgba[3];
-            } else if (match[2]) { // hsla
-                this.format = "hsla";
-                this.hsla = match[2].replace(/%/g, "").split(/\s*,\s*/);
-                this.rgba = this._hslaToRGBA(this.hsla);
-                this.alpha = this.hsla[3];
-            }
-
-            return;
-        }
-
-        // Could not parse as a valid color
-        throw "could not parse color";
-    }
-}
-
-// Simple Values: [rgb, hsl, nickname]
-WebInspector.Color.HexTable = {
-    "000000": [[0, 0, 0], [0, 0, 0], "black"],
-    "000080": [[0, 0, 128], [240, 100, 25], "navy"],
-    "00008B": [[0, 0, 139], [240, 100, 27], "darkBlue"],
-    "0000CD": [[0, 0, 205], [240, 100, 40], "mediumBlue"],
-    "0000FF": [[0, 0, 255], [240, 100, 50], "blue"],
-    "006400": [[0, 100, 0], [120, 100, 20], "darkGreen"],
-    "008000": [[0, 128, 0], [120, 100, 25], "green"],
-    "008080": [[0, 128, 128], [180, 100, 25], "teal"],
-    "008B8B": [[0, 139, 139], [180, 100, 27], "darkCyan"],
-    "00BFFF": [[0, 191, 255], [195, 100, 50], "deepSkyBlue"],
-    "00CED1": [[0, 206, 209], [181, 100, 41], "darkTurquoise"],
-    "00FA9A": [[0, 250, 154], [157, 100, 49], "mediumSpringGreen"],
-    "00FF00": [[0, 255, 0], [120, 100, 50], "lime"],
-    "00FF7F": [[0, 255, 127], [150, 100, 50], "springGreen"],
-    "00FFFF": [[0, 255, 255], [180, 100, 50], "cyan"],
-    "191970": [[25, 25, 112], [240, 64, 27], "midnightBlue"],
-    "1E90FF": [[30, 144, 255], [210, 100, 56], "dodgerBlue"],
-    "20B2AA": [[32, 178, 170], [177, 70, 41], "lightSeaGreen"],
-    "228B22": [[34, 139, 34], [120, 61, 34], "forestGreen"],
-    "2E8B57": [[46, 139, 87], [146, 50, 36], "seaGreen"],
-    "2F4F4F": [[47, 79, 79], [180, 25, 25], "darkSlateGray"],
-    "32CD32": [[50, 205, 50], [120, 61, 50], "limeGreen"],
-    "3CB371": [[60, 179, 113], [147, 50, 47], "mediumSeaGreen"],
-    "40E0D0": [[64, 224, 208], [174, 72, 56], "turquoise"],
-    "4169E1": [[65, 105, 225], [225, 73, 57], "royalBlue"],
-    "4682B4": [[70, 130, 180], [207, 44, 49], "steelBlue"],
-    "483D8B": [[72, 61, 139], [248, 39, 39], "darkSlateBlue"],
-    "48D1CC": [[72, 209, 204], [178, 60, 55], "mediumTurquoise"],
-    "4B0082": [[75, 0, 130], [275, 100, 25], "indigo"],
-    "556B2F": [[85, 107, 47], [82, 39, 30], "darkOliveGreen"],
-    "5F9EA0": [[95, 158, 160], [182, 25, 50], "cadetBlue"],
-    "6495ED": [[100, 149, 237], [219, 79, 66], "cornflowerBlue"],
-    "66CDAA": [[102, 205, 170], [160, 51, 60], "mediumAquaMarine"],
-    "696969": [[105, 105, 105], [0, 0, 41], "dimGray"],
-    "6A5ACD": [[106, 90, 205], [248, 53, 58], "slateBlue"],
-    "6B8E23": [[107, 142, 35], [80, 60, 35], "oliveDrab"],
-    "708090": [[112, 128, 144], [210, 13, 50], "slateGray"],
-    "778899": [[119, 136, 153], [210, 14, 53], "lightSlateGray"],
-    "7B68EE": [[123, 104, 238], [249, 80, 67], "mediumSlateBlue"],
-    "7CFC00": [[124, 252, 0], [90, 100, 49], "lawnGreen"],
-    "7FFF00": [[127, 255, 0], [90, 100, 50], "chartreuse"],
-    "7FFFD4": [[127, 255, 212], [160, 100, 75], "aquamarine"],
-    "800000": [[128, 0, 0], [0, 100, 25], "maroon"],
-    "800080": [[128, 0, 128], [300, 100, 25], "purple"],
-    "808000": [[128, 128, 0], [60, 100, 25], "olive"],
-    "808080": [[128, 128, 128], [0, 0, 50], "gray"],
-    "87CEEB": [[135, 206, 235], [197, 71, 73], "skyBlue"],
-    "87CEFA": [[135, 206, 250], [203, 92, 75], "lightSkyBlue"],
-    "8A2BE2": [[138, 43, 226], [271, 76, 53], "blueViolet"],
-    "8B0000": [[139, 0, 0], [0, 100, 27], "darkRed"],
-    "8B008B": [[139, 0, 139], [300, 100, 27], "darkMagenta"],
-    "8B4513": [[139, 69, 19], [25, 76, 31], "saddleBrown"],
-    "8FBC8F": [[143, 188, 143], [120, 25, 65], "darkSeaGreen"],
-    "90EE90": [[144, 238, 144], [120, 73, 75], "lightGreen"],
-    "9370D8": [[147, 112, 219], [260, 60, 65], "mediumPurple"],
-    "9400D3": [[148, 0, 211], [282, 100, 41], "darkViolet"],
-    "98FB98": [[152, 251, 152], [120, 93, 79], "paleGreen"],
-    "9932CC": [[153, 50, 204], [280, 61, 50], "darkOrchid"],
-    "9ACD32": [[154, 205, 50], [80, 61, 50], "yellowGreen"],
-    "A0522D": [[160, 82, 45], [19, 56, 40], "sienna"],
-    "A52A2A": [[165, 42, 42], [0, 59, 41], "brown"],
-    "A9A9A9": [[169, 169, 169], [0, 0, 66], "darkGray"],
-    "ADD8E6": [[173, 216, 230], [195, 53, 79], "lightBlue"],
-    "ADFF2F": [[173, 255, 47], [84, 100, 59], "greenYellow"],
-    "AFEEEE": [[175, 238, 238], [180, 65, 81], "paleTurquoise"],
-    "B0C4DE": [[176, 196, 222], [214, 41, 78], "lightSteelBlue"],
-    "B0E0E6": [[176, 224, 230], [187, 52, 80], "powderBlue"],
-    "B22222": [[178, 34, 34], [0, 68, 42], "fireBrick"],
-    "B8860B": [[184, 134, 11], [43, 89, 38], "darkGoldenRod"],
-    "BA55D3": [[186, 85, 211], [288, 59, 58], "mediumOrchid"],
-    "BC8F8F": [[188, 143, 143], [0, 25, 65], "rosyBrown"],
-    "BDB76B": [[189, 183, 107], [56, 38, 58], "darkKhaki"],
-    "C0C0C0": [[192, 192, 192], [0, 0, 75], "silver"],
-    "C71585": [[199, 21, 133], [322, 81, 43], "mediumVioletRed"],
-    "CD5C5C": [[205, 92, 92], [0, 53, 58], "indianRed"],
-    "CD853F": [[205, 133, 63], [30, 59, 53], "peru"],
-    "D2691E": [[210, 105, 30], [25, 75, 47], "chocolate"],
-    "D2B48C": [[210, 180, 140], [34, 44, 69], "tan"],
-    "D3D3D3": [[211, 211, 211], [0, 0, 83], "lightGrey"],
-    "D87093": [[219, 112, 147], [340, 60, 65], "paleVioletRed"],
-    "D8BFD8": [[216, 191, 216], [300, 24, 80], "thistle"],
-    "DA70D6": [[218, 112, 214], [302, 59, 65], "orchid"],
-    "DAA520": [[218, 165, 32], [43, 74, 49], "goldenRod"],
-    "DC143C": [[237, 164, 61], [35, 83, 58], "crimson"],
-    "DCDCDC": [[220, 220, 220], [0, 0, 86], "gainsboro"],
-    "DDA0DD": [[221, 160, 221], [300, 47, 75], "plum"],
-    "DEB887": [[222, 184, 135], [34, 57, 70], "burlyWood"],
-    "E0FFFF": [[224, 255, 255], [180, 100, 94], "lightCyan"],
-    "E6E6FA": [[230, 230, 250], [240, 67, 94], "lavender"],
-    "E9967A": [[233, 150, 122], [15, 72, 70], "darkSalmon"],
-    "EE82EE": [[238, 130, 238], [300, 76, 72], "violet"],
-    "EEE8AA": [[238, 232, 170], [55, 67, 80], "paleGoldenRod"],
-    "F08080": [[240, 128, 128], [0, 79, 72], "lightCoral"],
-    "F0E68C": [[240, 230, 140], [54, 77, 75], "khaki"],
-    "F0F8FF": [[240, 248, 255], [208, 100, 97], "aliceBlue"],
-    "F0FFF0": [[240, 255, 240], [120, 100, 97], "honeyDew"],
-    "F0FFFF": [[240, 255, 255], [180, 100, 97], "azure"],
-    "F4A460": [[244, 164, 96], [28, 87, 67], "sandyBrown"],
-    "F5DEB3": [[245, 222, 179], [39, 77, 83], "wheat"],
-    "F5F5DC": [[245, 245, 220], [60, 56, 91], "beige"],
-    "F5F5F5": [[245, 245, 245], [0, 0, 96], "whiteSmoke"],
-    "F5FFFA": [[245, 255, 250], [150, 100, 98], "mintCream"],
-    "F8F8FF": [[248, 248, 255], [240, 100, 99], "ghostWhite"],
-    "FA8072": [[250, 128, 114], [6, 93, 71], "salmon"],
-    "FAEBD7": [[250, 235, 215], [34, 78, 91], "antiqueWhite"],
-    "FAF0E6": [[250, 240, 230], [30, 67, 94], "linen"],
-    "FAFAD2": [[250, 250, 210], [60, 80, 90], "lightGoldenRodYellow"],
-    "FDF5E6": [[253, 245, 230], [39, 85, 95], "oldLace"],
-    "FF0000": [[255, 0, 0], [0, 100, 50], "red"],
-    "FF00FF": [[255, 0, 255], [300, 100, 50], "magenta"],
-    "FF1493": [[255, 20, 147], [328, 100, 54], "deepPink"],
-    "FF4500": [[255, 69, 0], [16, 100, 50], "orangeRed"],
-    "FF6347": [[255, 99, 71], [9, 100, 64], "tomato"],
-    "FF69B4": [[255, 105, 180], [330, 100, 71], "hotPink"],
-    "FF7F50": [[255, 127, 80], [16, 100, 66], "coral"],
-    "FF8C00": [[255, 140, 0], [33, 100, 50], "darkOrange"],
-    "FFA07A": [[255, 160, 122], [17, 100, 74], "lightSalmon"],
-    "FFA500": [[255, 165, 0], [39, 100, 50], "orange"],
-    "FFB6C1": [[255, 182, 193], [351, 100, 86], "lightPink"],
-    "FFC0CB": [[255, 192, 203], [350, 100, 88], "pink"],
-    "FFD700": [[255, 215, 0], [51, 100, 50], "gold"],
-    "FFDAB9": [[255, 218, 185], [28, 100, 86], "peachPuff"],
-    "FFDEAD": [[255, 222, 173], [36, 100, 84], "navajoWhite"],
-    "FFE4B5": [[255, 228, 181], [38, 100, 85], "moccasin"],
-    "FFE4C4": [[255, 228, 196], [33, 100, 88], "bisque"],
-    "FFE4E1": [[255, 228, 225], [6, 100, 94], "mistyRose"],
-    "FFEBCD": [[255, 235, 205], [36, 100, 90], "blanchedAlmond"],
-    "FFEFD5": [[255, 239, 213], [37, 100, 92], "papayaWhip"],
-    "FFF0F5": [[255, 240, 245], [340, 100, 97], "lavenderBlush"],
-    "FFF5EE": [[255, 245, 238], [25, 100, 97], "seaShell"],
-    "FFF8DC": [[255, 248, 220], [48, 100, 93], "cornsilk"],
-    "FFFACD": [[255, 250, 205], [54, 100, 90], "lemonChiffon"],
-    "FFFAF0": [[255, 250, 240], [40, 100, 97], "floralWhite"],
-    "FFFAFA": [[255, 250, 250], [0, 100, 99], "snow"],
-    "FFFF00": [[255, 255, 0], [60, 100, 50], "yellow"],
-    "FFFFE0": [[255, 255, 224], [60, 100, 94], "lightYellow"],
-    "FFFFF0": [[255, 255, 240], [60, 100, 97], "ivory"],
-    "FFFFFF": [[255, 255, 255], [0, 100, 100], "white"]
-};
-
-// Simple Values
-WebInspector.Color.Nicknames = {
-    "aliceblue": "F0F8FF",
-    "antiquewhite": "FAEBD7",
-    "aqua": "00FFFF",
-    "aquamarine": "7FFFD4",
-    "azure": "F0FFFF",
-    "beige": "F5F5DC",
-    "bisque": "FFE4C4",
-    "black": "000000",
-    "blanchedalmond": "FFEBCD",
-    "blue": "0000FF",
-    "blueviolet": "8A2BE2",
-    "brown": "A52A2A",
-    "burlywood": "DEB887",
-    "cadetblue": "5F9EA0",
-    "chartreuse": "7FFF00",
-    "chocolate": "D2691E",
-    "coral": "FF7F50",
-    "cornflowerblue": "6495ED",
-    "cornsilk": "FFF8DC",
-    "crimson": "DC143C",
-    "cyan": "00FFFF",
-    "darkblue": "00008B",
-    "darkcyan": "008B8B",
-    "darkgoldenrod": "B8860B",
-    "darkgray": "A9A9A9",
-    "darkgreen": "006400",
-    "darkkhaki": "BDB76B",
-    "darkmagenta": "8B008B",
-    "darkolivegreen": "556B2F",
-    "darkorange": "FF8C00",
-    "darkorchid": "9932CC",
-    "darkred": "8B0000",
-    "darksalmon": "E9967A",
-    "darkseagreen": "8FBC8F",
-    "darkslateblue": "483D8B",
-    "darkslategray": "2F4F4F",
-    "darkturquoise": "00CED1",
-    "darkviolet": "9400D3",
-    "deeppink": "FF1493",
-    "deepskyblue": "00BFFF",
-    "dimgray": "696969",
-    "dodgerblue": "1E90FF",
-    "firebrick": "B22222",
-    "floralwhite": "FFFAF0",
-    "forestgreen": "228B22",
-    "fuchsia": "FF00FF",
-    "gainsboro": "DCDCDC",
-    "ghostwhite": "F8F8FF",
-    "gold": "FFD700",
-    "goldenrod": "DAA520",
-    "gray": "808080",
-    "green": "008000",
-    "greenyellow": "ADFF2F",
-    "honeydew": "F0FFF0",
-    "hotpink": "FF69B4",
-    "indianred": "CD5C5C",
-    "indigo": "4B0082",
-    "ivory": "FFFFF0",
-    "khaki": "F0E68C",
-    "lavender": "E6E6FA",
-    "lavenderblush": "FFF0F5",
-    "lawngreen": "7CFC00",
-    "lemonchiffon": "FFFACD",
-    "lightblue": "ADD8E6",
-    "lightcoral": "F08080",
-    "lightcyan": "E0FFFF",
-    "lightgoldenrodyellow": "FAFAD2",
-    "lightgreen": "90EE90",
-    "lightgrey": "D3D3D3",
-    "lightpink": "FFB6C1",
-    "lightsalmon": "FFA07A",
-    "lightseagreen": "20B2AA",
-    "lightskyblue": "87CEFA",
-    "lightslategray": "778899",
-    "lightsteelblue": "B0C4DE",
-    "lightyellow": "FFFFE0",
-    "lime": "00FF00",
-    "limegreen": "32CD32",
-    "linen": "FAF0E6",
-    "magenta": "FF00FF",
-    "maroon": "800000",
-    "mediumaquamarine": "66CDAA",
-    "mediumblue": "0000CD",
-    "mediumorchid": "BA55D3",
-    "mediumpurple": "9370D8",
-    "mediumseagreen": "3CB371",
-    "mediumslateblue": "7B68EE",
-    "mediumspringgreen": "00FA9A",
-    "mediumturquoise": "48D1CC",
-    "mediumvioletred": "C71585",
-    "midnightblue": "191970",
-    "mintcream": "F5FFFA",
-    "mistyrose": "FFE4E1",
-    "moccasin": "FFE4B5",
-    "navajowhite": "FFDEAD",
-    "navy": "000080",
-    "oldlace": "FDF5E6",
-    "olive": "808000",
-    "olivedrab": "6B8E23",
-    "orange": "FFA500",
-    "orangered": "FF4500",
-    "orchid": "DA70D6",
-    "palegoldenrod": "EEE8AA",
-    "palegreen": "98FB98",
-    "paleturquoise": "AFEEEE",
-    "palevioletred": "D87093",
-    "papayawhip": "FFEFD5",
-    "peachpuff": "FFDAB9",
-    "peru": "CD853F",
-    "pink": "FFC0CB",
-    "plum": "DDA0DD",
-    "powderblue": "B0E0E6",
-    "purple": "800080",
-    "red": "FF0000",
-    "rosybrown": "BC8F8F",
-    "royalblue": "4169E1",
-    "saddlebrown": "8B4513",
-    "salmon": "FA8072",
-    "sandybrown": "F4A460",
-    "seagreen": "2E8B57",
-    "seashell": "FFF5EE",
-    "sienna": "A0522D",
-    "silver": "C0C0C0",
-    "skyblue": "87CEEB",
-    "slateblue": "6A5ACD",
-    "slategray": "708090",
-    "snow": "FFFAFA",
-    "springgreen": "00FF7F",
-    "steelblue": "4682B4",
-    "tan": "D2B48C",
-    "teal": "008080",
-    "thistle": "D8BFD8",
-    "tomato": "FF6347",
-    "turquoise": "40E0D0",
-    "violet": "EE82EE",
-    "wheat": "F5DEB3",
-    "white": "FFFFFF",
-    "whitesmoke": "F5F5F5",
-    "yellow": "FFFF00",
-    "yellowgreen": "9ACD32"
-};
-
-// Advanced Values [rgba, hsla, nickname]
-WebInspector.Color.AdvancedNickNames = {
-    "transparent": [[0, 0, 0, 0], [0, 0, 0, 0], "transparent"],
-    "rgba(0,0,0,0)": [[0, 0, 0, 0], [0, 0, 0, 0], "transparent"],
-    "hsla(0,0,0,0)": [[0, 0, 0, 0], [0, 0, 0, 0], "transparent"],
-};
diff --git a/resources/inspector/ConsoleView.js b/resources/inspector/ConsoleView.js
deleted file mode 100755
index 6cbd48a..0000000
--- a/resources/inspector/ConsoleView.js
+++ /dev/null
@@ -1,992 +0,0 @@
-/*
- * Copyright (C) 2007, 2008 Apple Inc.  All rights reserved.
- * Copyright (C) 2009 Joseph Pecoraro
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer. 
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution. 
- * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- *     its contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission. 
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-const ExpressionStopCharacters = " =:[({;,!+-*/&|^<>";
-
-WebInspector.ConsoleView = function(drawer)
-{
-    WebInspector.View.call(this, document.getElementById("console-view"));
-
-    this.messages = [];
-    this.drawer = drawer;
-
-    this.clearButton = document.getElementById("clear-console-status-bar-item");
-    this.clearButton.title = WebInspector.UIString("Clear console log.");
-    this.clearButton.addEventListener("click", this._clearButtonClicked.bind(this), false);
-
-    this.messagesElement = document.getElementById("console-messages");
-    this.messagesElement.addEventListener("selectstart", this._messagesSelectStart.bind(this), false);
-    this.messagesElement.addEventListener("click", this._messagesClicked.bind(this), true);
-
-    this.promptElement = document.getElementById("console-prompt");
-    this.promptElement.handleKeyEvent = this._promptKeyDown.bind(this);
-    this.prompt = new WebInspector.TextPrompt(this.promptElement, this.completions.bind(this), ExpressionStopCharacters + ".");
-
-    this.topGroup = new WebInspector.ConsoleGroup(null, 0);
-    this.messagesElement.insertBefore(this.topGroup.element, this.promptElement);
-    this.groupLevel = 0;
-    this.currentGroup = this.topGroup;
-
-    this.toggleConsoleButton = document.getElementById("console-status-bar-item");
-    this.toggleConsoleButton.title = WebInspector.UIString("Show console.");
-    this.toggleConsoleButton.addEventListener("click", this._toggleConsoleButtonClicked.bind(this), false);
-
-    var anchoredStatusBar = document.getElementById("anchored-status-bar-items");
-    anchoredStatusBar.appendChild(this.toggleConsoleButton);
-    
-    // Will hold the list of filter elements
-    this.filterBarElement = document.getElementById("console-filter");
-    
-    function createDividerElement() {
-        var dividerElement = document.createElement("div");
-        
-        dividerElement.addStyleClass("divider");
-        
-        this.filterBarElement.appendChild(dividerElement);
-    }
-    
-    function createFilterElement(category) {
-        var categoryElement = document.createElement("li");
-        categoryElement.category = category;
-     
-        categoryElement.addStyleClass(categoryElement.category);
-            
-        var label = category.toString();
-        categoryElement.appendChild(document.createTextNode(label));
-     
-        categoryElement.addEventListener("click", this._updateFilter.bind(this), false);
-     
-        this.filterBarElement.appendChild(categoryElement);
-        return categoryElement;
-    }
-    
-    this.allElement = createFilterElement.call(this, "All");
-    
-    createDividerElement.call(this);
-    
-    this.errorElement = createFilterElement.call(this, "Errors");
-    this.warningElement = createFilterElement.call(this, "Warnings");
-    this.logElement = createFilterElement.call(this, "Logs");
-
-    this.filter(this.allElement);
-}
-
-WebInspector.ConsoleView.prototype = {
-    
-    _updateFilter: function(e)
-    {
-        this.filter(e.target);
-    },
-    
-    filter: function(target)
-    {
-        if (target.category == "All") {
-            if (target.hasStyleClass("selected")) {
-                // We can't unselect all, so we break early here
-                return;
-            }
-            
-            this.errorElement.removeStyleClass("selected");
-            this.warningElement.removeStyleClass("selected");
-            this.logElement.removeStyleClass("selected");
-            
-            document.getElementById("console-messages").removeStyleClass("filter-errors");
-            document.getElementById("console-messages").removeStyleClass("filter-warnings");
-            document.getElementById("console-messages").removeStyleClass("filter-logs");
-        } else {
-            // Something other than all is being selected, so we want to unselect all
-            if (this.allElement.hasStyleClass("selected")) {
-                this.allElement.removeStyleClass("selected");
-                document.getElementById("console-messages").removeStyleClass("filter-all");
-            }
-        }
-        
-        if (target.hasStyleClass("selected")) {
-            target.removeStyleClass("selected");
-            var newClass = "filter-" + target.category.toLowerCase();
-            var filterElement = document.getElementById("console-messages");
-            filterElement.removeStyleClass(newClass);
-        } else {
-            target.addStyleClass("selected");
-            var newClass = "filter-" + target.category.toLowerCase();
-            var filterElement = document.getElementById("console-messages");
-            filterElement.addStyleClass(newClass);
-        }
-    },
-    
-    _toggleConsoleButtonClicked: function()
-    {
-        this.drawer.visibleView = this;
-    },
-
-    attach: function(mainElement, statusBarElement)
-    {
-        mainElement.appendChild(this.element);
-        statusBarElement.appendChild(this.clearButton);
-        statusBarElement.appendChild(this.filterBarElement);
-    },
-
-    show: function()
-    {
-        this.toggleConsoleButton.addStyleClass("toggled-on");
-        this.toggleConsoleButton.title = WebInspector.UIString("Hide console.");
-        if (!this.prompt.isCaretInsidePrompt())
-            this.prompt.moveCaretToEndOfPrompt();
-    },
-
-    afterShow: function()
-    {
-        WebInspector.currentFocusElement = this.promptElement;  
-    },
-
-    hide: function()
-    {
-        this.toggleConsoleButton.removeStyleClass("toggled-on");
-        this.toggleConsoleButton.title = WebInspector.UIString("Show console.");
-    },
-
-    addMessage: function(msg)
-    {
-        if (msg instanceof WebInspector.ConsoleMessage && !(msg instanceof WebInspector.ConsoleCommandResult)) {
-            msg.totalRepeatCount = msg.repeatCount;
-            msg.repeatDelta = msg.repeatCount;
-
-            var messageRepeated = false;
-
-            if (msg.isEqual && msg.isEqual(this.previousMessage)) {
-                // Because sometimes we get a large number of repeated messages and sometimes
-                // we get them one at a time, we need to know the difference between how many
-                // repeats we used to have and how many we have now.
-                msg.repeatDelta -= this.previousMessage.totalRepeatCount;
-
-                if (!isNaN(this.repeatCountBeforeCommand))
-                    msg.repeatCount -= this.repeatCountBeforeCommand;
-
-                if (!this.commandSincePreviousMessage) {
-                    // Recreate the previous message element to reset the repeat count.
-                    var messagesElement = this.currentGroup.messagesElement;
-                    messagesElement.removeChild(messagesElement.lastChild);
-                    messagesElement.appendChild(msg.toMessageElement());
-
-                    messageRepeated = true;
-                }
-            } else
-                delete this.repeatCountBeforeCommand;
-
-            // Increment the error or warning count
-            switch (msg.level) {
-            case WebInspector.ConsoleMessage.MessageLevel.Warning:
-                WebInspector.warnings += msg.repeatDelta;
-                break;
-            case WebInspector.ConsoleMessage.MessageLevel.Error:
-                WebInspector.errors += msg.repeatDelta;
-                break;
-            }
-
-            // Add message to the resource panel
-            if (msg.url in WebInspector.resourceURLMap) {
-                msg.resource = WebInspector.resourceURLMap[msg.url];
-                if (WebInspector.panels.resources)
-                    WebInspector.panels.resources.addMessageToResource(msg.resource, msg);
-            }
-
-            this.commandSincePreviousMessage = false;
-            this.previousMessage = msg;
-
-            if (messageRepeated)
-                return;
-        } else if (msg instanceof WebInspector.ConsoleCommand) {
-            if (this.previousMessage) {
-                this.commandSincePreviousMessage = true;
-                this.repeatCountBeforeCommand = this.previousMessage.totalRepeatCount;
-            }
-        }
-
-        this.messages.push(msg);
-
-        if (msg.type === WebInspector.ConsoleMessage.MessageType.EndGroup) {
-            if (this.groupLevel < 1)
-                return;
-
-            this.groupLevel--;
-
-            this.currentGroup = this.currentGroup.parentGroup;
-        } else {
-            if (msg.type === WebInspector.ConsoleMessage.MessageType.StartGroup) {
-                this.groupLevel++;
-
-                var group = new WebInspector.ConsoleGroup(this.currentGroup, this.groupLevel);
-                this.currentGroup.messagesElement.appendChild(group.element);
-                this.currentGroup = group;
-            }
-
-            this.currentGroup.addMessage(msg);
-        }
-
-        this.promptElement.scrollIntoView(false);
-    },
-
-    clearMessages: function(clearInspectorController)
-    {
-        if (clearInspectorController)
-            InspectorController.clearMessages(false);
-        if (WebInspector.panels.resources)
-            WebInspector.panels.resources.clearMessages();
-
-        this.messages = [];
-
-        this.groupLevel = 0;
-        this.currentGroup = this.topGroup;
-        this.topGroup.messagesElement.removeChildren();
-
-        WebInspector.errors = 0;
-        WebInspector.warnings = 0;
-
-        delete this.commandSincePreviousMessage;
-        delete this.repeatCountBeforeCommand;
-        delete this.previousMessage;
-    },
-
-    completions: function(wordRange, bestMatchOnly, completionsReadyCallback)
-    {
-        // Pass less stop characters to rangeOfWord so the range will be a more complete expression.
-        var expressionRange = wordRange.startContainer.rangeOfWord(wordRange.startOffset, ExpressionStopCharacters, this.promptElement, "backward");
-        var expressionString = expressionRange.toString();
-        var lastIndex = expressionString.length - 1;
-
-        var dotNotation = (expressionString[lastIndex] === ".");
-        var bracketNotation = (expressionString[lastIndex] === "[");
-
-        if (dotNotation || bracketNotation)
-            expressionString = expressionString.substr(0, lastIndex);
-
-        var prefix = wordRange.toString();
-        if (!expressionString && !prefix)
-            return;
-
-        var reportCompletions = this._reportCompletions.bind(this, bestMatchOnly, completionsReadyCallback, dotNotation, bracketNotation, prefix);
-        // Collect comma separated object properties for the completion.
-
-        var includeInspectorCommandLineAPI = (!dotNotation && !bracketNotation);
-        if (WebInspector.panels.scripts && WebInspector.panels.scripts.paused)
-            var callFrameId = WebInspector.panels.scripts.selectedCallFrameId();
-        InjectedScriptAccess.getCompletions(expressionString, includeInspectorCommandLineAPI, callFrameId, reportCompletions);
-    },
-
-    _reportCompletions: function(bestMatchOnly, completionsReadyCallback, dotNotation, bracketNotation, prefix, result, isException) {
-        if (isException)
-            return;
-
-        if (bracketNotation) {
-            if (prefix.length && prefix[0] === "'")
-                var quoteUsed = "'";
-            else
-                var quoteUsed = "\"";
-        }
-
-        var results = [];
-        var properties = Object.sortedProperties(result);
-
-        for (var i = 0; i < properties.length; ++i) {
-            var property = properties[i];
-
-            if (dotNotation && !/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(property))
-                continue;
-
-            if (bracketNotation) {
-                if (!/^[0-9]+$/.test(property))
-                    property = quoteUsed + property.escapeCharacters(quoteUsed + "\\") + quoteUsed;
-                property += "]";
-            }
-
-            if (property.length < prefix.length)
-                continue;
-            if (property.indexOf(prefix) !== 0)
-                continue;
-
-            results.push(property);
-            if (bestMatchOnly)
-                break;
-        }
-        completionsReadyCallback(results);
-    },
-
-    _clearButtonClicked: function()
-    {
-        this.clearMessages(true);
-    },
-
-    _messagesSelectStart: function(event)
-    {
-        if (this._selectionTimeout)
-            clearTimeout(this._selectionTimeout);
-
-        this.prompt.clearAutoComplete();
-
-        function moveBackIfOutside()
-        {
-            delete this._selectionTimeout;
-            if (!this.prompt.isCaretInsidePrompt() && window.getSelection().isCollapsed)
-                this.prompt.moveCaretToEndOfPrompt();
-            this.prompt.autoCompleteSoon();
-        }
-
-        this._selectionTimeout = setTimeout(moveBackIfOutside.bind(this), 100);
-    },
-
-    _messagesClicked: function(event)
-    {
-        var link = event.target.enclosingNodeOrSelfWithNodeName("a");
-        if (!link || !link.representedNode)
-            return;
-
-        WebInspector.updateFocusedNode(link.representedNode.id);
-        event.stopPropagation();
-        event.preventDefault();
-    },
-
-    _promptKeyDown: function(event)
-    {
-        switch (event.keyIdentifier) {
-            case "Enter":
-                this._enterKeyPressed(event);
-                return;
-        }
-
-        this.prompt.handleKeyEvent(event);
-    },
-
-    evalInInspectedWindow: function(expression, objectGroup, callback)
-    {
-        if (WebInspector.panels.scripts && WebInspector.panels.scripts.paused) {
-            WebInspector.panels.scripts.evaluateInSelectedCallFrame(expression, false, objectGroup, callback);
-            return;
-        }
-        this.doEvalInWindow(expression, objectGroup, callback);
-    },
-
-    doEvalInWindow: function(expression, objectGroup, callback)
-    {
-        if (!expression) {
-            // There is no expression, so the completion should happen against global properties.
-            expression = "this";
-        }
-
-        function evalCallback(result)
-        {
-            callback(result.value, result.isException);
-        };
-        InjectedScriptAccess.evaluate(expression, objectGroup, evalCallback);
-    },
-
-    _enterKeyPressed: function(event)
-    {
-        if (event.altKey)
-            return;
-
-        event.preventDefault();
-        event.stopPropagation();
-
-        this.prompt.clearAutoComplete(true);
-
-        var str = this.prompt.text;
-        if (!str.length)
-            return;
-
-        var commandMessage = new WebInspector.ConsoleCommand(str);
-        this.addMessage(commandMessage);
-
-        var self = this;
-        function printResult(result, exception)
-        {
-            self.prompt.history.push(str);
-            self.prompt.historyOffset = 0;
-            self.prompt.text = "";
-            self.addMessage(new WebInspector.ConsoleCommandResult(result, exception, commandMessage));
-        }
-        this.evalInInspectedWindow(str, "console", printResult);
-    },
-
-    _format: function(output, forceObjectFormat)
-    {
-        var isProxy = (output != null && typeof output === "object");
-
-        if (forceObjectFormat)
-            var type = "object";
-        else
-            var type = Object.proxyType(output);
-
-        if (isProxy && type !== "object" && type !== "function" && type !== "array" && type !== "node") {
-            // Unwrap primitive value, skip decoration.
-            output = output.description;
-            type = "undecorated"
-        }
-
-        // We don't perform any special formatting on these types, so we just
-        // pass them through the simple _formatvalue function.
-        var undecoratedTypes = {
-            "undefined": 1,
-            "null": 1,
-            "boolean": 1,
-            "number": 1,
-            "undecorated": 1
-        };
-
-        var formatter;
-        if (forceObjectFormat)
-            formatter = "_formatobject";
-        else if (type in undecoratedTypes)
-            formatter = "_formatvalue";
-        else {
-            formatter = "_format" + type;
-            if (!(formatter in this)) {
-                formatter = "_formatobject";
-                type = "object";
-            }
-        }
-
-        var span = document.createElement("span");
-        span.addStyleClass("console-formatted-" + type);
-        this[formatter](output, span);
-        return span;
-    },
-
-    _formatvalue: function(val, elem)
-    {
-        elem.appendChild(document.createTextNode(val));
-    },
-
-    _formatfunction: function(func, elem)
-    {
-        elem.appendChild(document.createTextNode(func.description));
-    },
-
-    _formatdate: function(date, elem)
-    {
-        elem.appendChild(document.createTextNode(date));
-    },
-
-    _formatstring: function(str, elem)
-    {
-        elem.appendChild(document.createTextNode("\"" + str + "\""));
-    },
-
-    _formatregexp: function(re, elem)
-    {
-        var formatted = String(re.description).replace(/([\\\/])/g, "\\$1").replace(/\\(\/[gim]*)$/, "$1").substring(1);
-        elem.appendChild(document.createTextNode(formatted));
-    },
-
-    _formatarray: function(arr, elem)
-    {
-        InjectedScriptAccess.getProperties(arr, false, this._printArray.bind(this, elem));
-    },
-
-    _printArray: function(elem, properties)
-    {
-        if (!properties)
-            return;
-        var elements = [];
-        for (var i = 0; i < properties.length; ++i) {
-            var name = properties[i].name;
-            if (name == parseInt(name))
-                elements[name] = this._format(properties[i].value);
-        }
-
-        elem.appendChild(document.createTextNode("["));
-        for (var i = 0; i < elements.length; ++i) {
-            var element = elements[i];
-            if (element)
-                elem.appendChild(element);
-            else
-                elem.appendChild(document.createTextNode("undefined"))
-            if (i < elements.length - 1)
-                elem.appendChild(document.createTextNode(", "));
-        }
-        elem.appendChild(document.createTextNode("]"));
-    },
-
-    _formatnode: function(object, elem)
-    {
-        function printNode(nodeId)
-        {
-            if (!nodeId)
-                return;
-            var treeOutline = new WebInspector.ElementsTreeOutline();
-            treeOutline.showInElementsPanelEnabled = true;
-            treeOutline.rootDOMNode = WebInspector.domAgent.nodeForId(nodeId);
-            treeOutline.element.addStyleClass("outline-disclosure");
-            if (!treeOutline.children[0].hasChildren)
-                treeOutline.element.addStyleClass("single-node");
-            elem.appendChild(treeOutline.element);
-        }
-        InjectedScriptAccess.pushNodeToFrontend(object, printNode);
-    },
-
-    _formatobject: function(obj, elem)
-    {
-        elem.appendChild(new WebInspector.ObjectPropertiesSection(obj, obj.description, null, true).element);
-    },
-
-    _formaterror: function(obj, elem)
-    {
-        var messageElement = document.createElement("span");
-        messageElement.className = "error-message";
-        messageElement.textContent = obj.name + ": " + obj.message;
-        elem.appendChild(messageElement);
-
-        if (obj.sourceURL) {
-            var urlElement = document.createElement("a");
-            urlElement.className = "webkit-html-resource-link";
-            urlElement.href = obj.sourceURL;
-            urlElement.lineNumber = obj.line;
-            urlElement.preferredPanel = "scripts";
-
-            if (obj.line > 0)
-                urlElement.textContent = WebInspector.displayNameForURL(obj.sourceURL) + ":" + obj.line;
-            else
-                urlElement.textContent = WebInspector.displayNameForURL(obj.sourceURL);
-
-            elem.appendChild(document.createTextNode(" ("));
-            elem.appendChild(urlElement);
-            elem.appendChild(document.createTextNode(")"));
-        }
-    }
-}
-
-WebInspector.ConsoleView.prototype.__proto__ = WebInspector.View.prototype;
-
-WebInspector.ConsoleMessage = function(source, type, level, line, url, groupLevel, repeatCount)
-{
-    this.source = source;
-    this.type = type;
-    this.level = level;
-    this.line = line;
-    this.url = url;
-    this.groupLevel = groupLevel;
-    this.repeatCount = repeatCount;
-    if (arguments.length > 7)
-        this.setMessageBody(Array.prototype.slice.call(arguments, 7));
-}
-
-WebInspector.ConsoleMessage.prototype = {
-    setMessageBody: function(args)
-    {
-        switch (this.type) {
-            case WebInspector.ConsoleMessage.MessageType.Trace:
-                var span = document.createElement("span");
-                span.addStyleClass("console-formatted-trace");
-                var stack = Array.prototype.slice.call(args);
-                var funcNames = stack.map(function(f) {
-                    return f || WebInspector.UIString("(anonymous function)");
-                });
-                span.appendChild(document.createTextNode(funcNames.join("\n")));
-                this.formattedMessage = span;
-                break;
-            case WebInspector.ConsoleMessage.MessageType.Object:
-                this.formattedMessage = this._format(["%O", args[0]]);
-                break;
-            default:
-                this.formattedMessage = this._format(args);
-                break;
-        }
-
-        // This is used for inline message bubbles in SourceFrames, or other plain-text representations.
-        this.message = this.formattedMessage.textContent;
-    },
-
-    isErrorOrWarning: function()
-    {
-        return (this.level === WebInspector.ConsoleMessage.MessageLevel.Warning || this.level === WebInspector.ConsoleMessage.MessageLevel.Error);
-    },
-
-    _format: function(parameters)
-    {
-        var formattedResult = document.createElement("span");
-
-        if (!parameters.length)
-            return formattedResult;
-
-        // Formatting code below assumes that parameters are all wrappers whereas frontend console
-        // API allows passing arbitrary values as messages (strings, numberts, etc.). Wrap them here.
-        for (var i = 0; i < parameters.length; ++i) {
-            if (typeof parameters[i] !== "object" && typeof parameters[i] !== "function")
-                parameters[i] = WebInspector.ObjectProxy.wrapPrimitiveValue(parameters[i]);
-        }
-
-        function formatForConsole(obj)
-        {
-            return WebInspector.console._format(obj);
-        }
-
-        function formatAsObjectForConsole(obj)
-        {
-            return WebInspector.console._format(obj, true);
-        }
-
-        if (Object.proxyType(parameters[0]) === "string") {
-            var formatters = {}
-            for (var i in String.standardFormatters)
-                formatters[i] = String.standardFormatters[i];
-
-            // Firebug uses %o for formatting objects.
-            formatters.o = formatForConsole;
-            // Firebug allows both %i and %d for formatting integers.
-            formatters.i = formatters.d;
-            // Support %O to force object formating, instead of the type-based %o formatting.
-            formatters.O = formatAsObjectForConsole;
-
-            function append(a, b)
-            {
-                if (!(b instanceof Node))
-                    a.appendChild(WebInspector.linkifyStringAsFragment(b.toString()));
-                else
-                    a.appendChild(b);
-                return a;
-            }
-
-            var result = String.format(parameters[0].description, parameters.slice(1), formatters, formattedResult, append);
-            formattedResult = result.formattedResult;
-            parameters = result.unusedSubstitutions;
-            if (parameters.length)
-                formattedResult.appendChild(document.createTextNode(" "));
-        }
-
-        for (var i = 0; i < parameters.length; ++i) {
-            if (Object.proxyType(parameters[i]) === "string")
-                formattedResult.appendChild(WebInspector.linkifyStringAsFragment(parameters[i].description));
-            else
-                formattedResult.appendChild(formatForConsole(parameters[i]));
-
-            if (i < parameters.length - 1)
-                formattedResult.appendChild(document.createTextNode(" "));
-        }
-
-        return formattedResult;
-    },
-
-    toMessageElement: function()
-    {
-        if (this.propertiesSection)
-            return this.propertiesSection.element;
-
-        var element = document.createElement("div");
-        element.message = this;
-        element.className = "console-message";
-
-        switch (this.source) {
-            case WebInspector.ConsoleMessage.MessageSource.HTML:
-                element.addStyleClass("console-html-source");
-                break;
-            case WebInspector.ConsoleMessage.MessageSource.WML:
-                element.addStyleClass("console-wml-source");
-                break;
-            case WebInspector.ConsoleMessage.MessageSource.XML:
-                element.addStyleClass("console-xml-source");
-                break;
-            case WebInspector.ConsoleMessage.MessageSource.JS:
-                element.addStyleClass("console-js-source");
-                break;
-            case WebInspector.ConsoleMessage.MessageSource.CSS:
-                element.addStyleClass("console-css-source");
-                break;
-            case WebInspector.ConsoleMessage.MessageSource.Other:
-                element.addStyleClass("console-other-source");
-                break;
-        }
-
-        switch (this.level) {
-            case WebInspector.ConsoleMessage.MessageLevel.Tip:
-                element.addStyleClass("console-tip-level");
-                break;
-            case WebInspector.ConsoleMessage.MessageLevel.Log:
-                element.addStyleClass("console-log-level");
-                break;
-            case WebInspector.ConsoleMessage.MessageLevel.Debug:
-                element.addStyleClass("console-debug-level");
-                break;
-            case WebInspector.ConsoleMessage.MessageLevel.Warning:
-                element.addStyleClass("console-warning-level");
-                break;
-            case WebInspector.ConsoleMessage.MessageLevel.Error:
-                element.addStyleClass("console-error-level");
-                break;
-        }
-        
-        if (this.type === WebInspector.ConsoleMessage.MessageType.StartGroup) {
-            element.addStyleClass("console-group-title");
-        }
-
-        if (this.elementsTreeOutline) {
-            element.addStyleClass("outline-disclosure");
-            element.appendChild(this.elementsTreeOutline.element);
-            return element;
-        }
-
-        if (this.repeatCount > 1) {
-            var messageRepeatCountElement = document.createElement("span");
-            messageRepeatCountElement.className = "bubble";
-            messageRepeatCountElement.textContent = this.repeatCount;
-
-            element.appendChild(messageRepeatCountElement);
-            element.addStyleClass("repeated-message");
-        }
-
-        if (this.url && this.url !== "undefined") {
-            var urlElement = document.createElement("a");
-            urlElement.className = "console-message-url webkit-html-resource-link";
-            urlElement.href = this.url;
-            urlElement.lineNumber = this.line;
-
-            if (this.source === WebInspector.ConsoleMessage.MessageSource.JS)
-                urlElement.preferredPanel = "scripts";
-
-            if (this.line > 0)
-                urlElement.textContent = WebInspector.displayNameForURL(this.url) + ":" + this.line;
-            else
-                urlElement.textContent = WebInspector.displayNameForURL(this.url);
-
-            element.appendChild(urlElement);
-        }
-
-        var messageTextElement = document.createElement("span");
-        messageTextElement.className = "console-message-text";
-        messageTextElement.appendChild(this.formattedMessage);
-        element.appendChild(messageTextElement);
-
-        return element;
-    },
-
-    toString: function()
-    {
-        var sourceString;
-        switch (this.source) {
-            case WebInspector.ConsoleMessage.MessageSource.HTML:
-                sourceString = "HTML";
-                break;
-            case WebInspector.ConsoleMessage.MessageSource.WML:
-                sourceString = "WML";
-                break;
-            case WebInspector.ConsoleMessage.MessageSource.XML:
-                sourceString = "XML";
-                break;
-            case WebInspector.ConsoleMessage.MessageSource.JS:
-                sourceString = "JS";
-                break;
-            case WebInspector.ConsoleMessage.MessageSource.CSS:
-                sourceString = "CSS";
-                break;
-            case WebInspector.ConsoleMessage.MessageSource.Other:
-                sourceString = "Other";
-                break;
-        }
-
-        var typeString;
-        switch (this.type) {
-            case WebInspector.ConsoleMessage.MessageType.Log:
-                typeString = "Log";
-                break;
-            case WebInspector.ConsoleMessage.MessageType.Object:
-                typeString = "Object";
-                break;
-            case WebInspector.ConsoleMessage.MessageType.Trace:
-                typeString = "Trace";
-                break;
-            case WebInspector.ConsoleMessage.MessageType.StartGroup:
-                typeString = "Start Group";
-                break;
-            case WebInspector.ConsoleMessage.MessageType.EndGroup:
-                typeString = "End Group";
-                break;
-        }
-        
-        var levelString;
-        switch (this.level) {
-            case WebInspector.ConsoleMessage.MessageLevel.Tip:
-                levelString = "Tip";
-                break;
-            case WebInspector.ConsoleMessage.MessageLevel.Log:
-                levelString = "Log";
-                break;
-            case WebInspector.ConsoleMessage.MessageLevel.Warning:
-                levelString = "Warning";
-                break;
-            case WebInspector.ConsoleMessage.MessageLevel.Debug:
-                levelString = "Debug";
-                break;
-            case WebInspector.ConsoleMessage.MessageLevel.Error:
-                levelString = "Error";
-                break;
-        }
-
-        return sourceString + " " + typeString + " " + levelString + ": " + this.formattedMessage.textContent + "\n" + this.url + " line " + this.line;
-    },
-
-    isEqual: function(msg, disreguardGroup)
-    {
-        if (!msg)
-            return false;
-
-        var ret = (this.source == msg.source)
-            && (this.type == msg.type)
-            && (this.level == msg.level)
-            && (this.line == msg.line)
-            && (this.url == msg.url)
-            && (this.message == msg.message);
-
-        return (disreguardGroup ? ret : (ret && (this.groupLevel == msg.groupLevel)));
-    }
-}
-
-// Note: Keep these constants in sync with the ones in Console.h
-WebInspector.ConsoleMessage.MessageSource = {
-    HTML: 0,
-    WML: 1,
-    XML: 2,
-    JS: 3,
-    CSS: 4,
-    Other: 5
-}
-
-WebInspector.ConsoleMessage.MessageType = {
-    Log: 0,
-    Object: 1,
-    Trace: 2,
-    StartGroup: 3,
-    EndGroup: 4
-}
-
-WebInspector.ConsoleMessage.MessageLevel = {
-    Tip: 0,
-    Log: 1,
-    Warning: 2,
-    Error: 3,
-    Debug: 4
-}
-
-WebInspector.ConsoleCommand = function(command)
-{
-    this.command = command;
-}
-
-WebInspector.ConsoleCommand.prototype = {
-    toMessageElement: function()
-    {
-        var element = document.createElement("div");
-        element.command = this;
-        element.className = "console-user-command";
-
-        var commandTextElement = document.createElement("span");
-        commandTextElement.className = "console-message-text";
-        commandTextElement.textContent = this.command;
-        element.appendChild(commandTextElement);
-
-        return element;
-    }
-}
-
-WebInspector.ConsoleTextMessage = function(text, level)
-{
-    level = level || WebInspector.ConsoleMessage.MessageLevel.Log;
-    WebInspector.ConsoleMessage.call(this, WebInspector.ConsoleMessage.MessageSource.JS, WebInspector.ConsoleMessage.MessageType.Log, level, 0, null, null, 1, text);
-}
-
-WebInspector.ConsoleTextMessage.prototype.__proto__ = WebInspector.ConsoleMessage.prototype;
-
-WebInspector.ConsoleCommandResult = function(result, exception, originatingCommand)
-{
-    var level = (exception ? WebInspector.ConsoleMessage.MessageLevel.Error : WebInspector.ConsoleMessage.MessageLevel.Log);
-    var message = result;
-    var line = (exception ? result.line : -1);
-    var url = (exception ? result.sourceURL : null);
-
-    WebInspector.ConsoleMessage.call(this, WebInspector.ConsoleMessage.MessageSource.JS, WebInspector.ConsoleMessage.MessageType.Log, level, line, url, null, 1, message);
-
-    this.originatingCommand = originatingCommand;
-}
-
-WebInspector.ConsoleCommandResult.prototype = {
-    toMessageElement: function()
-    {
-        var element = WebInspector.ConsoleMessage.prototype.toMessageElement.call(this);
-        element.addStyleClass("console-user-command-result");
-        return element;
-    }
-}
-
-WebInspector.ConsoleCommandResult.prototype.__proto__ = WebInspector.ConsoleMessage.prototype;
-
-WebInspector.ConsoleGroup = function(parentGroup, level)
-{
-    this.parentGroup = parentGroup;
-    this.level = level;
-
-    var element = document.createElement("div");
-    element.className = "console-group";
-    element.group = this;
-    this.element = element;
-
-    var messagesElement = document.createElement("div");
-    messagesElement.className = "console-group-messages";
-    element.appendChild(messagesElement);
-    this.messagesElement = messagesElement;
-}
-
-WebInspector.ConsoleGroup.prototype = {
-    addMessage: function(msg)
-    {
-        var element = msg.toMessageElement();
-        
-        if (msg.type === WebInspector.ConsoleMessage.MessageType.StartGroup) {
-            this.messagesElement.parentNode.insertBefore(element, this.messagesElement);
-            element.addEventListener("click", this._titleClicked.bind(this), true);
-        } else
-            this.messagesElement.appendChild(element);
-
-        if (element.previousSibling && msg.originatingCommand && element.previousSibling.command === msg.originatingCommand)
-            element.previousSibling.addStyleClass("console-adjacent-user-command-result");
-    },
-
-    _titleClicked: function(event)
-    {
-        var groupTitleElement = event.target.enclosingNodeOrSelfWithClass("console-group-title");
-        if (groupTitleElement) {
-            var groupElement = groupTitleElement.enclosingNodeOrSelfWithClass("console-group");
-            if (groupElement)
-                if (groupElement.hasStyleClass("collapsed"))
-                    groupElement.removeStyleClass("collapsed");
-                else
-                    groupElement.addStyleClass("collapsed");
-            groupTitleElement.scrollIntoViewIfNeeded(true);
-        }
-
-        event.stopPropagation();
-        event.preventDefault();
-    }
-}
diff --git a/resources/inspector/CookieItemsView.js b/resources/inspector/CookieItemsView.js
deleted file mode 100755
index 9f9845c..0000000
--- a/resources/inspector/CookieItemsView.js
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Copyright (C) 2009 Apple Inc.  All rights reserved.
- * Copyright (C) 2009 Joseph Pecoraro
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- *     its contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WebInspector.CookieItemsView = function(cookieDomain)
-{
-    WebInspector.View.call(this);
-
-    this.element.addStyleClass("storage-view");
-    this.element.addStyleClass("table");
-
-    this.deleteButton = new WebInspector.StatusBarButton(WebInspector.UIString("Delete"), "delete-storage-status-bar-item");
-    this.deleteButton.visible = false;
-    this.deleteButton.addEventListener("click", this._deleteButtonClicked.bind(this), false);
-
-    this.refreshButton = new WebInspector.StatusBarButton(WebInspector.UIString("Refresh"), "refresh-storage-status-bar-item");
-    this.refreshButton.addEventListener("click", this._refreshButtonClicked.bind(this), false);
-    
-    this._cookieDomain = cookieDomain;
-}
-
-WebInspector.CookieItemsView.prototype = {
-    get statusBarItems()
-    {
-        return [this.refreshButton.element, this.deleteButton.element];
-    },
-
-    show: function(parentElement)
-    {
-        WebInspector.View.prototype.show.call(this, parentElement);
-        this.update();
-    },
-
-    hide: function()
-    {
-        WebInspector.View.prototype.hide.call(this);
-        this.deleteButton.visible = false;
-    },
-
-    update: function()
-    {
-        this.element.removeChildren();
-
-        var self = this;
-        function callback(cookies, isAdvanced) {
-            var dataGrid = (isAdvanced ? self.dataGridForCookies(cookies) : self.simpleDataGridForCookies(cookies));
-            if (dataGrid) {
-                self._dataGrid = dataGrid;
-                self.element.appendChild(dataGrid.element);
-                self._dataGrid.updateWidths();
-                if (isAdvanced)
-                    self.deleteButton.visible = true;
-            } else {
-                var emptyMsgElement = document.createElement("div");
-                emptyMsgElement.className = "storage-table-empty";
-                emptyMsgElement.textContent = WebInspector.UIString("This site has no cookies.");
-                self.element.appendChild(emptyMsgElement);
-                self._dataGrid = null;
-                self.deleteButton.visible = false;
-            }
-        }
-
-        WebInspector.Cookies.getCookiesAsync(callback, this._cookieDomain);
-    },
-
-    dataGridForCookies: function(cookies)
-    {
-        if (!cookies.length)
-            return null;
-
-        for (var i = 0; i < cookies.length; ++i)
-            cookies[i].expires = new Date(cookies[i].expires);
-
-        var columns = { 0: {}, 1: {}, 2: {}, 3: {}, 4: {}, 5: {}, 6: {}, 7: {} };
-        columns[0].title = WebInspector.UIString("Name");
-        columns[0].width = columns[0].title.length;
-        columns[1].title = WebInspector.UIString("Value");
-        columns[1].width = columns[1].title.length;
-        columns[2].title = WebInspector.UIString("Domain");
-        columns[2].width = columns[2].title.length;
-        columns[3].title = WebInspector.UIString("Path");
-        columns[3].width = columns[3].title.length;
-        columns[4].title = WebInspector.UIString("Expires");
-        columns[4].width = columns[4].title.length;
-        columns[5].title = WebInspector.UIString("Size");
-        columns[5].width = columns[5].title.length;
-        columns[5].aligned = "right";
-        columns[6].title = WebInspector.UIString("HTTP");
-        columns[6].width = columns[6].title.length;
-        columns[6].aligned = "centered";
-        columns[7].title = WebInspector.UIString("Secure");
-        columns[7].width = columns[7].title.length;
-        columns[7].aligned = "centered";
-
-        function updateDataAndColumn(index, value) {
-            data[index] = value;
-            if (value.length > columns[index].width)
-                columns[index].width = value.length;
-        }
-
-        var data;
-        var nodes = [];
-        for (var i = 0; i < cookies.length; ++i) {
-            var cookie = cookies[i];
-            data = {};
-
-            updateDataAndColumn(0, cookie.name);
-            updateDataAndColumn(1, cookie.value);
-            updateDataAndColumn(2, cookie.domain);
-            updateDataAndColumn(3, cookie.path);
-            updateDataAndColumn(4, (cookie.session ? WebInspector.UIString("Session") : cookie.expires.toGMTString()));
-            updateDataAndColumn(5, Number.bytesToString(cookie.size, WebInspector.UIString));
-            updateDataAndColumn(6, (cookie.httpOnly ? "\u2713" : "")); // Checkmark
-            updateDataAndColumn(7, (cookie.secure ? "\u2713" : "")); // Checkmark
-
-            var node = new WebInspector.DataGridNode(data, false);
-            node.cookie = cookie;
-            node.selectable = true;
-            nodes.push(node);
-        }
-
-        var totalColumnWidths = 0;
-        for (var columnIdentifier in columns)
-            totalColumnWidths += columns[columnIdentifier].width;
-
-        // Enforce the Value column (the 2nd column) to be a max of 33%
-        // tweaking the raw total width because may massively outshadow the others
-        var valueColumnWidth = columns[1].width;
-        if (valueColumnWidth / totalColumnWidths > 0.33) {
-            totalColumnWidths -= valueColumnWidth;
-            totalColumnWidths *= 1.33;
-            columns[1].width = totalColumnWidths * 0.33;
-        }
-
-        // Calculate the percentage width for the columns.
-        const minimumPrecent = 6;
-        var recoupPercent = 0;
-        for (var columnIdentifier in columns) {
-            var width = columns[columnIdentifier].width;
-            width = Math.round((width / totalColumnWidths) * 100);
-            if (width < minimumPrecent) {
-                recoupPercent += (minimumPrecent - width);
-                width = minimumPrecent;
-            }
-            columns[columnIdentifier].width = width;
-        }
-
-        // Enforce the minimum percentage width. (need to narrow total percentage due to earlier additions)
-        while (recoupPercent > 0) {
-            for (var columnIdentifier in columns) {
-                if (columns[columnIdentifier].width > minimumPrecent) {
-                    --columns[columnIdentifier].width;
-                    --recoupPercent;
-                    if (!recoupPercent)
-                        break;
-                }
-            }
-        }
-
-        for (var columnIdentifier in columns)
-            columns[columnIdentifier].width += "%";
-
-        var dataGrid = new WebInspector.DataGrid(columns);
-        var length = nodes.length;
-        for (var i = 0; i < length; ++i)
-            dataGrid.appendChild(nodes[i]);
-        if (length > 0)
-            nodes[0].selected = true;
-
-        return dataGrid;
-    },
-
-    simpleDataGridForCookies: function(cookies)
-    {
-        if (!cookies.length)
-            return null;
-
-        var columns = {};
-        columns[0] = {};
-        columns[1] = {};
-        columns[0].title = WebInspector.UIString("Name");
-        columns[0].width = columns[0].title.length;
-        columns[1].title = WebInspector.UIString("Value");
-        columns[1].width = columns[1].title.length;
-
-        var nodes = [];
-        for (var i = 0; i < cookies.length; ++i) {
-            var cookie = cookies[i];
-            var data = {};
-
-            var name = cookie.name;
-            data[0] = name;
-            if (name.length > columns[0].width)
-                columns[0].width = name.length;
-
-            var value = cookie.value;
-            data[1] = value;
-            if (value.length > columns[1].width)
-                columns[1].width = value.length;
-
-            var node = new WebInspector.DataGridNode(data, false);
-            node.selectable = true;
-            nodes.push(node);
-        }
-
-        var totalColumnWidths = columns[0].width + columns[1].width;
-        var width = Math.round((columns[0].width * 100) / totalColumnWidths);
-        const minimumPrecent = 20;
-        if (width < minimumPrecent)
-            width = minimumPrecent;
-        if (width > 100 - minimumPrecent)
-            width = 100 - minimumPrecent;
-        columns[0].width = width;
-        columns[1].width = 100 - width;
-        columns[0].width += "%";
-        columns[1].width += "%";
-
-        var dataGrid = new WebInspector.DataGrid(columns);
-        var length = nodes.length;
-        for (var i = 0; i < length; ++i)
-            dataGrid.appendChild(nodes[i]);
-        if (length > 0)
-            nodes[0].selected = true;
-
-        return dataGrid;
-    },
-    
-    resize: function()
-    {
-        if (this._dataGrid)
-            this._dataGrid.updateWidths();
-    },
-
-    _deleteButtonClicked: function(event)
-    {
-        if (!this._dataGrid)
-            return;
-
-        var cookie = this._dataGrid.selectedNode.cookie;
-        InspectorController.deleteCookie(cookie.name, this._cookieDomain);
-        this.update();
-    },
-
-    _refreshButtonClicked: function(event)
-    {
-        this.update();
-    }
-}
-
-WebInspector.CookieItemsView.prototype.__proto__ = WebInspector.View.prototype;
diff --git a/resources/inspector/DOMAgent.js b/resources/inspector/DOMAgent.js
deleted file mode 100755
index 25ffafa..0000000
--- a/resources/inspector/DOMAgent.js
+++ /dev/null
@@ -1,657 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
- * Copyright (C) 2009 Joseph Pecoraro
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WebInspector.DOMNode = function(doc, payload) {
-    this.ownerDocument = doc;
-
-    this.id = payload.id;
-    this.nodeType = payload.nodeType;
-    this.nodeName = payload.nodeName;
-    this.localName = payload.localName;
-    this._nodeValue = payload.nodeValue;
-    this.textContent = this.nodeValue;
-
-    this.attributes = [];
-    this._attributesMap = {};
-    if (payload.attributes)
-        this._setAttributesPayload(payload.attributes);
-
-    this._childNodeCount = payload.childNodeCount;
-    this.children = null;
-
-    this.nextSibling = null;
-    this.prevSibling = null;
-    this.firstChild = null;
-    this.lastChild = null;
-    this.parentNode = null;
-
-    if (payload.children)
-        this._setChildrenPayload(payload.children);
-
-    this._computedStyle = null;
-    this.style = null;
-    this._matchedCSSRules = [];
-
-    if (this.nodeType == Node.ELEMENT_NODE) {
-        if (this.nodeName == "HTML")
-            this.ownerDocument.documentElement = this;
-        if (this.nodeName == "BODY")
-            this.ownerDocument.body = this;
-    }
-}
-
-WebInspector.DOMNode.prototype = {
-    hasAttributes: function()
-    {
-        return this.attributes.length > 0;
-    },
-
-    hasChildNodes: function()  {
-        return this._childNodeCount > 0;
-    },
-
-    get nodeValue() {
-        return this._nodeValue;
-    },
-
-    set nodeValue(value) {
-        if (this.nodeType != Node.TEXT_NODE)
-            return;
-        var self = this;
-        var callback = function()
-        {
-            self._nodeValue = value;
-            self.textContent = value;
-        };
-        this.ownerDocument._domAgent.setTextNodeValueAsync(this, value, callback);
-    },
-
-    getAttribute: function(name)
-    {
-        var attr = this._attributesMap[name];
-        return attr ? attr.value : undefined;
-    },
-
-    setAttribute: function(name, value)
-    {
-        var self = this;
-        var callback = function()
-        {
-            var attr = self._attributesMap[name];
-            if (attr)
-                attr.value = value;
-            else
-                attr = self._addAttribute(name, value);
-        };
-        this.ownerDocument._domAgent.setAttributeAsync(this, name, value, callback);
-    },
-
-    removeAttribute: function(name)
-    {
-        var self = this;
-        var callback = function()
-        {
-            delete self._attributesMap[name];
-            for (var i = 0;  i < self.attributes.length; ++i) {
-                if (self.attributes[i].name == name) {
-                    self.attributes.splice(i, 1);
-                    break;
-                }
-            }
-        };
-        this.ownerDocument._domAgent.removeAttributeAsync(this, name, callback);
-    },
-
-    _setAttributesPayload: function(attrs)
-    {
-        for (var i = 0; i < attrs.length; i += 2)
-            this._addAttribute(attrs[i], attrs[i + 1]);
-    },
-
-    _insertChild: function(prev, payload)
-    {
-        var node = new WebInspector.DOMNode(this.ownerDocument, payload);
-        if (!prev)
-            // First node
-            this.children = [ node ];
-        else
-            this.children.splice(this.children.indexOf(prev) + 1, 0, node);
-        this._renumber();
-        return node;
-    },
-
-    removeChild_: function(node)
-    {
-        this.children.splice(this.children.indexOf(node), 1);
-        node.parentNode = null;
-        this._renumber();
-    },
-
-    _setChildrenPayload: function(payloads)
-    {
-        this.children = [];
-        for (var i = 0; i < payloads.length; ++i) {
-            var payload = payloads[i];
-            var node = new WebInspector.DOMNode(this.ownerDocument, payload);
-            this.children.push(node);
-        }
-        this._renumber();
-    },
-
-    _renumber: function()
-    {
-        this._childNodeCount = this.children.length;
-        if (this._childNodeCount == 0) {
-            this.firstChild = null;
-            this.lastChild = null;
-            return;
-        }
-        this.firstChild = this.children[0];
-        this.lastChild = this.children[this._childNodeCount - 1];
-        for (var i = 0; i < this._childNodeCount; ++i) {
-            var child = this.children[i];
-            child.nextSibling = i + 1 < this._childNodeCount ? this.children[i + 1] : null;
-            child.prevSibling = i - 1 >= 0 ? this.children[i - 1] : null;
-            child.parentNode = this;
-        }
-    },
-
-    _addAttribute: function(name, value)
-    {
-        var attr = {
-            "name": name,
-            "value": value,
-            "_node": this
-        };
-        this._attributesMap[name] = attr;
-        this.attributes.push(attr);
-    },
-
-    _setStyles: function(computedStyle, inlineStyle, styleAttributes, matchedCSSRules)
-    {
-        this._computedStyle = new WebInspector.CSSStyleDeclaration(computedStyle);
-        this.style = new WebInspector.CSSStyleDeclaration(inlineStyle);
-
-        for (var name in styleAttributes) {
-            if (this._attributesMap[name])
-                this._attributesMap[name].style = new WebInspector.CSSStyleDeclaration(styleAttributes[name]);
-        }
-
-        this._matchedCSSRules = [];
-        for (var i = 0; i < matchedCSSRules.length; i++)
-            this._matchedCSSRules.push(WebInspector.CSSStyleDeclaration.parseRule(matchedCSSRules[i]));
-    },
-
-    _clearStyles: function()
-    {
-        this.computedStyle = null;
-        this.style = null;
-        for (var name in this._attributesMap)
-            this._attributesMap[name].style = null;
-        this._matchedCSSRules = null;
-    }
-}
-
-WebInspector.DOMDocument = function(domAgent, defaultView, payload)
-{
-    WebInspector.DOMNode.call(this, this, payload);
-    this._listeners = {};
-    this._domAgent = domAgent;
-    this.defaultView = defaultView;
-}
-
-WebInspector.DOMDocument.prototype = {
-
-    addEventListener: function(name, callback)
-    {
-        var listeners = this._listeners[name];
-        if (!listeners) {
-            listeners = [];
-            this._listeners[name] = listeners;
-        }
-        listeners.push(callback);
-    },
-
-    removeEventListener: function(name, callback)
-    {
-        var listeners = this._listeners[name];
-        if (!listeners)
-            return;
-
-        var index = listeners.indexOf(callback);
-        if (index != -1)
-            listeners.splice(index, 1);
-    },
-
-    _fireDomEvent: function(name, event)
-    {
-        var listeners = this._listeners[name];
-        if (!listeners)
-            return;
-
-        for (var i = 0; i < listeners.length; ++i) {
-            var listener = listeners[i];
-            listener.call(this, event);
-        }
-    }
-}
-
-WebInspector.DOMDocument.prototype.__proto__ = WebInspector.DOMNode.prototype;
-
-
-WebInspector.DOMWindow = function(domAgent)
-{
-    this._domAgent = domAgent;
-}
-
-WebInspector.DOMWindow.prototype = {
-    get document()
-    {
-        return this._domAgent.document;
-    },
-
-    get Node()
-    {
-        return WebInspector.DOMNode;
-    },
-
-    get Element()
-    {
-        return WebInspector.DOMNode;
-    },
-
-    Object: function()
-    {
-    },
-
-    getComputedStyle: function(node)
-    {
-        return node._computedStyle;
-    },
-
-    getMatchedCSSRules: function(node, pseudoElement, authorOnly)
-    {
-        return node._matchedCSSRules;
-    }
-}
-
-WebInspector.DOMAgent = function() {
-    this._window = new WebInspector.DOMWindow(this);
-    this._idToDOMNode = null;
-    this.document = null;
-}
-
-WebInspector.DOMAgent.prototype = {
-    get domWindow()
-    {
-        return this._window;
-    },
-
-    getChildNodesAsync: function(parent, callback)
-    {
-        var children = parent.children;
-        if (children) {
-            callback(children);
-            return;
-        }
-        function mycallback() {
-            callback(parent.children);
-        }
-        var callId = WebInspector.Callback.wrap(mycallback);
-        InspectorController.getChildNodes(callId, parent.id);
-    },
-
-    setAttributeAsync: function(node, name, value, callback)
-    {
-        var mycallback = this._didApplyDomChange.bind(this, node, callback);
-        InspectorController.setAttribute(WebInspector.Callback.wrap(mycallback), node.id, name, value);
-    },
-
-    removeAttributeAsync: function(node, name, callback)
-    {
-        var mycallback = this._didApplyDomChange.bind(this, node, callback);
-        InspectorController.removeAttribute(WebInspector.Callback.wrap(mycallback), node.id, name);
-    },
-
-    setTextNodeValueAsync: function(node, text, callback)
-    {
-        var mycallback = this._didApplyDomChange.bind(this, node, callback);
-        InspectorController.setTextNodeValue(WebInspector.Callback.wrap(mycallback), node.id, text);
-    },
-
-    _didApplyDomChange: function(node, callback, success)
-    {
-        if (!success)
-            return;
-        callback();
-        // TODO(pfeldman): Fix this hack.
-        var elem = WebInspector.panels.elements.treeOutline.findTreeElement(node);
-        if (elem) {
-            elem._updateTitle();
-        }
-    },
-
-    _attributesUpdated: function(nodeId, attrsArray)
-    {
-        var node = this._idToDOMNode[nodeId];
-        node._setAttributesPayload(attrsArray);
-    },
-
-    nodeForId: function(nodeId) {
-        return this._idToDOMNode[nodeId];
-    },
-
-    _setDocument: function(payload)
-    {
-        this._idToDOMNode = {};
-        if (payload) {
-            this.document = new WebInspector.DOMDocument(this, this._window, payload);
-            this._idToDOMNode[payload.id] = this.document;
-            this._bindNodes(this.document.children);
-        } else
-            this.document = null;
-        WebInspector.panels.elements.reset();
-    },
-
-    _setDetachedRoot: function(payload)
-    {
-        var root = new WebInspector.DOMNode(this.document, payload);
-        this._idToDOMNode[payload.id] = root;
-    },
-
-    _setChildNodes: function(parentId, payloads)
-    {
-        var parent = this._idToDOMNode[parentId];
-        parent._setChildrenPayload(payloads);
-        this._bindNodes(parent.children);
-    },
-
-    _bindNodes: function(children)
-    {
-        for (var i = 0; i < children.length; ++i) {
-            var child = children[i];
-            this._idToDOMNode[child.id] = child;
-            if (child.children)
-                this._bindNodes(child.children);
-        }
-    },
-
-    _childNodeCountUpdated: function(nodeId, newValue)
-    {
-        var node = this._idToDOMNode[nodeId];
-        node._childNodeCount = newValue;
-        var outline = WebInspector.panels.elements.treeOutline;
-        var treeElement = outline.findTreeElement(node);
-        if (treeElement)
-            treeElement.hasChildren = newValue;
-    },
-
-    _childNodeInserted: function(parentId, prevId, payload)
-    {
-        var parent = this._idToDOMNode[parentId];
-        var prev = this._idToDOMNode[prevId];
-        var node = parent._insertChild(prev, payload);
-        this._idToDOMNode[node.id] = node;
-        var event = { target : node, relatedNode : parent };
-        this.document._fireDomEvent("DOMNodeInserted", event);
-    },
-
-    _childNodeRemoved: function(parentId, nodeId)
-    {
-        var parent = this._idToDOMNode[parentId];
-        var node = this._idToDOMNode[nodeId];
-        parent.removeChild_(node);
-        var event = { target : node, relatedNode : parent };
-        this.document._fireDomEvent("DOMNodeRemoved", event);
-        delete this._idToDOMNode[nodeId];
-    }
-}
-
-WebInspector.Cookies = {}
-
-WebInspector.Cookies.getCookiesAsync = function(callback, cookieDomain)
-{
-    function mycallback(cookies, cookiesString) {
-        if (cookiesString)
-            callback(WebInspector.Cookies.buildCookiesFromString(cookiesString), false);
-        else
-            callback(cookies, true);
-    }
-    var callId = WebInspector.Callback.wrap(mycallback);
-    InspectorController.getCookies(callId, cookieDomain);
-}
-
-WebInspector.Cookies.buildCookiesFromString = function(rawCookieString)
-{
-    var rawCookies = rawCookieString.split(/;\s*/);
-    var cookies = [];
-
-    if (!(/^\s*$/.test(rawCookieString))) {
-        for (var i = 0; i < rawCookies.length; ++i) {
-            var cookie = rawCookies[i];
-            var delimIndex = cookie.indexOf("=");
-            var name = cookie.substring(0, delimIndex);
-            var value = cookie.substring(delimIndex + 1);
-            var size = name.length + value.length;
-            cookies.push({ name: name, value: value, size: size });
-        }
-    }
-
-    return cookies;
-}
-
-WebInspector.EventListeners = {}
-
-WebInspector.EventListeners.getEventListenersForNodeAsync = function(node, callback)
-{
-    if (!node)
-        return;
-
-    var callId = WebInspector.Callback.wrap(callback);
-    InspectorController.getEventListenersForNode(callId, node.id);
-}
-
-WebInspector.CSSStyleDeclaration = function(payload)
-{
-    this.id = payload.id;
-    this.width = payload.width;
-    this.height = payload.height;
-    this.__disabledProperties = payload.__disabledProperties;
-    this.__disabledPropertyValues = payload.__disabledPropertyValues;
-    this.__disabledPropertyPriorities = payload.__disabledPropertyPriorities;
-    this.uniqueStyleProperties = payload.uniqueStyleProperties;
-    this._shorthandValues = payload.shorthandValues;
-    this._propertyMap = {};
-    this._longhandProperties = {};
-    this.length = payload.properties.length;
-
-    for (var i = 0; i < this.length; ++i) {
-        var property = payload.properties[i];
-        var name = property.name;
-        this[i] = name;
-        this._propertyMap[name] = property;
-    }
-
-    // Index longhand properties.
-    for (var i = 0; i < this.uniqueStyleProperties.length; ++i) {
-        var name = this.uniqueStyleProperties[i];
-        var property = this._propertyMap[name];
-        if (property.shorthand) {
-            var longhands = this._longhandProperties[property.shorthand];
-            if (!longhands) {
-                longhands = [];
-                this._longhandProperties[property.shorthand] = longhands;
-            }
-            longhands.push(name);
-        }
-    }
-}
-
-WebInspector.CSSStyleDeclaration.parseStyle = function(payload)
-{
-    return new WebInspector.CSSStyleDeclaration(payload);
-}
-
-WebInspector.CSSStyleDeclaration.parseRule = function(payload)
-{
-    var rule = {};
-    rule.id = payload.id;
-    rule.selectorText = payload.selectorText;
-    rule.style = new WebInspector.CSSStyleDeclaration(payload.style);
-    rule.style.parentRule = rule;
-    rule.isUserAgent = payload.isUserAgent;
-    rule.isUser = payload.isUser;
-    rule.isViaInspector = payload.isViaInspector;
-    if (payload.parentStyleSheet)
-        rule.parentStyleSheet = { href: payload.parentStyleSheet.href };
-
-    return rule;
-}
-
-WebInspector.CSSStyleDeclaration.prototype = {
-    getPropertyValue: function(name)
-    {
-        var property = this._propertyMap[name];
-        return property ? property.value : "";
-    },
-
-    getPropertyPriority: function(name)
-    {
-        var property = this._propertyMap[name];
-        return property ? property.priority : "";
-    },
-
-    getPropertyShorthand: function(name)
-    {
-        var property = this._propertyMap[name];
-        return property ? property.shorthand : "";
-    },
-
-    isPropertyImplicit: function(name)
-    {
-        var property = this._propertyMap[name];
-        return property ? property.implicit : "";
-    },
-
-    styleTextWithShorthands: function()
-    {
-        var cssText = "";
-        var foundProperties = {};
-        for (var i = 0; i < this.length; ++i) {
-            var individualProperty = this[i];
-            var shorthandProperty = this.getPropertyShorthand(individualProperty);
-            var propertyName = (shorthandProperty || individualProperty);
-
-            if (propertyName in foundProperties)
-                continue;
-
-            if (shorthandProperty) {
-                var value = this.getPropertyValue(shorthandProperty);
-                var priority = this.getShorthandPriority(shorthandProperty);
-            } else {
-                var value = this.getPropertyValue(individualProperty);
-                var priority = this.getPropertyPriority(individualProperty);
-            }
-
-            foundProperties[propertyName] = true;
-
-            cssText += propertyName + ": " + value;
-            if (priority)
-                cssText += " !" + priority;
-            cssText += "; ";
-        }
-
-        return cssText;
-    },
-
-    getLonghandProperties: function(name)
-    {
-        return this._longhandProperties[name] || [];
-    },
-
-    getShorthandValue: function(shorthandProperty)
-    {
-        return this._shorthandValues[shorthandProperty];
-    },
-
-    getShorthandPriority: function(shorthandProperty)
-    {
-        var priority = this.getPropertyPriority(shorthandProperty);
-        if (priority)
-            return priority;
-
-        var longhands = this._longhandProperties[shorthandProperty];
-        return longhands ? this.getPropertyPriority(longhands[0]) : null;
-    }
-}
-
-WebInspector.attributesUpdated = function()
-{
-    this.domAgent._attributesUpdated.apply(this.domAgent, arguments);
-}
-
-WebInspector.setDocument = function()
-{
-    this.domAgent._setDocument.apply(this.domAgent, arguments);
-}
-
-WebInspector.setDetachedRoot = function()
-{
-    this.domAgent._setDetachedRoot.apply(this.domAgent, arguments);
-}
-
-WebInspector.setChildNodes = function()
-{
-    this.domAgent._setChildNodes.apply(this.domAgent, arguments);
-}
-
-WebInspector.childNodeCountUpdated = function()
-{
-    this.domAgent._childNodeCountUpdated.apply(this.domAgent, arguments);
-}
-
-WebInspector.childNodeInserted = function()
-{
-    this.domAgent._childNodeInserted.apply(this.domAgent, arguments);
-}
-
-WebInspector.childNodeRemoved = function()
-{
-    this.domAgent._childNodeRemoved.apply(this.domAgent, arguments);
-}
-
-WebInspector.didGetCookies = WebInspector.Callback.processCallback;
-WebInspector.didGetChildNodes = WebInspector.Callback.processCallback;
-WebInspector.didPerformSearch = WebInspector.Callback.processCallback;
-WebInspector.didApplyDomChange = WebInspector.Callback.processCallback;
-WebInspector.didRemoveAttribute = WebInspector.Callback.processCallback;
-WebInspector.didSetTextNodeValue = WebInspector.Callback.processCallback;
-WebInspector.didGetEventListenersForNode = WebInspector.Callback.processCallback;
diff --git a/resources/inspector/DOMStorage.js b/resources/inspector/DOMStorage.js
deleted file mode 100755
index 03a10bf..0000000
--- a/resources/inspector/DOMStorage.js
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2008 Nokia Inc.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- *     its contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WebInspector.DOMStorage = function(id, domain, isLocalStorage)
-{
-    this._id = id;
-    this._domain = domain;
-    this._isLocalStorage = isLocalStorage;
-}
-
-WebInspector.DOMStorage.prototype = {
-    get id()
-    {
-        return this._id;
-    },
-
-    get domStorage()
-    {
-        return this._domStorage;
-    },
-
-    get domain()
-    {
-        return this._domain;
-    },
-
-    get isLocalStorage()
-    {
-        return this._isLocalStorage;
-    },
-
-    getEntries: function(callback)
-    {
-        var callId = WebInspector.Callback.wrap(callback);
-        InspectorController.getDOMStorageEntries(callId, this._id);
-    },
-    
-    setItem: function(key, value, callback)
-    {
-        var callId = WebInspector.Callback.wrap(callback);
-        InspectorController.setDOMStorageItem(callId, this._id, key, value);
-    },
-    
-    removeItem: function(key, callback)
-    {
-        var callId = WebInspector.Callback.wrap(callback);
-        InspectorController.removeDOMStorageItem(callId, this._id, key);
-    }
-}
-
-WebInspector.didGetDOMStorageEntries = WebInspector.Callback.processCallback;
-WebInspector.didSetDOMStorageItem = WebInspector.Callback.processCallback;
-WebInspector.didRemoveDOMStorageItem = WebInspector.Callback.processCallback;
diff --git a/resources/inspector/DOMStorageDataGrid.js b/resources/inspector/DOMStorageDataGrid.js
deleted file mode 100755
index 45a9ba1..0000000
--- a/resources/inspector/DOMStorageDataGrid.js
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2009 Nokia Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *        notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *        notice, this list of conditions and the following disclaimer in the
- *        documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.         IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WebInspector.DOMStorageDataGrid = function(columns, domStorage, keys)
-{
-    WebInspector.DataGrid.call(this, columns);
-    this.dataTableBody.addEventListener("dblclick", this._ondblclick.bind(this), false);
-    this._domStorage = domStorage;
-    this._keys = keys;
-}
-
-WebInspector.DOMStorageDataGrid.prototype = {
-    _ondblclick: function(event)
-    {
-        if (this._editing)
-            return;
-        if (this._editingNode)
-            return;
-        this._startEditing(event);
-    },
-
-    _startEditingColumnOfDataGridNode: function(node, column)
-    {
-        this._editing = true;
-        this._editingNode = node;
-        this._editingNode.select();
-
-        var element = this._editingNode._element.children[column];
-        WebInspector.startEditing(element, this._editingCommitted.bind(this), this._editingCancelled.bind(this), element.textContent);
-        window.getSelection().setBaseAndExtent(element, 0, element, 1);
-    },
-
-    _startEditing: function(event)
-    {
-        var element = event.target.enclosingNodeOrSelfWithNodeName("td");
-        if (!element)
-            return;
-
-        this._editingNode = this.dataGridNodeFromEvent(event);
-        if (!this._editingNode) {
-            if (!this.creationNode)
-                return;
-            this._editingNode = this.creationNode;
-        }
-
-        // Force editing the "Key" column when editing the creation node
-        if (this._editingNode.isCreationNode)
-            return this._startEditingColumnOfDataGridNode(this._editingNode, 0);
-
-        this._editing = true;
-        WebInspector.startEditing(element, this._editingCommitted.bind(this), this._editingCancelled.bind(this), element.textContent);
-        window.getSelection().setBaseAndExtent(element, 0, element, 1);
-    },
-
-    _editingCommitted: function(element, newText, oldText, context, moveDirection)
-    {
-        var columnIdentifier = (element.hasStyleClass("0-column") ? 0 : 1);
-        var textBeforeEditing = this._editingNode.data[columnIdentifier];
-        var currentEditingNode = this._editingNode;
-
-        function moveToNextIfNeeded(wasChange) {
-            if (!moveDirection)
-                return;
-
-            if (moveDirection === "forward") {
-                if (currentEditingNode.isCreationNode && columnIdentifier === 0 && !wasChange)
-                    return;
-
-                if (columnIdentifier === 0)
-                    return this._startEditingColumnOfDataGridNode(currentEditingNode, 1);
-
-                var nextDataGridNode = currentEditingNode.traverseNextNode(true, null, true);
-                if (nextDataGridNode)
-                    return this._startEditingColumnOfDataGridNode(nextDataGridNode, 0);
-                if (currentEditingNode.isCreationNode && wasChange) {
-                    addCreationNode(false);
-                    return this._startEditingColumnOfDataGridNode(this.creationNode, 0);
-                }
-                return;
-            }
-
-            if (moveDirection === "backward") {
-                if (columnIdentifier === 1)
-                    return this._startEditingColumnOfDataGridNode(currentEditingNode, 0);
-                    var nextDataGridNode = currentEditingNode.traversePreviousNode(true, null, true);
-
-                if (nextDataGridNode)
-                    return this._startEditingColumnOfDataGridNode(nextDataGridNode, 1);
-                return;
-            }
-        }
-
-        if (textBeforeEditing == newText) {
-            this._editingCancelled(element);
-            moveToNextIfNeeded.call(this, false);
-            return;
-        }
-
-        var domStorage = this._domStorage;
-        if (columnIdentifier === 0) {
-            if (this._keys.indexOf(newText) !== -1) {
-                element.textContent = this._editingNode.data[0];
-                this._editingCancelled(element);
-                moveToNextIfNeeded.call(this, false);
-                return;
-            }
-            domStorage.removeItem(this._editingNode.data[0]);
-            domStorage.setItem(newText, this._editingNode.data[1]);
-            this._editingNode.data[0] = newText;
-        } else {
-            domStorage.setItem(this._editingNode.data[0], newText);
-            this._editingNode.data[1] = newText;
-        }
-
-        if (this._editingNode.isCreationNode)
-            this.addCreationNode(false);
-
-        this._editingCancelled(element);
-        moveToNextIfNeeded.call(this, true);
-    },
-
-    _editingCancelled: function(element, context)
-    {
-        delete this._editing;
-        this._editingNode = null;
-    },
-
-    deleteSelectedRow: function()
-    {
-        var node = this.selectedNode;
-        if (!node || node.isCreationNode)
-            return;
-
-        if (this._domStorage)
-            this._domStorage.removeItem(node.data[0]);
-    }
-}
-
-WebInspector.DOMStorageDataGrid.prototype.__proto__ = WebInspector.DataGrid.prototype;
diff --git a/resources/inspector/DOMStorageItemsView.js b/resources/inspector/DOMStorageItemsView.js
deleted file mode 100755
index a7da370..0000000
--- a/resources/inspector/DOMStorageItemsView.js
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2008 Nokia Inc.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WebInspector.DOMStorageItemsView = function(domStorage)
-{
-    WebInspector.View.call(this);
-
-    this.domStorage = domStorage;
-
-    this.element.addStyleClass("storage-view");
-    this.element.addStyleClass("table");
-
-    this.deleteButton = new WebInspector.StatusBarButton(WebInspector.UIString("Delete"), "delete-storage-status-bar-item");
-    this.deleteButton.visible = false;
-    this.deleteButton.addEventListener("click", this._deleteButtonClicked.bind(this), false);
-
-    this.refreshButton = new WebInspector.StatusBarButton(WebInspector.UIString("Refresh"), "refresh-storage-status-bar-item");
-    this.refreshButton.addEventListener("click", this._refreshButtonClicked.bind(this), false);
-}
-
-WebInspector.DOMStorageItemsView.prototype = {
-    get statusBarItems()
-    {
-        return [this.refreshButton.element, this.deleteButton.element];
-    },
-
-    show: function(parentElement)
-    {
-        WebInspector.View.prototype.show.call(this, parentElement);
-        this.update();
-    },
-
-    hide: function()
-    {
-        WebInspector.View.prototype.hide.call(this);
-        this.deleteButton.visible = false;
-    },
-
-    update: function()
-    {
-        this.element.removeChildren();
-        var callback = this._showDOMStorageEntries.bind(this);
-        this.domStorage.getEntries(callback);
-    },
-
-    _showDOMStorageEntries: function(entries) 
-    {
-        if (entries.length > 0) {
-            this._dataGrid = this._dataGridForDOMStorageEntries(entries);
-            this.element.appendChild(this._dataGrid.element);
-            this._dataGrid.updateWidths();
-            this.deleteButton.visible = true;
-        } else {
-            var emptyMsgElement = document.createElement("div");
-            emptyMsgElement.className = "storage-table-empty";
-            if (this.domStorage)
-                emptyMsgElement.textContent = WebInspector.UIString("This storage is empty.");
-            this.element.appendChild(emptyMsgElement);
-            this._dataGrid = null;
-            this.deleteButton.visible = false;
-        }
-    },
-
-    resize: function()
-    {
-        if (this._dataGrid)
-            this._dataGrid.updateWidths();
-    },
-
-    _dataGridForDOMStorageEntries: function(entries)
-    {
-        var columns = {};
-        columns[0] = {};
-        columns[1] = {};
-        columns[0].title = WebInspector.UIString("Key");
-        columns[0].width = columns[0].title.length;
-        columns[1].title = WebInspector.UIString("Value");
-        columns[1].width = columns[1].title.length;
-
-        var nodes = [];
-
-        var keys = [];
-        var length = entries.length;
-        for (var i = 0; i < entries.length; i++) {
-            var data = {};
-
-            var key = entries[i][0];
-            data[0] = key;
-            if (key.length > columns[0].width)
-                columns[0].width = key.length;
-
-            var value = entries[i][1];
-            data[1] = value;
-            if (value.length > columns[1].width)
-                columns[1].width = value.length;
-            var node = new WebInspector.DataGridNode(data, false);
-            node.selectable = true;
-            nodes.push(node);
-            keys.push(key);
-        }
-
-        var totalColumnWidths = columns[0].width + columns[1].width;
-        var width = Math.round((columns[0].width * 100) / totalColumnWidths);
-        const minimumPrecent = 10;
-        if (width < minimumPrecent)
-            width = minimumPrecent;
-        if (width > 100 - minimumPrecent)
-            width = 100 - minimumPrecent;
-        columns[0].width = width;
-        columns[1].width = 100 - width;
-        columns[0].width += "%";
-        columns[1].width += "%";
-
-        var dataGrid = new WebInspector.DOMStorageDataGrid(columns, this.domStorage, keys);
-        var length = nodes.length;
-        for (var i = 0; i < length; ++i)
-            dataGrid.appendChild(nodes[i]);
-        dataGrid.addCreationNode(false);
-        if (length > 0)
-            nodes[0].selected = true;
-        return dataGrid;
-    },
-
-    _deleteButtonClicked: function(event)
-    {
-        if (this._dataGrid) {
-            this._dataGrid.deleteSelectedRow();
-            
-            this.show();
-        }
-    },
-
-    _refreshButtonClicked: function(event)
-    {
-        this.update();
-    }
-}
-
-WebInspector.DOMStorageItemsView.prototype.__proto__ = WebInspector.View.prototype;
diff --git a/resources/inspector/DataGrid.js b/resources/inspector/DataGrid.js
deleted file mode 100755
index ce61548..0000000
--- a/resources/inspector/DataGrid.js
+++ /dev/null
@@ -1,1041 +0,0 @@
-/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *        notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *        notice, this list of conditions and the following disclaimer in the
- *        documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.         IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WebInspector.DataGrid = function(columns)
-{
-    this.element = document.createElement("div");
-    this.element.className = "data-grid";
-    this.element.tabIndex = 0;
-    this.element.addEventListener("keydown", this._keyDown.bind(this), false);
-
-    this._headerTable = document.createElement("table");
-    this._headerTable.className = "header";
-
-    this._dataTable = document.createElement("table");
-    this._dataTable.className = "data";
-
-    this._dataTable.addEventListener("mousedown", this._mouseDownInDataTable.bind(this), true);
-    this._dataTable.addEventListener("click", this._clickInDataTable.bind(this), true);
-
-    this.aligned = {};
-
-    var scrollContainer = document.createElement("div");
-    scrollContainer.className = "data-container";
-    scrollContainer.appendChild(this._dataTable);
-
-    this.element.appendChild(this._headerTable);
-    this.element.appendChild(scrollContainer);
-
-    var headerRow = document.createElement("tr");
-    var columnGroup = document.createElement("colgroup");
-    var columnCount = 0;
-
-    for (var columnIdentifier in columns) {
-        var column = columns[columnIdentifier];
-        if (column.disclosure)
-            this.disclosureColumnIdentifier = columnIdentifier;
-
-        var col = document.createElement("col");
-        if (column.width)
-            col.style.width = column.width;
-        columnGroup.appendChild(col);
-
-        var cell = document.createElement("th");
-        cell.className = columnIdentifier + "-column";
-        cell.columnIdentifier = columnIdentifier;
-
-        var div = document.createElement("div");
-        div.textContent = column.title;
-        cell.appendChild(div);
-
-        if (column.sort) {
-            cell.addStyleClass("sort-" + column.sort);
-            this._sortColumnCell = cell;
-        }
-
-        if (column.sortable) {
-            cell.addEventListener("click", this._clickInHeaderCell.bind(this), false);
-            cell.addStyleClass("sortable");
-        }
-
-        if (column.aligned) {
-            cell.addStyleClass(column.aligned);
-            this.aligned[columnIdentifier] = column.aligned;
-        }
-
-        headerRow.appendChild(cell);
-
-        ++columnCount;
-    }
-
-    columnGroup.span = columnCount;
-
-    var cell = document.createElement("th");
-    cell.className = "corner";
-    headerRow.appendChild(cell);
-
-    this._headerTableColumnGroup = columnGroup;
-    this._headerTable.appendChild(this._headerTableColumnGroup);
-    this.headerTableBody.appendChild(headerRow);
-
-    var fillerRow = document.createElement("tr");
-    fillerRow.className = "filler";
-
-    for (var i = 0; i < columnCount; ++i) {
-        var cell = document.createElement("td");
-        fillerRow.appendChild(cell);
-    }
-    
-    this._dataTableColumnGroup = columnGroup.cloneNode(true);
-    this._dataTable.appendChild(this._dataTableColumnGroup);
-    this.dataTableBody.appendChild(fillerRow);
-
-    this.columns = columns || {};
-    this.children = [];
-    this.selectedNode = null;
-    this.expandNodesWhenArrowing = false;
-    this.root = true;
-    this.hasChildren = false;
-    this.expanded = true;
-    this.revealed = true;
-    this.selected = false;
-    this.dataGrid = this;
-    this.indentWidth = 15;
-    this.resizers = [];
-    this.columnWidthsInitialized = false;
-}
-
-WebInspector.DataGrid.prototype = {
-    get sortColumnIdentifier()
-    {
-        if (!this._sortColumnCell)
-            return null;
-        return this._sortColumnCell.columnIdentifier;
-    },
-
-    get sortOrder()
-    {
-        if (!this._sortColumnCell || this._sortColumnCell.hasStyleClass("sort-ascending"))
-            return "ascending";
-        if (this._sortColumnCell.hasStyleClass("sort-descending"))
-            return "descending";
-        return null;
-    },
-
-    get headerTableBody()
-    {
-        if ("_headerTableBody" in this)
-            return this._headerTableBody;
-
-        this._headerTableBody = this._headerTable.getElementsByTagName("tbody")[0];
-        if (!this._headerTableBody) {
-            this._headerTableBody = this.element.ownerDocument.createElement("tbody");
-            this._headerTable.insertBefore(this._headerTableBody, this._headerTable.tFoot);
-        }
-
-        return this._headerTableBody;
-    },
-
-    get dataTableBody()
-    {
-        if ("_dataTableBody" in this)
-            return this._dataTableBody;
-
-        this._dataTableBody = this._dataTable.getElementsByTagName("tbody")[0];
-        if (!this._dataTableBody) {
-            this._dataTableBody = this.element.ownerDocument.createElement("tbody");
-            this._dataTable.insertBefore(this._dataTableBody, this._dataTable.tFoot);
-        }
-
-        return this._dataTableBody;
-    },
- 
-    // Updates the widths of the table, including the positions of the column
-    // resizers.
-    //
-    // IMPORTANT: This function MUST be called once after the element of the
-    // DataGrid is attached to its parent element and every subsequent time the
-    // width of the parent element is changed in order to make it possible to
-    // resize the columns.
-    //
-    // If this function is not called after the DataGrid is attached to its
-    // parent element, then the DataGrid's columns will not be resizable.
-    updateWidths: function()
-    {
-        var headerTableColumns = this._headerTableColumnGroup.children;
-        
-        var left = 0;
-        var tableWidth = this._dataTable.offsetWidth;
-        var numColumns = headerTableColumns.length;
-        
-        if (!this.columnWidthsInitialized) {
-            // Give all the columns initial widths now so that during a resize,
-            // when the two columns that get resized get a percent value for
-            // their widths, all the other columns already have percent values
-            // for their widths.
-            for (var i = 0; i < numColumns; i++) {
-                var columnWidth = this.headerTableBody.rows[0].cells[i].offsetWidth;
-                var percentWidth = ((columnWidth / tableWidth) * 100) + "%";
-                this._headerTableColumnGroup.children[i].style.width = percentWidth;
-                this._dataTableColumnGroup.children[i].style.width = percentWidth;
-            }
-            this.columnWidthsInitialized = true;
-        }
-        
-        // Make n - 1 resizers for n columns. 
-        for (var i = 0; i < numColumns - 1; i++) {
-            var resizer = this.resizers[i];
-
-            if (!resizer) {
-                // This is the first call to updateWidth, so the resizers need
-                // to be created.
-                resizer = document.createElement("div");
-                resizer.addStyleClass("data-grid-resizer");
-                // This resizer is associated with the column to its right.
-                resizer.rightNeighboringColumnID = i + 1;
-                resizer.addEventListener("mousedown", this._startResizerDragging.bind(this), false);
-                this.element.appendChild(resizer);
-                this.resizers[i] = resizer;
-            }
-
-            // Get the width of the cell in the first (and only) row of the
-            // header table in order to determine the width of the column, since
-            // it is not possible to query a column for its width.
-            left += this.headerTableBody.rows[0].cells[i].offsetWidth;
-            
-            resizer.style.left = left + "px";
-        }
-    },
-
-    addCreationNode: function(hasChildren)
-    {
-        if (this.creationNode)
-            this.creationNode.makeNormal();
-
-        var emptyData = {};
-        for (var column in this.columns)
-            emptyData[column] = '';
-        this.creationNode = new WebInspector.CreationDataGridNode(emptyData, hasChildren);
-        this.appendChild(this.creationNode);
-    },
-
-    appendChild: function(child)
-    {
-        this.insertChild(child, this.children.length);
-    },
-
-    insertChild: function(child, index)
-    {
-        if (!child)
-            throw("insertChild: Node can't be undefined or null.");
-        if (child.parent === this)
-            throw("insertChild: Node is already a child of this node.");
-
-        if (child.parent)
-            child.parent.removeChild(child);
-
-        this.children.splice(index, 0, child);
-        this.hasChildren = true;
-
-        child.parent = this;
-        child.dataGrid = this.dataGrid;
-        child._recalculateSiblings(index);
-
-        delete child._depth;
-        delete child._revealed;
-        delete child._attached;
-
-        var current = child.children[0];
-        while (current) {
-            current.dataGrid = this.dataGrid;
-            delete current._depth;
-            delete current._revealed;
-            delete current._attached;
-            current = current.traverseNextNode(false, child, true);
-        }
-
-        if (this.expanded)
-            child._attach();
-    },
-
-    removeChild: function(child)
-    {
-        if (!child)
-            throw("removeChild: Node can't be undefined or null.");
-        if (child.parent !== this)
-            throw("removeChild: Node is not a child of this node.");
-
-        child.deselect();
-
-        this.children.remove(child, true);
-
-        if (child.previousSibling)
-            child.previousSibling.nextSibling = child.nextSibling;
-        if (child.nextSibling)
-            child.nextSibling.previousSibling = child.previousSibling;
-
-        child.dataGrid = null;
-        child.parent = null;
-        child.nextSibling = null;
-        child.previousSibling = null;
-
-        if (this.children.length <= 0)
-            this.hasChildren = false;
-    },
-
-    removeChildren: function()
-    {
-        for (var i = 0; i < this.children.length; ++i) {
-            var child = this.children[i];
-            child.deselect();
-            child._detach();
-
-            child.dataGrid = null;
-            child.parent = null;
-            child.nextSibling = null;
-            child.previousSibling = null;
-        }
-
-        this.children = [];
-        this.hasChildren = false;
-    },
-
-    removeChildrenRecursive: function()
-    {
-        var childrenToRemove = this.children;
-
-        var child = this.children[0];
-        while (child) {
-            if (child.children.length)
-                childrenToRemove = childrenToRemove.concat(child.children);
-            child = child.traverseNextNode(false, this, true);
-        }
-
-        for (var i = 0; i < childrenToRemove.length; ++i) {
-            var child = childrenToRemove[i];
-            child.deselect();
-            child._detach();
-
-            child.children = [];
-            child.dataGrid = null;
-            child.parent = null;
-            child.nextSibling = null;
-            child.previousSibling = null;
-        }
-
-        this.children = [];
-    },
-
-    handleKeyEvent: function(event)
-    {
-        if (!this.selectedNode || event.shiftKey || event.metaKey || event.ctrlKey)
-            return false;
-
-        var handled = false;
-        var nextSelectedNode;
-        if (event.keyIdentifier === "Up" && !event.altKey) {
-            nextSelectedNode = this.selectedNode.traversePreviousNode(true);
-            while (nextSelectedNode && !nextSelectedNode.selectable)
-                nextSelectedNode = nextSelectedNode.traversePreviousNode(!this.expandTreeNodesWhenArrowing);
-            handled = nextSelectedNode ? true : false;
-        } else if (event.keyIdentifier === "Down" && !event.altKey) {
-            nextSelectedNode = this.selectedNode.traverseNextNode(true);
-            while (nextSelectedNode && !nextSelectedNode.selectable)
-                nextSelectedNode = nextSelectedNode.traverseNextNode(!this.expandTreeNodesWhenArrowing);
-            handled = nextSelectedNode ? true : false;
-        } else if (event.keyIdentifier === "Left") {
-            if (this.selectedNode.expanded) {
-                if (event.altKey)
-                    this.selectedNode.collapseRecursively();
-                else
-                    this.selectedNode.collapse();
-                handled = true;
-            } else if (this.selectedNode.parent && !this.selectedNode.parent.root) {
-                handled = true;
-                if (this.selectedNode.parent.selectable) {
-                    nextSelectedNode = this.selectedNode.parent;
-                    handled = nextSelectedNode ? true : false;
-                } else if (this.selectedNode.parent)
-                    this.selectedNode.parent.collapse();
-            }
-        } else if (event.keyIdentifier === "Right") {
-            if (!this.selectedNode.revealed) {
-                this.selectedNode.reveal();
-                handled = true;
-            } else if (this.selectedNode.hasChildren) {
-                handled = true;
-                if (this.selectedNode.expanded) {
-                    nextSelectedNode = this.selectedNode.children[0];
-                    handled = nextSelectedNode ? true : false;
-                } else {
-                    if (event.altKey)
-                        this.selectedNode.expandRecursively();
-                    else
-                        this.selectedNode.expand();
-                }
-            }
-        }
-
-        if (nextSelectedNode) {
-            nextSelectedNode.reveal();
-            nextSelectedNode.select();
-        }
-
-        if (handled) {
-            event.preventDefault();
-            event.stopPropagation();
-        }
-
-        return handled;
-    },
-
-    expand: function()
-    {
-        // This is the root, do nothing.
-    },
-
-    collapse: function()
-    {
-        // This is the root, do nothing.
-    },
-
-    reveal: function()
-    {
-        // This is the root, do nothing.
-    },
-
-    dataGridNodeFromEvent: function(event)
-    {
-        var rowElement = event.target.enclosingNodeOrSelfWithNodeName("tr");
-        return rowElement._dataGridNode;
-    },
-
-    dataGridNodeFromPoint: function(x, y)
-    {
-        var node = this._dataTable.ownerDocument.elementFromPoint(x, y);
-        var rowElement = node.enclosingNodeOrSelfWithNodeName("tr");
-        return rowElement._dataGridNode;
-    },
-
-    _keyDown: function(event)
-    {
-        this.handleKeyEvent(event);
-    },
-
-    _clickInHeaderCell: function(event)
-    {
-        var cell = event.target.enclosingNodeOrSelfWithNodeName("th");
-        if (!cell || !cell.columnIdentifier || !cell.hasStyleClass("sortable"))
-            return;
-
-        var sortOrder = this.sortOrder;
-
-        if (this._sortColumnCell) {
-            this._sortColumnCell.removeStyleClass("sort-ascending");
-            this._sortColumnCell.removeStyleClass("sort-descending");
-        }
-
-        if (cell == this._sortColumnCell) {
-            if (sortOrder == "ascending")
-                sortOrder = "descending";
-            else
-                sortOrder = "ascending";
-        }
-
-        this._sortColumnCell = cell;
-
-        cell.addStyleClass("sort-" + sortOrder);
-
-        this.dispatchEventToListeners("sorting changed");
-    },
-
-    _mouseDownInDataTable: function(event)
-    {
-        var gridNode = this.dataGridNodeFromEvent(event);
-        if (!gridNode || !gridNode.selectable)
-            return;
-
-        if (gridNode.isEventWithinDisclosureTriangle(event))
-            return;
-
-        if (event.metaKey) {
-            if (gridNode.selected)
-                gridNode.deselect();
-            else
-                gridNode.select();
-        } else
-            gridNode.select();
-    },
-
-    _clickInDataTable: function(event)
-    {
-        var gridNode = this.dataGridNodeFromEvent(event);
-        if (!gridNode || !gridNode.hasChildren)
-            return;
-
-        if (!gridNode.isEventWithinDisclosureTriangle(event))
-            return;
-
-        if (gridNode.expanded) {
-            if (event.altKey)
-                gridNode.collapseRecursively();
-            else
-                gridNode.collapse();
-        } else {
-            if (event.altKey)
-                gridNode.expandRecursively();
-            else
-                gridNode.expand();
-        }
-    },
-    
-    _startResizerDragging: function(event)
-    {
-        this.currentResizer = event.target;
-        if (!this.currentResizer.rightNeighboringColumnID)
-            return;
-        WebInspector.elementDragStart(this.lastResizer, this._resizerDragging.bind(this),
-            this._endResizerDragging.bind(this), event, "col-resize");
-    },
-    
-    _resizerDragging: function(event)
-    {
-        var resizer = this.currentResizer;
-        if (!resizer)
-            return;
-        
-        // Constrain the dragpoint to be within the containing div of the
-        // datagrid.
-        var dragPoint = event.clientX - this.element.totalOffsetLeft;
-        // Constrain the dragpoint to be within the space made up by the
-        // column directly to the left and the column directly to the right.
-        var leftEdgeOfPreviousColumn = 0;
-        var firstRowCells = this.headerTableBody.rows[0].cells;
-        for (var i = 0; i < resizer.rightNeighboringColumnID - 1; i++)
-            leftEdgeOfPreviousColumn += firstRowCells[i].offsetWidth;
-            
-        var rightEdgeOfNextColumn = leftEdgeOfPreviousColumn + firstRowCells[resizer.rightNeighboringColumnID - 1].offsetWidth + firstRowCells[resizer.rightNeighboringColumnID].offsetWidth;
-        
-        // Give each column some padding so that they don't disappear.               
-        var leftMinimum = leftEdgeOfPreviousColumn + this.ColumnResizePadding;
-        var rightMaximum = rightEdgeOfNextColumn - this.ColumnResizePadding;
-        
-        dragPoint = Number.constrain(dragPoint, leftMinimum, rightMaximum);
-        
-        resizer.style.left = (dragPoint - this.CenterResizerOverBorderAdjustment) + "px";
-        
-        var percentLeftColumn = (((dragPoint - leftEdgeOfPreviousColumn) / this._dataTable.offsetWidth) * 100) + "%";
-        this._headerTableColumnGroup.children[resizer.rightNeighboringColumnID - 1].style.width = percentLeftColumn;
-        this._dataTableColumnGroup.children[resizer.rightNeighboringColumnID - 1].style.width = percentLeftColumn;
-        
-        var percentRightColumn = (((rightEdgeOfNextColumn - dragPoint) / this._dataTable.offsetWidth) * 100) + "%";
-        this._headerTableColumnGroup.children[resizer.rightNeighboringColumnID].style.width =  percentRightColumn;
-        this._dataTableColumnGroup.children[resizer.rightNeighboringColumnID].style.width = percentRightColumn;
-        
-        event.preventDefault();
-    },
-    
-    _endResizerDragging: function(event)
-    {
-        WebInspector.elementDragEnd(event);
-        this.currentResizer = null;
-    },
-    
-    ColumnResizePadding: 10,
-    
-    CenterResizerOverBorderAdjustment: 3,
-}
-
-WebInspector.DataGrid.prototype.__proto__ = WebInspector.Object.prototype;
-
-WebInspector.DataGridNode = function(data, hasChildren)
-{
-    this._expanded = false;
-    this._selected = false;
-    this._shouldRefreshChildren = true;
-    this._data = data || {};
-    this.hasChildren = hasChildren || false;
-    this.children = [];
-    this.dataGrid = null;
-    this.parent = null;
-    this.previousSibling = null;
-    this.nextSibling = null;
-    this.disclosureToggleWidth = 10;
-}
-
-WebInspector.DataGridNode.prototype = {
-    selectable: true,
-
-    get element()
-    {
-        if (this._element)
-            return this._element;
-
-        if (!this.dataGrid)
-            return null;
-
-        this._element = document.createElement("tr");
-        this._element._dataGridNode = this;
-
-        if (this.hasChildren)
-            this._element.addStyleClass("parent");
-        if (this.expanded)
-            this._element.addStyleClass("expanded");
-        if (this.selected)
-            this._element.addStyleClass("selected");
-        if (this.revealed)
-            this._element.addStyleClass("revealed");
-
-        for (var columnIdentifier in this.dataGrid.columns) {
-            var cell = this.createCell(columnIdentifier);
-            this._element.appendChild(cell);
-        }
-
-        return this._element;
-    },
-
-    get data()
-    {
-        return this._data;
-    },
-
-    set data(x)
-    {
-        this._data = x || {};
-        this.refresh();
-    },
-
-    get revealed()
-    {
-        if ("_revealed" in this)
-            return this._revealed;
-
-        var currentAncestor = this.parent;
-        while (currentAncestor && !currentAncestor.root) {
-            if (!currentAncestor.expanded) {
-                this._revealed = false;
-                return false;
-            }
-
-            currentAncestor = currentAncestor.parent;
-        }
-
-        this._revealed = true;
-        return true;
-    },
-
-    set hasChildren(x)
-    {
-        if (this._hasChildren === x)
-            return;
-
-        this._hasChildren = x;
-
-        if (!this._element)
-            return;
-
-        if (this._hasChildren)
-        {
-            this._element.addStyleClass("parent");
-            if (this.expanded)
-                this._element.addStyleClass("expanded");
-        }
-        else
-        {
-            this._element.removeStyleClass("parent");
-            this._element.removeStyleClass("expanded");
-        }
-    },
-
-    get hasChildren()
-    {
-        return this._hasChildren;
-    },
-
-    set revealed(x)
-    {
-        if (this._revealed === x)
-            return;
-
-        this._revealed = x;
-
-        if (this._element) {
-            if (this._revealed)
-                this._element.addStyleClass("revealed");
-            else
-                this._element.removeStyleClass("revealed");
-        }
-
-        for (var i = 0; i < this.children.length; ++i)
-            this.children[i].revealed = x && this.expanded;
-    },
-
-    get depth()
-    {
-        if ("_depth" in this)
-            return this._depth;
-        if (this.parent && !this.parent.root)
-            this._depth = this.parent.depth + 1;
-        else
-            this._depth = 0;
-        return this._depth;
-    },
-
-    get shouldRefreshChildren()
-    {
-        return this._shouldRefreshChildren;
-    },
-
-    set shouldRefreshChildren(x)
-    {
-        this._shouldRefreshChildren = x;
-        if (x && this.expanded)
-            this.expand();
-    },
-
-    get selected()
-    {
-        return this._selected;
-    },
-
-    set selected(x)
-    {
-        if (x)
-            this.select();
-        else
-            this.deselect();
-    },
-
-    get expanded()
-    {
-        return this._expanded;
-    },
-
-    set expanded(x)
-    {
-        if (x)
-            this.expand();
-        else
-            this.collapse();
-    },
-
-    refresh: function()
-    {
-        if (!this._element || !this.dataGrid)
-            return;
-
-        this._element.removeChildren();
-
-        for (var columnIdentifier in this.dataGrid.columns) {
-            var cell = this.createCell(columnIdentifier);
-            this._element.appendChild(cell);
-        }
-    },
-
-    createCell: function(columnIdentifier)
-    {
-        var cell = document.createElement("td");
-        cell.className = columnIdentifier + "-column";
-
-        var alignment = this.dataGrid.aligned[columnIdentifier];
-        if (alignment)
-            cell.addStyleClass(alignment);
-
-        var div = document.createElement("div");
-        div.textContent = this.data[columnIdentifier];
-        cell.appendChild(div);
-
-        if (columnIdentifier === this.dataGrid.disclosureColumnIdentifier) {
-            cell.addStyleClass("disclosure");
-            if (this.depth)
-                cell.style.setProperty("padding-left", (this.depth * this.dataGrid.indentWidth) + "px");
-        }
-
-        return cell;
-    },
-
-    // Share these functions with DataGrid. They are written to work with a DataGridNode this object.
-    appendChild: WebInspector.DataGrid.prototype.appendChild,
-    insertChild: WebInspector.DataGrid.prototype.insertChild,
-    removeChild: WebInspector.DataGrid.prototype.removeChild,
-    removeChildren: WebInspector.DataGrid.prototype.removeChildren,
-    removeChildrenRecursive: WebInspector.DataGrid.prototype.removeChildrenRecursive,
-
-    _recalculateSiblings: function(myIndex)
-    {
-        if (!this.parent)
-            return;
-
-        var previousChild = (myIndex > 0 ? this.parent.children[myIndex - 1] : null);
-
-        if (previousChild) {
-            previousChild.nextSibling = this;
-            this.previousSibling = previousChild;
-        } else
-            this.previousSibling = null;
-
-        var nextChild = this.parent.children[myIndex + 1];
-
-        if (nextChild) {
-            nextChild.previousSibling = this;
-            this.nextSibling = nextChild;
-        } else
-            this.nextSibling = null;
-    },
-
-    collapse: function()
-    {
-        if (this._element)
-            this._element.removeStyleClass("expanded");
-
-        this._expanded = false;
-
-        for (var i = 0; i < this.children.length; ++i)
-            this.children[i].revealed = false;
-
-        this.dispatchEventToListeners("collapsed");
-    },
-
-    collapseRecursively: function()
-    {
-        var item = this;
-        while (item) {
-            if (item.expanded)
-                item.collapse();
-            item = item.traverseNextNode(false, this, true);
-        }
-    },
-
-    expand: function()
-    {
-        if (!this.hasChildren || this.expanded)
-            return;
-
-        if (this.revealed && !this._shouldRefreshChildren)
-            for (var i = 0; i < this.children.length; ++i)
-                this.children[i].revealed = true;
-
-        if (this._shouldRefreshChildren) {
-            for (var i = 0; i < this.children.length; ++i)
-                this.children[i]._detach();
-
-            this.dispatchEventToListeners("populate");
-
-            if (this._attached) {
-                for (var i = 0; i < this.children.length; ++i) {
-                    var child = this.children[i];
-                    if (this.revealed)
-                        child.revealed = true;
-                    child._attach();
-                }
-            }
-
-            delete this._shouldRefreshChildren;
-        }
-
-        if (this._element)
-            this._element.addStyleClass("expanded");
-
-        this._expanded = true;
-
-        this.dispatchEventToListeners("expanded");
-    },
-
-    expandRecursively: function()
-    {
-        var item = this;
-        while (item) {
-            item.expand();
-            item = item.traverseNextNode(false, this);
-        }
-    },
-
-    reveal: function()
-    {
-        var currentAncestor = this.parent;
-        while (currentAncestor && !currentAncestor.root) {
-            if (!currentAncestor.expanded)
-                currentAncestor.expand();
-            currentAncestor = currentAncestor.parent;
-        }
-
-        this.element.scrollIntoViewIfNeeded(false);
-
-        this.dispatchEventToListeners("revealed");
-    },
-
-    select: function(supressSelectedEvent)
-    {
-        if (!this.dataGrid || !this.selectable || this.selected)
-            return;
-
-        if (this.dataGrid.selectedNode)
-            this.dataGrid.selectedNode.deselect();
-
-        this._selected = true;
-        this.dataGrid.selectedNode = this;
-
-        if (this._element)
-            this._element.addStyleClass("selected");
-
-        if (!supressSelectedEvent)
-            this.dispatchEventToListeners("selected");
-    },
-
-    deselect: function(supressDeselectedEvent)
-    {
-        if (!this.dataGrid || this.dataGrid.selectedNode !== this || !this.selected)
-            return;
-
-        this._selected = false;
-        this.dataGrid.selectedNode = null;
-
-        if (this._element)
-            this._element.removeStyleClass("selected");
-
-        if (!supressDeselectedEvent)
-            this.dispatchEventToListeners("deselected");
-    },
-
-    traverseNextNode: function(skipHidden, stayWithin, dontPopulate, info)
-    {
-        if (!dontPopulate && this.hasChildren)
-            this.dispatchEventToListeners("populate");
-
-        if (info)
-            info.depthChange = 0;
-
-        var node = (!skipHidden || this.revealed) ? this.children[0] : null;
-        if (node && (!skipHidden || this.expanded)) {
-            if (info)
-                info.depthChange = 1;
-            return node;
-        }
-
-        if (this === stayWithin)
-            return null;
-
-        node = (!skipHidden || this.revealed) ? this.nextSibling : null;
-        if (node)
-            return node;
-
-        node = this;
-        while (node && !node.root && !((!skipHidden || node.revealed) ? node.nextSibling : null) && node.parent !== stayWithin) {
-            if (info)
-                info.depthChange -= 1;
-            node = node.parent;
-        }
-
-        if (!node)
-            return null;
-
-        return (!skipHidden || node.revealed) ? node.nextSibling : null;
-    },
-
-    traversePreviousNode: function(skipHidden, dontPopulate)
-    {
-        var node = (!skipHidden || this.revealed) ? this.previousSibling : null;
-        if (!dontPopulate && node && node.hasChildren)
-            node.dispatchEventToListeners("populate");
-
-        while (node && ((!skipHidden || (node.revealed && node.expanded)) ? node.children[node.children.length - 1] : null)) {
-            if (!dontPopulate && node.hasChildren)
-                node.dispatchEventToListeners("populate");
-            node = ((!skipHidden || (node.revealed && node.expanded)) ? node.children[node.children.length - 1] : null);
-        }
-
-        if (node)
-            return node;
-
-        if (!this.parent || this.parent.root)
-            return null;
-
-        return this.parent;
-    },
-
-    isEventWithinDisclosureTriangle: function(event)
-    {
-        if (!this.hasChildren)
-            return false;
-        var cell = event.target.enclosingNodeOrSelfWithNodeName("td");
-        if (!cell.hasStyleClass("disclosure"))
-            return false;
-        var computedLeftPadding = window.getComputedStyle(cell).getPropertyCSSValue("padding-left").getFloatValue(CSSPrimitiveValue.CSS_PX);
-        var left = cell.totalOffsetLeft + computedLeftPadding;
-        return event.pageX >= left && event.pageX <= left + this.disclosureToggleWidth;
-    },
-
-    _attach: function()
-    {
-        if (!this.dataGrid || this._attached)
-            return;
-
-        this._attached = true;
-
-        var nextNode = null;
-        var previousNode = this.traversePreviousNode(true, true);
-        if (previousNode && previousNode.element.parentNode && previousNode.element.nextSibling)
-            var nextNode = previousNode.element.nextSibling;
-        if (!nextNode)
-            nextNode = this.dataGrid.dataTableBody.lastChild;
-        this.dataGrid.dataTableBody.insertBefore(this.element, nextNode);
-
-        if (this.expanded)
-            for (var i = 0; i < this.children.length; ++i)
-                this.children[i]._attach();
-    },
-
-    _detach: function()
-    {
-        if (!this._attached)
-            return;
-
-        this._attached = false;
-
-        if (this._element && this._element.parentNode)
-            this._element.parentNode.removeChild(this._element);
-
-        for (var i = 0; i < this.children.length; ++i)
-            this.children[i]._detach();
-    }
-}
-
-WebInspector.DataGridNode.prototype.__proto__ = WebInspector.Object.prototype;
-
-WebInspector.CreationDataGridNode = function(data, hasChildren)
-{
-    WebInspector.DataGridNode.call(this, data, hasChildren);
-    this.isCreationNode = true;
-}
-
-WebInspector.CreationDataGridNode.prototype = {
-    makeNormal: function()
-    {
-        delete this.isCreationNode;
-        delete this.makeNormal;
-    }
-}
-
-WebInspector.CreationDataGridNode.prototype.__proto__ = WebInspector.DataGridNode.prototype;
diff --git a/resources/inspector/Database.js b/resources/inspector/Database.js
deleted file mode 100755
index 1a348fc..0000000
--- a/resources/inspector/Database.js
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2007, 2008 Apple Inc.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- *     its contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WebInspector.Database = function(id, domain, name, version)
-{
-    this._id = id;
-    this._domain = domain;
-    this._name = name;
-    this._version = version;
-}
-
-WebInspector.Database.prototype = {
-    get id()
-    {
-        return this._id;
-    },
-
-    get name()
-    {
-        return this._name;
-    },
-
-    set name(x)
-    {
-        this._name = x;
-    },
-
-    get version()
-    {
-        return this._version;
-    },
-
-    set version(x)
-    {
-        this._version = x;
-    },
-
-    get domain()
-    {
-        return this._domain;
-    },
-
-    set domain(x)
-    {
-        this._domain = x;
-    },
-
-    get displayDomain()
-    {
-        return WebInspector.Resource.prototype.__lookupGetter__("displayDomain").call(this);
-    },
-
-    getTableNames: function(callback)
-    {
-        function sortingCallback(names)
-        {
-            callback(names.sort());
-        }
-        var callId = WebInspector.Callback.wrap(sortingCallback);
-        InspectorController.getDatabaseTableNames(callId, this._id);
-    },
-    
-    executeSql: function(query, onSuccess, onError)
-    {
-        function callback(result)
-        {
-            if (!(result instanceof Array)) {
-                onError(result);
-                return;
-            }
-            onSuccess(result);
-        }
-        InjectedScriptAccess.executeSql(this._id, query, callback);
-    }
-}
-
-WebInspector.didGetDatabaseTableNames = WebInspector.Callback.processCallback;
diff --git a/resources/inspector/DatabaseQueryView.js b/resources/inspector/DatabaseQueryView.js
deleted file mode 100755
index 6c5fa02..0000000
--- a/resources/inspector/DatabaseQueryView.js
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WebInspector.DatabaseQueryView = function(database)
-{
-    WebInspector.View.call(this);
-
-    this.database = database;
-
-    this.element.addStyleClass("storage-view");
-    this.element.addStyleClass("query");
-    this.element.tabIndex = 0;
-
-    this.element.addEventListener("selectstart", this._selectStart.bind(this), false);
-
-    this.promptElement = document.createElement("div");
-    this.promptElement.className = "database-query-prompt";
-    this.promptElement.appendChild(document.createElement("br"));
-    this.promptElement.handleKeyEvent = this._promptKeyDown.bind(this);
-    this.element.appendChild(this.promptElement);
-
-    this.prompt = new WebInspector.TextPrompt(this.promptElement, this.completions.bind(this), " ");
-}
-
-WebInspector.DatabaseQueryView.prototype = {
-    show: function(parentElement)
-    {
-        WebInspector.View.prototype.show.call(this, parentElement);
-
-        function moveBackIfOutside()
-        {
-            if (!this.prompt.isCaretInsidePrompt() && window.getSelection().isCollapsed)
-                this.prompt.moveCaretToEndOfPrompt();
-        }
-
-        setTimeout(moveBackIfOutside.bind(this), 0);
-    },
-
-    completions: function(wordRange, bestMatchOnly, completionsReadyCallback)
-    {
-        var prefix = wordRange.toString().toLowerCase();
-        if (!prefix.length)
-            return;
-
-        var results = [];
-
-        function accumulateMatches(textArray)
-        {
-            if (bestMatchOnly && results.length)
-                return;
-            for (var i = 0; i < textArray.length; ++i) {
-                var text = textArray[i].toLowerCase();
-                if (text.length < prefix.length)
-                    continue;
-                if (text.indexOf(prefix) !== 0)
-                    continue;
-                results.push(textArray[i]);
-                if (bestMatchOnly)
-                    return;
-            }
-        }
-        
-        function tableNamesCallback(tableNames)
-        {
-            accumulateMatches(tableNames.map(function(name) { return name + " " }));
-            accumulateMatches(["SELECT ", "FROM ", "WHERE ", "LIMIT ", "DELETE FROM ", "CREATE ", "DROP ", "TABLE ", "INDEX ", "UPDATE ", "INSERT INTO ", "VALUES ("]);
-
-            completionsReadyCallback(results);
-        }
-        this.database.getTableNames(tableNamesCallback);
-    },
-
-    _promptKeyDown: function(event)
-    {
-        switch (event.keyIdentifier) {
-            case "Enter":
-                this._enterKeyPressed(event);
-                return;
-        }
-
-        this.prompt.handleKeyEvent(event);
-    },
-
-    _selectStart: function(event)
-    {
-        if (this._selectionTimeout)
-            clearTimeout(this._selectionTimeout);
-
-        this.prompt.clearAutoComplete();
-
-        function moveBackIfOutside()
-        {
-            delete this._selectionTimeout;
-            if (!this.prompt.isCaretInsidePrompt() && window.getSelection().isCollapsed)
-                this.prompt.moveCaretToEndOfPrompt();
-            this.prompt.autoCompleteSoon();
-        }
-
-        this._selectionTimeout = setTimeout(moveBackIfOutside.bind(this), 100);
-    },
-
-    _enterKeyPressed: function(event)
-    {
-        event.preventDefault();
-        event.stopPropagation();
-
-        this.prompt.clearAutoComplete(true);
-
-        var query = this.prompt.text;
-        if (!query.length)
-            return;
-
-        this.prompt.history.push(query);
-        this.prompt.historyOffset = 0;
-        this.prompt.text = "";
-
-        this.database.executeSql(query, this._queryFinished.bind(this, query), this._queryError.bind(this, query));
-    },
-
-    _queryFinished: function(query, result)
-    {
-        var dataGrid = WebInspector.panels.storage.dataGridForResult(result);
-        if (!dataGrid)
-            return;
-        dataGrid.element.addStyleClass("inline");
-        this._appendQueryResult(query, dataGrid.element);
-
-        if (query.match(/^create /i) || query.match(/^drop table /i))
-            WebInspector.panels.storage.updateDatabaseTables(this.database);
-    },
-
-    _queryError: function(query, error)
-    {
-        if (error.code == 1)
-            var message = error.message;
-        else if (error.code == 2)
-            var message = WebInspector.UIString("Database no longer has expected version.");
-        else
-            var message = WebInspector.UIString("An unexpected error %s occurred.", error.code);
-
-        this._appendQueryResult(query, message, "error");
-    },
-
-    _appendQueryResult: function(query, result, resultClassName)
-    {
-        var element = document.createElement("div");
-        element.className = "database-user-query";
-
-        var commandTextElement = document.createElement("span");
-        commandTextElement.className = "database-query-text";
-        commandTextElement.textContent = query;
-        element.appendChild(commandTextElement);
-
-        var resultElement = document.createElement("div");
-        resultElement.className = "database-query-result";
-
-        if (resultClassName)
-            resultElement.addStyleClass(resultClassName);
-
-        if (typeof result === "string" || result instanceof String)
-            resultElement.textContent = result;
-        else if (result && result.nodeName)
-            resultElement.appendChild(result);
-
-        if (resultElement.childNodes.length)
-            element.appendChild(resultElement);
-
-        this.element.insertBefore(element, this.promptElement);
-        this.promptElement.scrollIntoView(false);
-    }
-}
-
-WebInspector.DatabaseQueryView.prototype.__proto__ = WebInspector.View.prototype;
diff --git a/resources/inspector/DatabaseTableView.js b/resources/inspector/DatabaseTableView.js
deleted file mode 100755
index aa76794..0000000
--- a/resources/inspector/DatabaseTableView.js
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WebInspector.DatabaseTableView = function(database, tableName)
-{
-    WebInspector.View.call(this);
-
-    this.database = database;
-    this.tableName = tableName;
-
-    this.element.addStyleClass("storage-view");
-    this.element.addStyleClass("table");
-
-    this.refreshButton = new WebInspector.StatusBarButton(WebInspector.UIString("Refresh"), "refresh-storage-status-bar-item");
-    this.refreshButton.addEventListener("click", this._refreshButtonClicked.bind(this), false);
-}
-
-WebInspector.DatabaseTableView.prototype = {
-    show: function(parentElement)
-    {
-        WebInspector.View.prototype.show.call(this, parentElement);
-        this.update();
-    },
-
-    get statusBarItems()
-    {
-        return [this.refreshButton];
-    },
-
-    update: function()
-    {
-        this.database.executeSql("SELECT * FROM " + this.tableName, this._queryFinished.bind(this), this._queryError.bind(this));
-    },
-
-    _queryFinished: function(result)
-    {
-        this.element.removeChildren();
-
-        var dataGrid = WebInspector.panels.storage.dataGridForResult(result);
-        if (!dataGrid) {
-            var emptyMsgElement = document.createElement("div");
-            emptyMsgElement.className = "storage-table-empty";
-            emptyMsgElement.textContent = WebInspector.UIString("The “%s”\ntable is empty.", this.tableName);
-            this.element.appendChild(emptyMsgElement);
-            return;
-        }
-
-        this.element.appendChild(dataGrid.element);
-    },
-
-    _queryError: function(error)
-    {
-        this.element.removeChildren();
-
-        var errorMsgElement = document.createElement("div");
-        errorMsgElement.className = "storage-table-error";
-        errorMsgElement.textContent = WebInspector.UIString("An error occurred trying to\nread the “%s” table.", this.tableName);
-        this.element.appendChild(errorMsgElement);
-    },
-
-    _refreshButtonClicked: function(event)
-    {
-        this.update();
-    }
-}
-
-WebInspector.DatabaseTableView.prototype.__proto__ = WebInspector.View.prototype;
diff --git a/resources/inspector/DevTools.js b/resources/inspector/DevTools.js
new file mode 100644
index 0000000..41dd9f5
--- /dev/null
+++ b/resources/inspector/DevTools.js
@@ -0,0 +1,44479 @@
+/* utilities.js */

+

+/*

+ * Copyright (C) 2007 Apple Inc.  All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without

+ * modification, are permitted provided that the following conditions

+ * are met:

+ *

+ * 1.  Redistributions of source code must retain the above copyright

+ *     notice, this list of conditions and the following disclaimer. 

+ * 2.  Redistributions in binary form must reproduce the above copyright

+ *     notice, this list of conditions and the following disclaimer in the

+ *     documentation and/or other materials provided with the distribution. 

+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of

+ *     its contributors may be used to endorse or promote products derived

+ *     from this software without specific prior written permission. 

+ *

+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY

+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED

+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE

+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY

+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES

+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND

+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ */

+

+Object.proxyType = function(objectProxy)

+{

+    if (objectProxy === null)

+        return "null";

+

+    var type = typeof objectProxy;

+    if (type !== "object" && type !== "function")

+        return type;

+

+    return objectProxy.type;

+}

+

+Object.properties = function(obj)

+{

+    var properties = [];

+    for (var prop in obj)

+        properties.push(prop);

+    return properties;

+}

+

+Object.sortedProperties = function(obj, sortFunc)

+{

+    return Object.properties(obj).sort(sortFunc);

+}

+

+Function.prototype.bind = function(thisObject)

+{

+    var func = this;

+    var args = Array.prototype.slice.call(arguments, 1);

+    return function() { return func.apply(thisObject, args.concat(Array.prototype.slice.call(arguments, 0))) };

+}

+

+Node.prototype.rangeOfWord = function(offset, stopCharacters, stayWithinNode, direction)

+{

+    var startNode;

+    var startOffset = 0;

+    var endNode;

+    var endOffset = 0;

+

+    if (!stayWithinNode)

+        stayWithinNode = this;

+

+    if (!direction || direction === "backward" || direction === "both") {

+        var node = this;

+        while (node) {

+            if (node === stayWithinNode) {

+                if (!startNode)

+                    startNode = stayWithinNode;

+                break;

+            }

+

+            if (node.nodeType === Node.TEXT_NODE) {

+                var start = (node === this ? (offset - 1) : (node.nodeValue.length - 1));

+                for (var i = start; i >= 0; --i) {

+                    if (stopCharacters.indexOf(node.nodeValue[i]) !== -1) {

+                        startNode = node;

+                        startOffset = i + 1;

+                        break;

+                    }

+                }

+            }

+

+            if (startNode)

+                break;

+

+            node = node.traversePreviousNode(stayWithinNode);

+        }

+

+        if (!startNode) {

+            startNode = stayWithinNode;

+            startOffset = 0;

+        }

+    } else {

+        startNode = this;

+        startOffset = offset;

+    }

+

+    if (!direction || direction === "forward" || direction === "both") {

+        node = this;

+        while (node) {

+            if (node === stayWithinNode) {

+                if (!endNode)

+                    endNode = stayWithinNode;

+                break;

+            }

+

+            if (node.nodeType === Node.TEXT_NODE) {

+                var start = (node === this ? offset : 0);

+                for (var i = start; i < node.nodeValue.length; ++i) {

+                    if (stopCharacters.indexOf(node.nodeValue[i]) !== -1) {

+                        endNode = node;

+                        endOffset = i;

+                        break;

+                    }

+                }

+            }

+

+            if (endNode)

+                break;

+

+            node = node.traverseNextNode(stayWithinNode);

+        }

+

+        if (!endNode) {

+            endNode = stayWithinNode;

+            endOffset = stayWithinNode.nodeType === Node.TEXT_NODE ? stayWithinNode.nodeValue.length : stayWithinNode.childNodes.length;

+        }

+    } else {

+        endNode = this;

+        endOffset = offset;

+    }

+

+    var result = this.ownerDocument.createRange();

+    result.setStart(startNode, startOffset);

+    result.setEnd(endNode, endOffset);

+

+    return result;

+}

+

+Node.prototype.traverseNextTextNode = function(stayWithin)

+{

+    var node = this.traverseNextNode(stayWithin);

+    if (!node)

+        return;

+

+    while (node && node.nodeType !== Node.TEXT_NODE)

+        node = node.traverseNextNode(stayWithin);

+

+    return node;

+}

+

+Node.prototype.rangeBoundaryForOffset = function(offset)

+{

+    var node = this.traverseNextTextNode(this);

+    while (node && offset > node.nodeValue.length) {

+        offset -= node.nodeValue.length;

+        node = node.traverseNextTextNode(this);

+    }

+    if (!node)

+        return { container: this, offset: 0 };

+    return { container: node, offset: offset };

+}

+

+Element.prototype.removeStyleClass = function(className) 

+{

+    // Test for the simple case first.

+    if (this.className === className) {

+        this.className = "";

+        return;

+    }

+

+    var index = this.className.indexOf(className);

+    if (index === -1)

+        return;

+

+    var newClassName = " " + this.className + " ";

+    this.className = newClassName.replace(" " + className + " ", " ");

+}

+

+Element.prototype.removeMatchingStyleClasses = function(classNameRegex)

+{

+    var regex = new RegExp("(^|\\s+)" + classNameRegex + "($|\\s+)");

+    if (regex.test(this.className))

+        this.className = this.className.replace(regex, " ");

+}

+

+Element.prototype.addStyleClass = function(className) 

+{

+    if (className && !this.hasStyleClass(className))

+        this.className += (this.className.length ? " " + className : className);

+}

+

+Element.prototype.hasStyleClass = function(className) 

+{

+    if (!className)

+        return false;

+    // Test for the simple case

+    if (this.className === className)

+        return true;

+

+    var index = this.className.indexOf(className);

+    if (index === -1)

+        return false;

+    var toTest = " " + this.className + " ";

+    return toTest.indexOf(" " + className + " ", index) !== -1;

+}

+

+Element.prototype.positionAt = function(x, y)

+{

+    this.style.left = x + "px";

+    this.style.top = y + "px";

+}

+

+Node.prototype.enclosingNodeOrSelfWithNodeNameInArray = function(nameArray)

+{

+    for (var node = this; node && node !== this.ownerDocument; node = node.parentNode)

+        for (var i = 0; i < nameArray.length; ++i)

+            if (node.nodeName.toLowerCase() === nameArray[i].toLowerCase())

+                return node;

+    return null;

+}

+

+Node.prototype.enclosingNodeOrSelfWithNodeName = function(nodeName)

+{

+    return this.enclosingNodeOrSelfWithNodeNameInArray([nodeName]);

+}

+

+Node.prototype.enclosingNodeOrSelfWithClass = function(className)

+{

+    for (var node = this; node && node !== this.ownerDocument; node = node.parentNode)

+        if (node.nodeType === Node.ELEMENT_NODE && node.hasStyleClass(className))

+            return node;

+    return null;

+}

+

+Node.prototype.enclosingNodeWithClass = function(className)

+{

+    if (!this.parentNode)

+        return null;

+    return this.parentNode.enclosingNodeOrSelfWithClass(className);

+}

+

+Element.prototype.query = function(query) 

+{

+    return this.ownerDocument.evaluate(query, this, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;

+}

+

+Element.prototype.removeChildren = function()

+{

+    this.innerHTML = "";

+}

+

+Element.prototype.isInsertionCaretInside = function()

+{

+    var selection = window.getSelection();

+    if (!selection.rangeCount || !selection.isCollapsed)

+        return false;

+    var selectionRange = selection.getRangeAt(0);

+    return selectionRange.startContainer === this || selectionRange.startContainer.isDescendant(this);

+}

+

+Element.prototype.__defineGetter__("totalOffsetLeft", function()

+{

+    var total = 0;

+    for (var element = this; element; element = element.offsetParent)

+        total += element.offsetLeft + (this !== element ? element.clientLeft : 0);

+    return total;

+});

+

+Element.prototype.__defineGetter__("totalOffsetTop", function()

+{

+    var total = 0;

+    for (var element = this; element; element = element.offsetParent)

+        total += element.offsetTop + (this !== element ? element.clientTop : 0);

+    return total;

+});

+

+Element.prototype.offsetRelativeToWindow = function(targetWindow)

+{

+    var elementOffset = {x: 0, y: 0};

+    var curElement = this;

+    var curWindow = this.ownerDocument.defaultView;

+    while (curWindow && curElement) {

+        elementOffset.x += curElement.totalOffsetLeft;

+        elementOffset.y += curElement.totalOffsetTop;

+        if (curWindow === targetWindow)

+            break;

+

+        curElement = curWindow.frameElement;

+        curWindow = curWindow.parent;

+    }

+

+    return elementOffset;

+}

+

+Node.prototype.isWhitespace = isNodeWhitespace;

+Node.prototype.displayName = nodeDisplayName;

+Node.prototype.isAncestor = function(node)

+{

+    return isAncestorNode(this, node);

+};

+Node.prototype.isDescendant = isDescendantNode;

+Node.prototype.traverseNextNode = traverseNextNode;

+Node.prototype.traversePreviousNode = traversePreviousNode;

+Node.prototype.onlyTextChild = onlyTextChild;

+

+String.prototype.hasSubstring = function(string, caseInsensitive)

+{

+    if (!caseInsensitive)

+        return this.indexOf(string) !== -1;

+    return this.match(new RegExp(string.escapeForRegExp(), "i"));

+}

+

+String.prototype.escapeCharacters = function(chars)

+{

+    var foundChar = false;

+    for (var i = 0; i < chars.length; ++i) {

+        if (this.indexOf(chars.charAt(i)) !== -1) {

+            foundChar = true;

+            break;

+        }

+    }

+

+    if (!foundChar)

+        return this;

+

+    var result = "";

+    for (var i = 0; i < this.length; ++i) {

+        if (chars.indexOf(this.charAt(i)) !== -1)

+            result += "\\";

+        result += this.charAt(i);

+    }

+

+    return result;

+}

+

+String.prototype.escapeForRegExp = function()

+{

+    return this.escapeCharacters("^[]{}()\\.$*+?|");

+}

+

+String.prototype.escapeHTML = function()

+{

+    return this.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");

+}

+

+String.prototype.collapseWhitespace = function()

+{

+    return this.replace(/[\s\xA0]+/g, " ");

+}

+

+String.prototype.trimURL = function(baseURLDomain)

+{

+    var result = this.replace(/^https?:\/\//i, "");

+    if (baseURLDomain)

+        result = result.replace(new RegExp("^" + baseURLDomain.escapeForRegExp(), "i"), "");

+    return result;

+}

+

+function isNodeWhitespace()

+{

+    if (!this || this.nodeType !== Node.TEXT_NODE)

+        return false;

+    if (!this.nodeValue.length)

+        return true;

+    return this.nodeValue.match(/^[\s\xA0]+$/);

+}

+

+function nodeDisplayName()

+{

+    if (!this)

+        return "";

+

+    switch (this.nodeType) {

+        case Node.DOCUMENT_NODE:

+            return "Document";

+

+        case Node.ELEMENT_NODE:

+            var name = "<" + this.nodeName.toLowerCase();

+

+            if (this.hasAttributes()) {

+                var value = this.getAttribute("id");

+                if (value)

+                    name += " id=\"" + value + "\"";

+                value = this.getAttribute("class");

+                if (value)

+                    name += " class=\"" + value + "\"";

+                if (this.nodeName.toLowerCase() === "a") {

+                    value = this.getAttribute("name");

+                    if (value)

+                        name += " name=\"" + value + "\"";

+                    value = this.getAttribute("href");

+                    if (value)

+                        name += " href=\"" + value + "\"";

+                } else if (this.nodeName.toLowerCase() === "img") {

+                    value = this.getAttribute("src");

+                    if (value)

+                        name += " src=\"" + value + "\"";

+                } else if (this.nodeName.toLowerCase() === "iframe") {

+                    value = this.getAttribute("src");

+                    if (value)

+                        name += " src=\"" + value + "\"";

+                } else if (this.nodeName.toLowerCase() === "input") {

+                    value = this.getAttribute("name");

+                    if (value)

+                        name += " name=\"" + value + "\"";

+                    value = this.getAttribute("type");

+                    if (value)

+                        name += " type=\"" + value + "\"";

+                } else if (this.nodeName.toLowerCase() === "form") {

+                    value = this.getAttribute("action");

+                    if (value)

+                        name += " action=\"" + value + "\"";

+                }

+            }

+

+            return name + ">";

+

+        case Node.TEXT_NODE:

+            if (isNodeWhitespace.call(this))

+                return "(whitespace)";

+            return "\"" + this.nodeValue + "\"";

+

+        case Node.COMMENT_NODE:

+            return "<!--" + this.nodeValue + "-->";

+            

+        case Node.DOCUMENT_TYPE_NODE:

+            var docType = "<!DOCTYPE " + this.nodeName;

+            if (this.publicId) {

+                docType += " PUBLIC \"" + this.publicId + "\"";

+                if (this.systemId)

+                    docType += " \"" + this.systemId + "\"";

+            } else if (this.systemId)

+                docType += " SYSTEM \"" + this.systemId + "\"";

+            if (this.internalSubset)

+                docType += " [" + this.internalSubset + "]";

+            return docType + ">";

+    }

+

+    return this.nodeName.toLowerCase().collapseWhitespace();

+}

+

+function isAncestorNode(ancestor, node)

+{

+    if (!node || !ancestor)

+        return false;

+

+    var currentNode = node.parentNode;

+    while (currentNode) {

+        if (ancestor === currentNode)

+            return true;

+        currentNode = currentNode.parentNode;

+    }

+    return false;

+}

+

+function isDescendantNode(descendant)

+{

+    return isAncestorNode(descendant, this);

+}

+

+function traverseNextNode(stayWithin)

+{

+    if (!this)

+        return;

+

+    var node = this.firstChild;

+    if (node)

+        return node;

+

+    if (stayWithin && this === stayWithin)

+        return null;

+

+    node = this.nextSibling;

+    if (node)

+        return node;

+

+    node = this;

+    while (node && !node.nextSibling && (!stayWithin || !node.parentNode || node.parentNode !== stayWithin))

+        node = node.parentNode;

+    if (!node)

+        return null;

+

+    return node.nextSibling;

+}

+

+function traversePreviousNode(stayWithin)

+{

+    if (!this)

+        return;

+    if (stayWithin && this === stayWithin)

+        return null;

+    var node = this.previousSibling;

+    while (node && node.lastChild)

+        node = node.lastChild;

+    if (node)

+        return node;

+    return this.parentNode;

+}

+

+function onlyTextChild()

+{

+    if (!this)

+        return null;

+

+    var firstChild = this.firstChild;

+    if (!firstChild || firstChild.nodeType !== Node.TEXT_NODE)

+        return null;

+

+    var sibling = firstChild.nextSibling;

+    return sibling ? null : firstChild;

+}

+

+function appropriateSelectorForNode(node, justSelector)

+{

+    if (!node)

+        return "";

+

+    var lowerCaseName = node.localName || node.nodeName.toLowerCase();

+

+    var id = node.getAttribute("id");

+    if (id) {

+        var selector = "#" + id;

+        return (justSelector ? selector : lowerCaseName + selector);

+    }

+

+    var className = node.getAttribute("class");

+    if (className) {

+        var selector = "." + className.replace(/\s+/, ".");

+        return (justSelector ? selector : lowerCaseName + selector);

+    }

+

+    if (lowerCaseName === "input" && node.getAttribute("type"))

+        return lowerCaseName + "[type=\"" + node.getAttribute("type") + "\"]";

+

+    return lowerCaseName;

+}

+

+function getDocumentForNode(node)

+{

+    return node.nodeType == Node.DOCUMENT_NODE ? node : node.ownerDocument;

+}

+

+function parentNode(node)

+{

+    return node.parentNode;

+}

+

+Number.secondsToString = function(seconds, formatterFunction, higherResolution)

+{

+    if (!formatterFunction)

+        formatterFunction = String.sprintf;

+

+    if (seconds === 0)

+        return "0";

+

+    var ms = seconds * 1000;

+    if (higherResolution && ms < 1000)

+        return formatterFunction("%.3fms", ms);

+    else if (ms < 1000)

+        return formatterFunction("%.0fms", ms);

+

+    if (seconds < 60)

+        return formatterFunction("%.2fs", seconds);

+

+    var minutes = seconds / 60;

+    if (minutes < 60)

+        return formatterFunction("%.1fmin", minutes);

+

+    var hours = minutes / 60;

+    if (hours < 24)

+        return formatterFunction("%.1fhrs", hours);

+

+    var days = hours / 24;

+    return formatterFunction("%.1f days", days);

+}

+

+Number.bytesToString = function(bytes, formatterFunction, higherResolution)

+{

+    if (!formatterFunction)

+        formatterFunction = String.sprintf;

+    if (typeof higherResolution === "undefined")

+        higherResolution = true;

+

+    if (bytes < 1024)

+        return formatterFunction("%.0fB", bytes);

+

+    var kilobytes = bytes / 1024;

+    if (higherResolution && kilobytes < 1024)

+        return formatterFunction("%.2fKB", kilobytes);

+    else if (kilobytes < 1024)

+        return formatterFunction("%.0fKB", kilobytes);

+

+    var megabytes = kilobytes / 1024;

+    if (higherResolution)

+        return formatterFunction("%.3fMB", megabytes);

+    else

+        return formatterFunction("%.0fMB", megabytes);

+}

+

+Number.constrain = function(num, min, max)

+{

+    if (num < min)

+        num = min;

+    else if (num > max)

+        num = max;

+    return num;

+}

+

+HTMLTextAreaElement.prototype.moveCursorToEnd = function()

+{

+    var length = this.value.length;

+    this.setSelectionRange(length, length);

+}

+

+Array.prototype.remove = function(value, onlyFirst)

+{

+    if (onlyFirst) {

+        var index = this.indexOf(value);

+        if (index !== -1)

+            this.splice(index, 1);

+        return;

+    }

+

+    var length = this.length;

+    for (var i = 0; i < length; ++i) {

+        if (this[i] === value)

+            this.splice(i, 1);

+    }

+}

+

+Array.prototype.keySet = function()

+{

+    var keys = {};

+    for (var i = 0; i < this.length; ++i)

+        keys[this[i]] = true;

+    return keys;

+}

+

+function insertionIndexForObjectInListSortedByFunction(anObject, aList, aFunction)

+{

+    // indexOf returns (-lowerBound - 1). Taking (-result - 1) works out to lowerBound.

+    return (-indexOfObjectInListSortedByFunction(anObject, aList, aFunction) - 1);

+}

+

+function indexOfObjectInListSortedByFunction(anObject, aList, aFunction)

+{

+    var first = 0;

+    var last = aList.length - 1;

+    var floor = Math.floor;

+    var mid, c;

+

+    while (first <= last) {

+        mid = floor((first + last) / 2);

+        c = aFunction(anObject, aList[mid]);

+

+        if (c > 0)

+            first = mid + 1;

+        else if (c < 0)

+            last = mid - 1;

+        else {

+            // Return the first occurance of an item in the list.

+            while (mid > 0 && aFunction(anObject, aList[mid - 1]) === 0)

+                mid--;

+            first = mid;

+            break;

+        }

+    }

+

+    // By returning 1 less than the negative lower search bound, we can reuse this function

+    // for both indexOf and insertionIndexFor, with some simple arithmetic.

+    return (-first - 1);

+}

+

+String.sprintf = function(format)

+{

+    return String.vsprintf(format, Array.prototype.slice.call(arguments, 1));

+}

+

+String.tokenizeFormatString = function(format)

+{

+    var tokens = [];

+    var substitutionIndex = 0;

+

+    function addStringToken(str)

+    {

+        tokens.push({ type: "string", value: str });

+    }

+

+    function addSpecifierToken(specifier, precision, substitutionIndex)

+    {

+        tokens.push({ type: "specifier", specifier: specifier, precision: precision, substitutionIndex: substitutionIndex });

+    }

+

+    var index = 0;

+    for (var precentIndex = format.indexOf("%", index); precentIndex !== -1; precentIndex = format.indexOf("%", index)) {

+        addStringToken(format.substring(index, precentIndex));

+        index = precentIndex + 1;

+

+        if (format[index] === "%") {

+            addStringToken("%");

+            ++index;

+            continue;

+        }

+

+        if (!isNaN(format[index])) {

+            // The first character is a number, it might be a substitution index.

+            var number = parseInt(format.substring(index));

+            while (!isNaN(format[index]))

+                ++index;

+            // If the number is greater than zero and ends with a "$",

+            // then this is a substitution index.

+            if (number > 0 && format[index] === "$") {

+                substitutionIndex = (number - 1);

+                ++index;

+            }

+        }

+

+        var precision = -1;

+        if (format[index] === ".") {

+            // This is a precision specifier. If no digit follows the ".",

+            // then the precision should be zero.

+            ++index;

+            precision = parseInt(format.substring(index));

+            if (isNaN(precision))

+                precision = 0;

+            while (!isNaN(format[index]))

+                ++index;

+        }

+

+        addSpecifierToken(format[index], precision, substitutionIndex);

+

+        ++substitutionIndex;

+        ++index;

+    }

+

+    addStringToken(format.substring(index));

+

+    return tokens;

+}

+

+String.standardFormatters = {

+    d: function(substitution)

+    {

+        if (typeof substitution == "object" && Object.proxyType(substitution) === "number")

+            substitution = substitution.description;

+        substitution = parseInt(substitution);

+        return !isNaN(substitution) ? substitution : 0;

+    },

+

+    f: function(substitution, token)

+    {

+        if (typeof substitution == "object" && Object.proxyType(substitution) === "number")

+            substitution = substitution.description;

+        substitution = parseFloat(substitution);

+        if (substitution && token.precision > -1)

+            substitution = substitution.toFixed(token.precision);

+        return !isNaN(substitution) ? substitution : (token.precision > -1 ? Number(0).toFixed(token.precision) : 0);

+    },

+

+    s: function(substitution)

+    {

+        if (typeof substitution == "object" && Object.proxyType(substitution) !== "null")

+            substitution = substitution.description;

+        return substitution;

+    },

+};

+

+String.vsprintf = function(format, substitutions)

+{

+    return String.format(format, substitutions, String.standardFormatters, "", function(a, b) { return a + b; }).formattedResult;

+}

+

+String.format = function(format, substitutions, formatters, initialValue, append)

+{

+    if (!format || !substitutions || !substitutions.length)

+        return { formattedResult: append(initialValue, format), unusedSubstitutions: substitutions };

+

+    function prettyFunctionName()

+    {

+        return "String.format(\"" + format + "\", \"" + substitutions.join("\", \"") + "\")";

+    }

+

+    function warn(msg)

+    {

+        console.warn(prettyFunctionName() + ": " + msg);

+    }

+

+    function error(msg)

+    {

+        console.error(prettyFunctionName() + ": " + msg);

+    }

+

+    var result = initialValue;

+    var tokens = String.tokenizeFormatString(format);

+    var usedSubstitutionIndexes = {};

+

+    for (var i = 0; i < tokens.length; ++i) {

+        var token = tokens[i];

+

+        if (token.type === "string") {

+            result = append(result, token.value);

+            continue;

+        }

+

+        if (token.type !== "specifier") {

+            error("Unknown token type \"" + token.type + "\" found.");

+            continue;

+        }

+

+        if (token.substitutionIndex >= substitutions.length) {

+            // If there are not enough substitutions for the current substitutionIndex

+            // just output the format specifier literally and move on.

+            error("not enough substitution arguments. Had " + substitutions.length + " but needed " + (token.substitutionIndex + 1) + ", so substitution was skipped.");

+            result = append(result, "%" + (token.precision > -1 ? token.precision : "") + token.specifier);

+            continue;

+        }

+

+        usedSubstitutionIndexes[token.substitutionIndex] = true;

+

+        if (!(token.specifier in formatters)) {

+            // Encountered an unsupported format character, treat as a string.

+            warn("unsupported format character \u201C" + token.specifier + "\u201D. Treating as a string.");

+            result = append(result, substitutions[token.substitutionIndex]);

+            continue;

+        }

+

+        result = append(result, formatters[token.specifier](substitutions[token.substitutionIndex], token));

+    }

+

+    var unusedSubstitutions = [];

+    for (var i = 0; i < substitutions.length; ++i) {

+        if (i in usedSubstitutionIndexes)

+            continue;

+        unusedSubstitutions.push(substitutions[i]);

+    }

+

+    return { formattedResult: result, unusedSubstitutions: unusedSubstitutions };

+}

+

+function isEnterKey(event) {

+    // Check if in IME.

+    return event.keyCode !== 229 && event.keyIdentifier === "Enter";

+}

+

+

+function highlightSearchResult(element, offset, length)

+{

+    var lineText = element.textContent;

+    var endOffset = offset + length;

+    var highlightNode = document.createElement("span");

+    highlightNode.className = "webkit-search-result";

+    highlightNode.textContent = lineText.substring(offset, endOffset);

+

+    var boundary = element.rangeBoundaryForOffset(offset);

+    var textNode = boundary.container;

+    var text = textNode.textContent;

+

+    if (boundary.offset + length < text.length) {

+        // Selection belong to a single split mode.

+        textNode.textContent = text.substring(boundary.offset + length);

+        textNode.parentElement.insertBefore(highlightNode, textNode);

+        var prefixNode = document.createTextNode(text.substring(0, boundary.offset));

+        textNode.parentElement.insertBefore(prefixNode, highlightNode);

+        return highlightNode;

+    }

+

+    var parentElement = textNode.parentElement;

+    var anchorElement = textNode.nextSibling;

+

+    length -= text.length - boundary.offset;

+    textNode.textContent = text.substring(0, boundary.offset);

+    textNode = textNode.traverseNextTextNode(element);

+

+    while (textNode) {

+        var text = textNode.textContent;

+        if (length < text.length) {

+            textNode.textContent = text.substring(length);

+            break;

+        }

+

+        length -= text.length;

+        textNode.textContent = "";

+        textNode = textNode.traverseNextTextNode(element);

+    }

+

+    parentElement.insertBefore(highlightNode, anchorElement);

+    return highlightNode;

+}

+

+function createSearchRegex(query)

+{

+    var regex = "";

+    for (var i = 0; i < query.length; ++i) {

+        var char = query.charAt(i);

+        if (char === "]")

+            char = "\\]";

+        regex += "[" + char + "]";

+    }

+    return new RegExp(regex, "i");

+}

+

+/* treeoutline.js */

+

+/*

+ * Copyright (C) 2007 Apple Inc.  All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without

+ * modification, are permitted provided that the following conditions

+ * are met:

+ *

+ * 1.  Redistributions of source code must retain the above copyright

+ *     notice, this list of conditions and the following disclaimer. 

+ * 2.  Redistributions in binary form must reproduce the above copyright

+ *     notice, this list of conditions and the following disclaimer in the

+ *     documentation and/or other materials provided with the distribution. 

+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of

+ *     its contributors may be used to endorse or promote products derived

+ *     from this software without specific prior written permission. 

+ *

+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY

+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED

+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE

+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY

+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES

+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND

+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ */

+

+function TreeOutline(listNode)

+{

+    this.children = [];

+    this.selectedTreeElement = null;

+    this._childrenListNode = listNode;

+    this._childrenListNode.removeChildren();

+    this._knownTreeElements = [];

+    this._treeElementsExpandedState = [];

+    this.expandTreeElementsWhenArrowing = false;

+    this.root = true;

+    this.hasChildren = false;

+    this.expanded = true;

+    this.selected = false;

+    this.treeOutline = this;

+

+    this._childrenListNode.tabIndex = 0;

+    this._childrenListNode.addEventListener("keydown", this._treeKeyDown.bind(this), true);

+}

+

+TreeOutline._knownTreeElementNextIdentifier = 1;

+

+TreeOutline._appendChild = function(child)

+{

+    if (!child)

+        throw("child can't be undefined or null");

+

+    var lastChild = this.children[this.children.length - 1];

+    if (lastChild) {

+        lastChild.nextSibling = child;

+        child.previousSibling = lastChild;

+    } else {

+        child.previousSibling = null;

+        child.nextSibling = null;

+    }

+

+    this.children.push(child);

+    this.hasChildren = true;

+    child.parent = this;

+    child.treeOutline = this.treeOutline;

+    child.treeOutline._rememberTreeElement(child);

+

+    var current = child.children[0];

+    while (current) {

+        current.treeOutline = this.treeOutline;

+        current.treeOutline._rememberTreeElement(current);

+        current = current.traverseNextTreeElement(false, child, true);

+    }

+

+    if (child.hasChildren && child.treeOutline._treeElementsExpandedState[child.identifier] !== undefined)

+        child.expanded = child.treeOutline._treeElementsExpandedState[child.identifier];

+

+    if (!this._childrenListNode) {

+        this._childrenListNode = this.treeOutline._childrenListNode.ownerDocument.createElement("ol");

+        this._childrenListNode.parentTreeElement = this;

+        this._childrenListNode.addStyleClass("children");

+        if (this.hidden)

+            this._childrenListNode.addStyleClass("hidden");

+    }

+

+    child._attach();

+}

+

+TreeOutline._insertChild = function(child, index)

+{

+    if (!child)

+        throw("child can't be undefined or null");

+

+    var previousChild = (index > 0 ? this.children[index - 1] : null);

+    if (previousChild) {

+        previousChild.nextSibling = child;

+        child.previousSibling = previousChild;

+    } else {

+        child.previousSibling = null;

+    }

+

+    var nextChild = this.children[index];

+    if (nextChild) {

+        nextChild.previousSibling = child;

+        child.nextSibling = nextChild;

+    } else {

+        child.nextSibling = null;

+    }

+

+    this.children.splice(index, 0, child);

+    this.hasChildren = true;

+    child.parent = this;

+    child.treeOutline = this.treeOutline;

+    child.treeOutline._rememberTreeElement(child);

+

+    var current = child.children[0];

+    while (current) {

+        current.treeOutline = this.treeOutline;

+        current.treeOutline._rememberTreeElement(current);

+        current = current.traverseNextTreeElement(false, child, true);

+    }

+

+    if (child.hasChildren && child.treeOutline._treeElementsExpandedState[child.identifier] !== undefined)

+        child.expanded = child.treeOutline._treeElementsExpandedState[child.identifier];

+

+    if (!this._childrenListNode) {

+        this._childrenListNode = this.treeOutline._childrenListNode.ownerDocument.createElement("ol");

+        this._childrenListNode.parentTreeElement = this;

+        this._childrenListNode.addStyleClass("children");

+        if (this.hidden)

+            this._childrenListNode.addStyleClass("hidden");

+    }

+

+    child._attach();

+}

+

+TreeOutline._removeChildAtIndex = function(childIndex)

+{

+    if (childIndex < 0 || childIndex >= this.children.length)

+        throw("childIndex out of range");

+

+    var child = this.children[childIndex];

+    this.children.splice(childIndex, 1);

+

+    var parent = child.parent;

+    if (child.deselect()) {

+        if (child.previousSibling)

+            child.previousSibling.select();

+        else if (child.nextSibling)

+            child.nextSibling.select();

+        else

+            parent.select();

+    }

+

+    if (child.previousSibling)

+        child.previousSibling.nextSibling = child.nextSibling;

+    if (child.nextSibling)

+        child.nextSibling.previousSibling = child.previousSibling;

+

+    if (child.treeOutline) {

+        child.treeOutline._forgetTreeElement(child);

+        child.treeOutline._forgetChildrenRecursive(child);

+    }

+

+    child._detach();

+    child.treeOutline = null;

+    child.parent = null;

+    child.nextSibling = null;

+    child.previousSibling = null;

+}

+

+TreeOutline._removeChild = function(child)

+{

+    if (!child)

+        throw("child can't be undefined or null");

+

+    var childIndex = this.children.indexOf(child);

+    if (childIndex === -1)

+        throw("child not found in this node's children");

+

+    TreeOutline._removeChildAtIndex.call(this, childIndex);

+}

+

+TreeOutline._removeChildren = function()

+{

+    for (var i = 0; i < this.children.length; ++i) {

+        var child = this.children[i];

+        child.deselect();

+

+        if (child.treeOutline) {

+            child.treeOutline._forgetTreeElement(child);

+            child.treeOutline._forgetChildrenRecursive(child);

+        }

+

+        child._detach();

+        child.treeOutline = null;

+        child.parent = null;

+        child.nextSibling = null;

+        child.previousSibling = null;

+    }

+

+    this.children = [];

+}

+

+TreeOutline._removeChildrenRecursive = function()

+{

+    var childrenToRemove = this.children;

+

+    var child = this.children[0];

+    while (child) {

+        if (child.children.length)

+            childrenToRemove = childrenToRemove.concat(child.children);

+        child = child.traverseNextTreeElement(false, this, true);

+    }

+

+    for (var i = 0; i < childrenToRemove.length; ++i) {

+        var child = childrenToRemove[i];

+        child.deselect();

+        if (child.treeOutline)

+            child.treeOutline._forgetTreeElement(child);

+        child._detach();

+        child.children = [];

+        child.treeOutline = null;

+        child.parent = null;

+        child.nextSibling = null;

+        child.previousSibling = null;

+    }

+

+    this.children = [];

+}

+

+TreeOutline.prototype._rememberTreeElement = function(element)

+{

+    if (!this._knownTreeElements[element.identifier])

+        this._knownTreeElements[element.identifier] = [];

+

+    // check if the element is already known

+    var elements = this._knownTreeElements[element.identifier];

+    if (elements.indexOf(element) !== -1)

+        return;

+

+    // add the element

+    elements.push(element);

+}

+

+TreeOutline.prototype._forgetTreeElement = function(element)

+{

+    if (this._knownTreeElements[element.identifier])

+        this._knownTreeElements[element.identifier].remove(element, true);

+}

+

+TreeOutline.prototype._forgetChildrenRecursive = function(parentElement)

+{

+    var child = parentElement.children[0];

+    while (child) {

+        this._forgetTreeElement(child);

+        child = child.traverseNextTreeElement(false, this, true);

+    }

+}

+

+TreeOutline.prototype.getCachedTreeElement = function(representedObject)

+{

+    if (!representedObject)

+        return null;

+

+    if ("__treeElementIdentifier" in representedObject) {

+        // If this representedObject has a tree element identifier, and it is a known TreeElement

+        // in our tree we can just return that tree element.

+        var elements = this._knownTreeElements[representedObject.__treeElementIdentifier];

+        if (elements) {

+            for (var i = 0; i < elements.length; ++i)

+                if (elements[i].representedObject === representedObject)

+                    return elements[i];

+        }

+    }

+    return null;

+}

+

+TreeOutline.prototype.findTreeElement = function(representedObject, isAncestor, getParent)

+{

+    if (!representedObject)

+        return null;

+

+    var cachedElement = this.getCachedTreeElement(representedObject);

+    if (cachedElement)

+        return cachedElement;

+

+    // The representedObject isn't know, so we start at the top of the tree and work down to find the first

+    // tree element that represents representedObject or one of its ancestors.

+    var item;

+    var found = false;

+    for (var i = 0; i < this.children.length; ++i) {

+        item = this.children[i];

+        if (item.representedObject === representedObject || isAncestor(item.representedObject, representedObject)) {

+            found = true;

+            break;

+        }

+    }

+

+    if (!found)

+        return null;

+

+    // Make sure the item that we found is connected to the root of the tree.

+    // Build up a list of representedObject's ancestors that aren't already in our tree.

+    var ancestors = [];

+    var currentObject = representedObject;

+    while (currentObject) {

+        ancestors.unshift(currentObject);

+        if (currentObject === item.representedObject)

+            break;

+        currentObject = getParent(currentObject);

+    }

+

+    // For each of those ancestors we populate them to fill in the tree.

+    for (var i = 0; i < ancestors.length; ++i) {

+        // Make sure we don't call findTreeElement with the same representedObject

+        // again, to prevent infinite recursion.

+        if (ancestors[i] === representedObject)

+            continue;

+        // FIXME: we could do something faster than findTreeElement since we will know the next

+        // ancestor exists in the tree.

+        item = this.findTreeElement(ancestors[i], isAncestor, getParent);

+        if (item && item.onpopulate)

+            item.onpopulate(item);

+    }

+

+    return this.getCachedTreeElement(representedObject);

+}

+

+TreeOutline.prototype.treeElementFromPoint = function(x, y)

+{

+    var node = this._childrenListNode.ownerDocument.elementFromPoint(x, y);

+    var listNode = node.enclosingNodeOrSelfWithNodeNameInArray(["ol", "li"]);

+    if (listNode)

+        return listNode.parentTreeElement || listNode.treeElement;

+    return null;

+}

+

+TreeOutline.prototype._treeKeyDown = function(event)

+{

+    if (event.target !== this._childrenListNode)

+        return;

+

+    if (!this.selectedTreeElement || event.shiftKey || event.metaKey || event.ctrlKey)

+        return;

+

+    var handled = false;

+    var nextSelectedElement;

+    if (event.keyIdentifier === "Up" && !event.altKey) {

+        nextSelectedElement = this.selectedTreeElement.traversePreviousTreeElement(true);

+        while (nextSelectedElement && !nextSelectedElement.selectable)

+            nextSelectedElement = nextSelectedElement.traversePreviousTreeElement(!this.expandTreeElementsWhenArrowing);

+        handled = nextSelectedElement ? true : false;

+    } else if (event.keyIdentifier === "Down" && !event.altKey) {

+        nextSelectedElement = this.selectedTreeElement.traverseNextTreeElement(true);

+        while (nextSelectedElement && !nextSelectedElement.selectable)

+            nextSelectedElement = nextSelectedElement.traverseNextTreeElement(!this.expandTreeElementsWhenArrowing);

+        handled = nextSelectedElement ? true : false;

+    } else if (event.keyIdentifier === "Left") {

+        if (this.selectedTreeElement.expanded) {

+            if (event.altKey)

+                this.selectedTreeElement.collapseRecursively();

+            else

+                this.selectedTreeElement.collapse();

+            handled = true;

+        } else if (this.selectedTreeElement.parent && !this.selectedTreeElement.parent.root) {

+            handled = true;

+            if (this.selectedTreeElement.parent.selectable) {

+                nextSelectedElement = this.selectedTreeElement.parent;

+                handled = nextSelectedElement ? true : false;

+            } else if (this.selectedTreeElement.parent)

+                this.selectedTreeElement.parent.collapse();

+        }

+    } else if (event.keyIdentifier === "Right") {

+        if (!this.selectedTreeElement.revealed()) {

+            this.selectedTreeElement.reveal();

+            handled = true;

+        } else if (this.selectedTreeElement.hasChildren) {

+            handled = true;

+            if (this.selectedTreeElement.expanded) {

+                nextSelectedElement = this.selectedTreeElement.children[0];

+                handled = nextSelectedElement ? true : false;

+            } else {

+                if (event.altKey)

+                    this.selectedTreeElement.expandRecursively();

+                else

+                    this.selectedTreeElement.expand();

+            }

+        }

+    }

+

+    if (nextSelectedElement) {

+        nextSelectedElement.reveal();

+        nextSelectedElement.select();

+    }

+

+    if (handled) {

+        event.preventDefault();

+        event.stopPropagation();

+    }

+}

+

+TreeOutline.prototype.expand = function()

+{

+    // this is the root, do nothing

+}

+

+TreeOutline.prototype.collapse = function()

+{

+    // this is the root, do nothing

+}

+

+TreeOutline.prototype.revealed = function()

+{

+    return true;

+}

+

+TreeOutline.prototype.reveal = function()

+{

+    // this is the root, do nothing

+}

+

+TreeOutline.prototype.appendChild = TreeOutline._appendChild;

+TreeOutline.prototype.insertChild = TreeOutline._insertChild;

+TreeOutline.prototype.removeChild = TreeOutline._removeChild;

+TreeOutline.prototype.removeChildAtIndex = TreeOutline._removeChildAtIndex;

+TreeOutline.prototype.removeChildren = TreeOutline._removeChildren;

+TreeOutline.prototype.removeChildrenRecursive = TreeOutline._removeChildrenRecursive;

+

+function TreeElement(title, representedObject, hasChildren)

+{

+    this._title = title;

+    this.representedObject = (representedObject || {});

+

+    if (this.representedObject.__treeElementIdentifier)

+        this.identifier = this.representedObject.__treeElementIdentifier;

+    else {

+        this.identifier = TreeOutline._knownTreeElementNextIdentifier++;

+        this.representedObject.__treeElementIdentifier = this.identifier;

+    }

+

+    this._hidden = false;

+    this.expanded = false;

+    this.selected = false;

+    this.hasChildren = hasChildren;

+    this.children = [];

+    this.treeOutline = null;

+    this.parent = null;

+    this.previousSibling = null;

+    this.nextSibling = null;

+    this._listItemNode = null;

+}

+

+TreeElement.prototype = {

+    selectable: true,

+    arrowToggleWidth: 10,

+

+    get listItemElement() {

+        return this._listItemNode;

+    },

+

+    get childrenListElement() {

+        return this._childrenListNode;

+    },

+

+    get title() {

+        return this._title;

+    },

+

+    set title(x) {

+        this._title = x;

+        if (this._listItemNode)

+            this._listItemNode.innerHTML = x;

+    },

+

+    get tooltip() {

+        return this._tooltip;

+    },

+

+    set tooltip(x) {

+        this._tooltip = x;

+        if (this._listItemNode)

+            this._listItemNode.title = x ? x : "";

+    },

+

+    get hasChildren() {

+        return this._hasChildren;

+    },

+

+    set hasChildren(x) {

+        if (this._hasChildren === x)

+            return;

+

+        this._hasChildren = x;

+

+        if (!this._listItemNode)

+            return;

+

+        if (x)

+            this._listItemNode.addStyleClass("parent");

+        else {

+            this._listItemNode.removeStyleClass("parent");

+            this.collapse();

+        }

+    },

+

+    get hidden() {

+        return this._hidden;

+    },

+

+    set hidden(x) {

+        if (this._hidden === x)

+            return;

+

+        this._hidden = x;

+

+        if (x) {

+            if (this._listItemNode)

+                this._listItemNode.addStyleClass("hidden");

+            if (this._childrenListNode)

+                this._childrenListNode.addStyleClass("hidden");

+        } else {

+            if (this._listItemNode)

+                this._listItemNode.removeStyleClass("hidden");

+            if (this._childrenListNode)

+                this._childrenListNode.removeStyleClass("hidden");

+        }

+    },

+

+    get shouldRefreshChildren() {

+        return this._shouldRefreshChildren;

+    },

+

+    set shouldRefreshChildren(x) {

+        this._shouldRefreshChildren = x;

+        if (x && this.expanded)

+            this.expand();

+    }

+}

+

+TreeElement.prototype.appendChild = TreeOutline._appendChild;

+TreeElement.prototype.insertChild = TreeOutline._insertChild;

+TreeElement.prototype.removeChild = TreeOutline._removeChild;

+TreeElement.prototype.removeChildAtIndex = TreeOutline._removeChildAtIndex;

+TreeElement.prototype.removeChildren = TreeOutline._removeChildren;

+TreeElement.prototype.removeChildrenRecursive = TreeOutline._removeChildrenRecursive;

+

+TreeElement.prototype._attach = function()

+{

+    if (!this._listItemNode || this.parent._shouldRefreshChildren) {

+        if (this._listItemNode && this._listItemNode.parentNode)

+            this._listItemNode.parentNode.removeChild(this._listItemNode);

+

+        this._listItemNode = this.treeOutline._childrenListNode.ownerDocument.createElement("li");

+        this._listItemNode.treeElement = this;

+        this._listItemNode.innerHTML = this._title;

+        this._listItemNode.title = this._tooltip ? this._tooltip : "";

+

+        if (this.hidden)

+            this._listItemNode.addStyleClass("hidden");

+        if (this.hasChildren)

+            this._listItemNode.addStyleClass("parent");

+        if (this.expanded)

+            this._listItemNode.addStyleClass("expanded");

+        if (this.selected)

+            this._listItemNode.addStyleClass("selected");

+

+        this._listItemNode.addEventListener("mousedown", TreeElement.treeElementSelected, false);

+        this._listItemNode.addEventListener("click", TreeElement.treeElementToggled, false);

+        this._listItemNode.addEventListener("dblclick", TreeElement.treeElementDoubleClicked, false);

+

+        if (this.onattach)

+            this.onattach(this);

+    }

+

+    var nextSibling = null;

+    if (this.nextSibling && this.nextSibling._listItemNode && this.nextSibling._listItemNode.parentNode === this.parent._childrenListNode)

+        nextSibling = this.nextSibling._listItemNode;

+    this.parent._childrenListNode.insertBefore(this._listItemNode, nextSibling);

+    if (this._childrenListNode)

+        this.parent._childrenListNode.insertBefore(this._childrenListNode, this._listItemNode.nextSibling);

+    if (this.selected)

+        this.select();

+    if (this.expanded)

+        this.expand();

+}

+

+TreeElement.prototype._detach = function()

+{

+    if (this._listItemNode && this._listItemNode.parentNode)

+        this._listItemNode.parentNode.removeChild(this._listItemNode);

+    if (this._childrenListNode && this._childrenListNode.parentNode)

+        this._childrenListNode.parentNode.removeChild(this._childrenListNode);

+}

+

+TreeElement.treeElementSelected = function(event)

+{

+    var element = event.currentTarget;

+    if (!element || !element.treeElement || !element.treeElement.selectable)

+        return;

+

+    if (element.treeElement.isEventWithinDisclosureTriangle(event))

+        return;

+

+    element.treeElement.select();

+}

+

+TreeElement.treeElementToggled = function(event)

+{

+    var element = event.currentTarget;

+    if (!element || !element.treeElement)

+        return;

+

+    if (!element.treeElement.isEventWithinDisclosureTriangle(event))

+        return;

+

+    if (element.treeElement.expanded) {

+        if (event.altKey)

+            element.treeElement.collapseRecursively();

+        else

+            element.treeElement.collapse();

+    } else {

+        if (event.altKey)

+            element.treeElement.expandRecursively();

+        else

+            element.treeElement.expand();

+    }

+}

+

+TreeElement.treeElementDoubleClicked = function(event)

+{

+    var element = event.currentTarget;

+    if (!element || !element.treeElement)

+        return;

+

+    if (element.treeElement.ondblclick)

+        element.treeElement.ondblclick.call(element.treeElement, event);

+    else if (element.treeElement.hasChildren && !element.treeElement.expanded)

+        element.treeElement.expand();

+}

+

+TreeElement.prototype.collapse = function()

+{

+    if (this._listItemNode)

+        this._listItemNode.removeStyleClass("expanded");

+    if (this._childrenListNode)

+        this._childrenListNode.removeStyleClass("expanded");

+

+    this.expanded = false;

+    if (this.treeOutline)

+        this.treeOutline._treeElementsExpandedState[this.identifier] = true;

+

+    if (this.oncollapse)

+        this.oncollapse(this);

+}

+

+TreeElement.prototype.collapseRecursively = function()

+{

+    var item = this;

+    while (item) {

+        if (item.expanded)

+            item.collapse();

+        item = item.traverseNextTreeElement(false, this, true);

+    }

+}

+

+TreeElement.prototype.expand = function()

+{

+    if (!this.hasChildren || (this.expanded && !this._shouldRefreshChildren && this._childrenListNode))

+        return;

+

+    if (this.treeOutline && (!this._childrenListNode || this._shouldRefreshChildren)) {

+        if (this._childrenListNode && this._childrenListNode.parentNode)

+            this._childrenListNode.parentNode.removeChild(this._childrenListNode);

+

+        this._childrenListNode = this.treeOutline._childrenListNode.ownerDocument.createElement("ol");

+        this._childrenListNode.parentTreeElement = this;

+        this._childrenListNode.addStyleClass("children");

+

+        if (this.hidden)

+            this._childrenListNode.addStyleClass("hidden");

+

+        if (this.onpopulate)

+            this.onpopulate(this);

+

+        for (var i = 0; i < this.children.length; ++i)

+            this.children[i]._attach();

+

+        delete this._shouldRefreshChildren;

+    }

+

+    if (this._listItemNode) {

+        this._listItemNode.addStyleClass("expanded");

+        if (this._childrenListNode && this._childrenListNode.parentNode != this._listItemNode.parentNode)

+            this.parent._childrenListNode.insertBefore(this._childrenListNode, this._listItemNode.nextSibling);

+    }

+

+    if (this._childrenListNode)

+        this._childrenListNode.addStyleClass("expanded");

+

+    this.expanded = true;

+    if (this.treeOutline)

+        this.treeOutline._treeElementsExpandedState[this.identifier] = true;

+

+    if (this.onexpand)

+        this.onexpand(this);

+}

+

+TreeElement.prototype.expandRecursively = function(maxDepth)

+{

+    var item = this;

+    var info = {};

+    var depth = 0;

+

+    // The Inspector uses TreeOutlines to represents object properties, so recursive expansion

+    // in some case can be infinite, since JavaScript objects can hold circular references.

+    // So default to a recursion cap of 3 levels, since that gives fairly good results.

+    if (typeof maxDepth === "undefined" || typeof maxDepth === "null")

+        maxDepth = 3;

+

+    while (item) {

+        if (depth < maxDepth)

+            item.expand();

+        item = item.traverseNextTreeElement(false, this, (depth >= maxDepth), info);

+        depth += info.depthChange;

+    }

+}

+

+TreeElement.prototype.hasAncestor = function(ancestor) {

+    if (!ancestor)

+        return false;

+

+    var currentNode = this.parent;

+    while (currentNode) {

+        if (ancestor === currentNode)

+            return true;

+        currentNode = currentNode.parent;

+    }

+

+    return false;

+}

+

+TreeElement.prototype.reveal = function()

+{

+    var currentAncestor = this.parent;

+    while (currentAncestor && !currentAncestor.root) {

+        if (!currentAncestor.expanded)

+            currentAncestor.expand();

+        currentAncestor = currentAncestor.parent;

+    }

+

+    if (this.onreveal)

+        this.onreveal(this);

+}

+

+TreeElement.prototype.revealed = function()

+{

+    var currentAncestor = this.parent;

+    while (currentAncestor && !currentAncestor.root) {

+        if (!currentAncestor.expanded)

+            return false;

+        currentAncestor = currentAncestor.parent;

+    }

+

+    return true;

+}

+

+TreeElement.prototype.select = function(supressOnSelect)

+{

+    if (!this.treeOutline || !this.selectable || this.selected)

+        return;

+

+    if (this.treeOutline.selectedTreeElement)

+        this.treeOutline.selectedTreeElement.deselect();

+

+    this.selected = true;

+    this.treeOutline._childrenListNode.focus();

+    this.treeOutline.selectedTreeElement = this;

+    if (this._listItemNode)

+        this._listItemNode.addStyleClass("selected");

+

+    if (this.onselect && !supressOnSelect)

+        this.onselect(this);

+}

+

+TreeElement.prototype.deselect = function(supressOnDeselect)

+{

+    if (!this.treeOutline || this.treeOutline.selectedTreeElement !== this || !this.selected)

+        return false;

+

+    this.selected = false;

+    this.treeOutline.selectedTreeElement = null;

+    if (this._listItemNode)

+        this._listItemNode.removeStyleClass("selected");

+

+    if (this.ondeselect && !supressOnDeselect)

+        this.ondeselect(this);

+    return true;

+}

+

+TreeElement.prototype.traverseNextTreeElement = function(skipHidden, stayWithin, dontPopulate, info)

+{

+    if (!dontPopulate && this.hasChildren && this.onpopulate)

+        this.onpopulate(this);

+

+    if (info)

+        info.depthChange = 0;

+

+    var element = skipHidden ? (this.revealed() ? this.children[0] : null) : this.children[0];

+    if (element && (!skipHidden || (skipHidden && this.expanded))) {

+        if (info)

+            info.depthChange = 1;

+        return element;

+    }

+

+    if (this === stayWithin)

+        return null;

+

+    element = skipHidden ? (this.revealed() ? this.nextSibling : null) : this.nextSibling;

+    if (element)

+        return element;

+

+    element = this;

+    while (element && !element.root && !(skipHidden ? (element.revealed() ? element.nextSibling : null) : element.nextSibling) && element.parent !== stayWithin) {

+        if (info)

+            info.depthChange -= 1;

+        element = element.parent;

+    }

+

+    if (!element)

+        return null;

+

+    return (skipHidden ? (element.revealed() ? element.nextSibling : null) : element.nextSibling);

+}

+

+TreeElement.prototype.traversePreviousTreeElement = function(skipHidden, dontPopulate)

+{

+    var element = skipHidden ? (this.revealed() ? this.previousSibling : null) : this.previousSibling;

+    if (!dontPopulate && element && element.hasChildren && element.onpopulate)

+        element.onpopulate(element);

+

+    while (element && (skipHidden ? (element.revealed() && element.expanded ? element.children[element.children.length - 1] : null) : element.children[element.children.length - 1])) {

+        if (!dontPopulate && element.hasChildren && element.onpopulate)

+            element.onpopulate(element);

+        element = (skipHidden ? (element.revealed() && element.expanded ? element.children[element.children.length - 1] : null) : element.children[element.children.length - 1]);

+    }

+

+    if (element)

+        return element;

+

+    if (!this.parent || this.parent.root)

+        return null;

+

+    return this.parent;

+}

+

+TreeElement.prototype.isEventWithinDisclosureTriangle = function(event)

+{

+    var left = this._listItemNode.totalOffsetLeft;

+    return event.pageX >= left && event.pageX <= left + this.arrowToggleWidth && this.hasChildren;

+}

+

+/* inspector.js */

+

+/*

+ * Copyright (C) 2006, 2007, 2008 Apple Inc.  All rights reserved.

+ * Copyright (C) 2007 Matt Lilek (pewtermoose@gmail.com).

+ * Copyright (C) 2009 Joseph Pecoraro

+ *

+ * Redistribution and use in source and binary forms, with or without

+ * modification, are permitted provided that the following conditions

+ * are met:

+ *

+ * 1.  Redistributions of source code must retain the above copyright

+ *     notice, this list of conditions and the following disclaimer.

+ * 2.  Redistributions in binary form must reproduce the above copyright

+ *     notice, this list of conditions and the following disclaimer in the

+ *     documentation and/or other materials provided with the distribution.

+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of

+ *     its contributors may be used to endorse or promote products derived

+ *     from this software without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY

+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED

+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE

+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY

+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES

+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;

+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND

+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF

+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ */

+

+function preloadImages()

+{

+    (new Image()).src = "Images/clearConsoleButtonGlyph.png";

+    (new Image()).src = "Images/consoleButtonGlyph.png";

+    (new Image()).src = "Images/dockButtonGlyph.png";

+    (new Image()).src = "Images/enableOutlineButtonGlyph.png";

+    (new Image()).src = "Images/enableSolidButtonGlyph.png";

+    (new Image()).src = "Images/excludeButtonGlyph.png";

+    (new Image()).src = "Images/focusButtonGlyph.png";

+    (new Image()).src = "Images/largerResourcesButtonGlyph.png";

+    (new Image()).src = "Images/nodeSearchButtonGlyph.png";

+    (new Image()).src = "Images/pauseOnExceptionButtonGlyph.png";

+    (new Image()).src = "Images/percentButtonGlyph.png";

+    (new Image()).src = "Images/recordButtonGlyph.png";

+    (new Image()).src = "Images/recordToggledButtonGlyph.png";

+    (new Image()).src = "Images/reloadButtonGlyph.png";

+    (new Image()).src = "Images/undockButtonGlyph.png";

+}

+

+preloadImages();

+

+var WebInspector = {

+    resources: {},

+    resourceURLMap: {},

+    cookieDomains: {},

+    missingLocalizedStrings: {},

+    pendingDispatches: 0,

+

+    // RegExp groups:

+    // 1 - scheme

+    // 2 - hostname

+    // 3 - ?port

+    // 4 - ?path

+    // 5 - ?fragment

+    URLRegExp: /^(http[s]?|file):\/\/([^\/:]*)(?::([\d]+))?(?:(\/[^#]*)(?:#(.*))?)?$/i,

+    GenericURLRegExp: /^([^:]+):\/\/([^\/:]*)(?::([\d]+))?(?:(\/[^#]*)(?:#(.*))?)?$/i,

+

+    get platform()

+    {

+        if (!("_platform" in this))

+            this._platform = InspectorFrontendHost.platform();

+

+        return this._platform;

+    },

+

+    get platformFlavor()

+    {

+        if (!("_platformFlavor" in this))

+            this._platformFlavor = this._detectPlatformFlavor();

+

+        return this._platformFlavor;

+    },

+

+    _detectPlatformFlavor: function()

+    {

+        const userAgent = navigator.userAgent;

+

+        if (this.platform === "windows") {

+            var match = userAgent.match(/Windows NT (\d+)\.(?:\d+)/);

+            if (match && match[1] >= 6)

+                return WebInspector.PlatformFlavor.WindowsVista;

+            return null;

+        } else if (this.platform === "mac") {

+            var match = userAgent.match(/Mac OS X\s*(?:(\d+)_(\d+))?/);

+            if (!match || match[1] != 10)

+                return WebInspector.PlatformFlavor.MacSnowLeopard;

+            switch (Number(match[2])) {

+                case 4:

+                    return WebInspector.PlatformFlavor.MacTiger;

+                case 5:

+                    return WebInspector.PlatformFlavor.MacLeopard;

+                case 6:

+                default:

+                    return WebInspector.PlatformFlavor.MacSnowLeopard;

+            }

+        }

+

+        return null;

+    },

+

+    get port()

+    {

+        if (!("_port" in this))

+            this._port = InspectorFrontendHost.port();

+

+        return this._port;

+    },

+

+    get previousFocusElement()

+    {

+        return this._previousFocusElement;

+    },

+

+    get currentFocusElement()

+    {

+        return this._currentFocusElement;

+    },

+

+    set currentFocusElement(x)

+    {

+        if (this._currentFocusElement !== x)

+            this._previousFocusElement = this._currentFocusElement;

+        this._currentFocusElement = x;

+

+        if (this._currentFocusElement) {

+            this._currentFocusElement.focus();

+

+            // Make a caret selection inside the new element if there isn't a range selection and

+            // there isn't already a caret selection inside.

+            var selection = window.getSelection();

+            if (selection.isCollapsed && !this._currentFocusElement.isInsertionCaretInside()) {

+                var selectionRange = this._currentFocusElement.ownerDocument.createRange();

+                selectionRange.setStart(this._currentFocusElement, 0);

+                selectionRange.setEnd(this._currentFocusElement, 0);

+

+                selection.removeAllRanges();

+                selection.addRange(selectionRange);

+            }

+        } else if (this._previousFocusElement)

+            this._previousFocusElement.blur();

+    },

+

+    get currentPanel()

+    {

+        return this._currentPanel;

+    },

+

+    set currentPanel(x)

+    {

+        if (this._currentPanel === x)

+            return;

+

+        if (this._currentPanel)

+            this._currentPanel.hide();

+

+        this._currentPanel = x;

+

+        this.updateSearchLabel();

+

+        if (x) {

+            x.show();

+

+            if (this.currentQuery) {

+                if (x.performSearch) {

+                    function performPanelSearch()

+                    {

+                        this.updateSearchMatchesCount();

+

+                        x.currentQuery = this.currentQuery;

+                        x.performSearch(this.currentQuery);

+                    }

+

+                    // Perform the search on a timeout so the panel switches fast.

+                    setTimeout(performPanelSearch.bind(this), 0);

+                } else {

+                    // Update to show Not found for panels that can't be searched.

+                    this.updateSearchMatchesCount();

+                }

+            }

+        }

+

+        for (var panelName in WebInspector.panels) {

+            if (WebInspector.panels[panelName] == x)

+                InspectorBackend.storeLastActivePanel(panelName);

+        }

+    },

+

+    _createPanels: function()

+    {

+        var hiddenPanels = (InspectorFrontendHost.hiddenPanels() || "").split(',');

+        if (hiddenPanels.indexOf("elements") === -1)

+            this.panels.elements = new WebInspector.ElementsPanel();

+        if (hiddenPanels.indexOf("resources") === -1)

+            this.panels.resources = new WebInspector.ResourcesPanel();

+        if (hiddenPanels.indexOf("scripts") === -1)

+            this.panels.scripts = new WebInspector.ScriptsPanel();

+        if (hiddenPanels.indexOf("timeline") === -1)

+            this.panels.timeline = new WebInspector.TimelinePanel();

+        if (hiddenPanels.indexOf("profiles") === -1) {

+            this.panels.profiles = new WebInspector.ProfilesPanel();

+            this.panels.profiles.registerProfileType(new WebInspector.CPUProfileType());

+        }

+        if (hiddenPanels.indexOf("storage") === -1 && hiddenPanels.indexOf("databases") === -1)

+            this.panels.storage = new WebInspector.StoragePanel();

+        if (Preferences.auditsPanelEnabled && hiddenPanels.indexOf("audits") === -1)

+            this.panels.audits = new WebInspector.AuditsPanel();

+        if (hiddenPanels.indexOf("console") === -1)

+            this.panels.console = new WebInspector.ConsolePanel();

+    },

+

+    get attached()

+    {

+        return this._attached;

+    },

+

+    set attached(x)

+    {

+        if (this._attached === x)

+            return;

+

+        this._attached = x;

+

+        this.updateSearchLabel();

+

+        var dockToggleButton = document.getElementById("dock-status-bar-item");

+        var body = document.body;

+

+        if (x) {

+            InspectorFrontendHost.attach();

+            body.removeStyleClass("detached");

+            body.addStyleClass("attached");

+            dockToggleButton.title = WebInspector.UIString("Undock into separate window.");

+        } else {

+            InspectorFrontendHost.detach();

+            body.removeStyleClass("attached");

+            body.addStyleClass("detached");

+            dockToggleButton.title = WebInspector.UIString("Dock to main window.");

+        }

+    },

+

+    get errors()

+    {

+        return this._errors || 0;

+    },

+

+    set errors(x)

+    {

+        x = Math.max(x, 0);

+

+        if (this._errors === x)

+            return;

+        this._errors = x;

+        this._updateErrorAndWarningCounts();

+    },

+

+    get warnings()

+    {

+        return this._warnings || 0;

+    },

+

+    set warnings(x)

+    {

+        x = Math.max(x, 0);

+

+        if (this._warnings === x)

+            return;

+        this._warnings = x;

+        this._updateErrorAndWarningCounts();

+    },

+

+    _updateErrorAndWarningCounts: function()

+    {

+        var errorWarningElement = document.getElementById("error-warning-count");

+        if (!errorWarningElement)

+            return;

+

+        if (!this.errors && !this.warnings) {

+            errorWarningElement.addStyleClass("hidden");

+            return;

+        }

+

+        errorWarningElement.removeStyleClass("hidden");

+

+        errorWarningElement.removeChildren();

+

+        if (this.errors) {

+            var errorElement = document.createElement("span");

+            errorElement.id = "error-count";

+            errorElement.textContent = this.errors;

+            errorWarningElement.appendChild(errorElement);

+        }

+

+        if (this.warnings) {

+            var warningsElement = document.createElement("span");

+            warningsElement.id = "warning-count";

+            warningsElement.textContent = this.warnings;

+            errorWarningElement.appendChild(warningsElement);

+        }

+

+        if (this.errors) {

+            if (this.warnings) {

+                if (this.errors == 1) {

+                    if (this.warnings == 1)

+                        errorWarningElement.title = WebInspector.UIString("%d error, %d warning", this.errors, this.warnings);

+                    else

+                        errorWarningElement.title = WebInspector.UIString("%d error, %d warnings", this.errors, this.warnings);

+                } else if (this.warnings == 1)

+                    errorWarningElement.title = WebInspector.UIString("%d errors, %d warning", this.errors, this.warnings);

+                else

+                    errorWarningElement.title = WebInspector.UIString("%d errors, %d warnings", this.errors, this.warnings);

+            } else if (this.errors == 1)

+                errorWarningElement.title = WebInspector.UIString("%d error", this.errors);

+            else

+                errorWarningElement.title = WebInspector.UIString("%d errors", this.errors);

+        } else if (this.warnings == 1)

+            errorWarningElement.title = WebInspector.UIString("%d warning", this.warnings);

+        else if (this.warnings)

+            errorWarningElement.title = WebInspector.UIString("%d warnings", this.warnings);

+        else

+            errorWarningElement.title = null;

+    },

+

+    get styleChanges()

+    {

+        return this._styleChanges;

+    },

+

+    set styleChanges(x)

+    {

+        x = Math.max(x, 0);

+

+        if (this._styleChanges === x)

+            return;

+        this._styleChanges = x;

+        this._updateChangesCount();

+    },

+

+    _updateChangesCount: function()

+    {

+        // TODO: Remove immediate return when enabling the Changes Panel

+        return;

+

+        var changesElement = document.getElementById("changes-count");

+        if (!changesElement)

+            return;

+

+        if (!this.styleChanges) {

+            changesElement.addStyleClass("hidden");

+            return;

+        }

+

+        changesElement.removeStyleClass("hidden");

+        changesElement.removeChildren();

+

+        if (this.styleChanges) {

+            var styleChangesElement = document.createElement("span");

+            styleChangesElement.id = "style-changes-count";

+            styleChangesElement.textContent = this.styleChanges;

+            changesElement.appendChild(styleChangesElement);

+        }

+

+        if (this.styleChanges) {

+            if (this.styleChanges === 1)

+                changesElement.title = WebInspector.UIString("%d style change", this.styleChanges);

+            else

+                changesElement.title = WebInspector.UIString("%d style changes", this.styleChanges);

+        }

+    },

+

+    get hoveredDOMNode()

+    {

+        return this._hoveredDOMNode;

+    },

+

+    set hoveredDOMNode(x)

+    {

+        if (this._hoveredDOMNode === x)

+            return;

+

+        this._hoveredDOMNode = x;

+

+        if (this._hoveredDOMNode)

+            this._updateHoverHighlightSoon(this.showingDOMNodeHighlight ? 50 : 500);

+        else

+            this._updateHoverHighlight();

+    },

+

+    _updateHoverHighlightSoon: function(delay)

+    {

+        if ("_updateHoverHighlightTimeout" in this)

+            clearTimeout(this._updateHoverHighlightTimeout);

+        this._updateHoverHighlightTimeout = setTimeout(this._updateHoverHighlight.bind(this), delay);

+    },

+

+    _updateHoverHighlight: function()

+    {

+        if ("_updateHoverHighlightTimeout" in this) {

+            clearTimeout(this._updateHoverHighlightTimeout);

+            delete this._updateHoverHighlightTimeout;

+        }

+

+        if (this._hoveredDOMNode) {

+            InspectorBackend.highlightDOMNode(this._hoveredDOMNode.id);

+            this.showingDOMNodeHighlight = true;

+        } else {

+            InspectorBackend.hideDOMNodeHighlight();

+            this.showingDOMNodeHighlight = false;

+        }

+    }

+}

+

+WebInspector.PlatformFlavor = {

+    WindowsVista: "windows-vista",

+    MacTiger: "mac-tiger",

+    MacLeopard: "mac-leopard",

+    MacSnowLeopard: "mac-snowleopard"

+}

+

+WebInspector.loaded = function()

+{

+    InspectorBackend.setInjectedScriptSource("(" + injectedScriptConstructor + ");");

+

+    var platform = WebInspector.platform;

+    document.body.addStyleClass("platform-" + platform);

+    var flavor = WebInspector.platformFlavor;

+    if (flavor)

+        document.body.addStyleClass("platform-" + flavor);

+    var port = WebInspector.port;

+    document.body.addStyleClass("port-" + port);

+

+    this.settings = new WebInspector.Settings();

+

+    this.drawer = new WebInspector.Drawer();

+    this.console = new WebInspector.ConsoleView(this.drawer);

+    // TODO: Uncomment when enabling the Changes Panel

+    // this.changes = new WebInspector.ChangesView(this.drawer);

+    // TODO: Remove class="hidden" from inspector.html on button#changes-status-bar-item

+    this.drawer.visibleView = this.console;

+    this.domAgent = new WebInspector.DOMAgent();

+

+    this.resourceCategories = {

+        documents: new WebInspector.ResourceCategory("documents", WebInspector.UIString("Documents"), "rgb(47,102,236)"),

+        stylesheets: new WebInspector.ResourceCategory("stylesheets", WebInspector.UIString("Stylesheets"), "rgb(157,231,119)"),

+        images: new WebInspector.ResourceCategory("images", WebInspector.UIString("Images"), "rgb(164,60,255)"),

+        scripts: new WebInspector.ResourceCategory("scripts", WebInspector.UIString("Scripts"), "rgb(255,121,0)"),

+        xhr: new WebInspector.ResourceCategory("xhr", WebInspector.UIString("XHR"), "rgb(231,231,10)"),

+        fonts: new WebInspector.ResourceCategory("fonts", WebInspector.UIString("Fonts"), "rgb(255,82,62)"),

+        other: new WebInspector.ResourceCategory("other", WebInspector.UIString("Other"), "rgb(186,186,186)")

+    };

+

+    this.panels = {};

+    this._createPanels();

+

+    var toolbarElement = document.getElementById("toolbar");

+    var previousToolbarItem = toolbarElement.children[0];

+

+    this.panelOrder = [];

+    for (var panelName in this.panels)

+        previousToolbarItem = WebInspector.addPanelToolbarIcon(toolbarElement, this.panels[panelName], previousToolbarItem);

+

+    this.Tips = {

+        ResourceNotCompressed: {id: 0, message: WebInspector.UIString("You could save bandwidth by having your web server compress this transfer with gzip or zlib.")}

+    };

+

+    this.Warnings = {

+        IncorrectMIMEType: {id: 0, message: WebInspector.UIString("Resource interpreted as %s but transferred with MIME type %s.")}

+    };

+

+    this.addMainEventListeners(document);

+

+    window.addEventListener("unload", this.windowUnload.bind(this), true);

+    window.addEventListener("resize", this.windowResize.bind(this), true);

+

+    document.addEventListener("focus", this.focusChanged.bind(this), true);

+    document.addEventListener("keydown", this.documentKeyDown.bind(this), false);

+    document.addEventListener("beforecopy", this.documentCanCopy.bind(this), true);

+    document.addEventListener("copy", this.documentCopy.bind(this), true);

+    document.addEventListener("contextmenu", this.contextMenuEventFired.bind(this), true);

+

+    var dockToggleButton = document.getElementById("dock-status-bar-item");

+    dockToggleButton.addEventListener("click", this.toggleAttach.bind(this), false);

+

+    if (this.attached)

+        dockToggleButton.title = WebInspector.UIString("Undock into separate window.");

+    else

+        dockToggleButton.title = WebInspector.UIString("Dock to main window.");

+

+    var errorWarningCount = document.getElementById("error-warning-count");

+    errorWarningCount.addEventListener("click", this.showConsole.bind(this), false);

+    this._updateErrorAndWarningCounts();

+

+    this.styleChanges = 0;

+    // TODO: Uncomment when enabling the Changes Panel

+    // var changesElement = document.getElementById("changes-count");

+    // changesElement.addEventListener("click", this.showChanges.bind(this), false);

+    // this._updateErrorAndWarningCounts();

+

+    var searchField = document.getElementById("search");

+    searchField.addEventListener("search", this.performSearch.bind(this), false); // when the search is emptied

+    searchField.addEventListener("mousedown", this._searchFieldManualFocus.bind(this), false); // when the search field is manually selected

+    searchField.addEventListener("keydown", this._searchKeyDown.bind(this), true);

+

+    toolbarElement.addEventListener("mousedown", this.toolbarDragStart, true);

+    document.getElementById("close-button-left").addEventListener("click", this.close, true);

+    document.getElementById("close-button-right").addEventListener("click", this.close, true);

+

+    InspectorFrontendHost.loaded();

+}

+

+WebInspector.addPanelToolbarIcon = function(toolbarElement, panel, previousToolbarItem)

+{

+    var panelToolbarItem = panel.toolbarItem;

+    this.panelOrder.push(panel);

+    panelToolbarItem.addEventListener("click", this._toolbarItemClicked.bind(this));

+    if (previousToolbarItem)

+        toolbarElement.insertBefore(panelToolbarItem, previousToolbarItem.nextSibling);

+    else

+        toolbarElement.insertBefore(panelToolbarItem, toolbarElement.firstChild);

+    return panelToolbarItem;

+}

+

+var windowLoaded = function()

+{

+    var localizedStringsURL = InspectorFrontendHost.localizedStringsURL();

+    if (localizedStringsURL) {

+        var localizedStringsScriptElement = document.createElement("script");

+        localizedStringsScriptElement.addEventListener("load", WebInspector.loaded.bind(WebInspector), false);

+        localizedStringsScriptElement.type = "text/javascript";

+        localizedStringsScriptElement.src = localizedStringsURL;

+        document.head.appendChild(localizedStringsScriptElement);

+    } else

+        WebInspector.loaded();

+

+    window.removeEventListener("load", windowLoaded, false);

+    delete windowLoaded;

+};

+

+window.addEventListener("load", windowLoaded, false);

+

+WebInspector.dispatch = function() {

+    var methodName = arguments[0];

+    var parameters = Array.prototype.slice.call(arguments, 1);

+

+    // We'd like to enforce asynchronous interaction between the inspector controller and the frontend.

+    // This is important to LayoutTests.

+    function delayDispatch()

+    {

+        WebInspector[methodName].apply(WebInspector, parameters);

+        WebInspector.pendingDispatches--;

+    }

+    WebInspector.pendingDispatches++;

+    setTimeout(delayDispatch, 0);

+}

+

+WebInspector.windowUnload = function(event)

+{

+    InspectorFrontendHost.windowUnloading();

+}

+

+WebInspector.windowResize = function(event)

+{

+    if (this.currentPanel)

+        this.currentPanel.resize();

+    this.drawer.resize();

+}

+

+WebInspector.windowFocused = function(event)

+{

+    // Fires after blur, so when focusing on either the main inspector

+    // or an <iframe> within the inspector we should always remove the

+    // "inactive" class.

+    if (event.target.document.nodeType === Node.DOCUMENT_NODE)

+        document.body.removeStyleClass("inactive");

+}

+

+WebInspector.windowBlurred = function(event)

+{

+    // Leaving the main inspector or an <iframe> within the inspector.

+    // We can add "inactive" now, and if we are moving the focus to another

+    // part of the inspector then windowFocused will correct this.

+    if (event.target.document.nodeType === Node.DOCUMENT_NODE)

+        document.body.addStyleClass("inactive");

+}

+

+WebInspector.focusChanged = function(event)

+{

+    this.currentFocusElement = event.target;

+}

+

+WebInspector.setAttachedWindow = function(attached)

+{

+    this.attached = attached;

+}

+

+WebInspector.close = function(event)

+{

+    InspectorFrontendHost.closeWindow();

+}

+

+WebInspector.documentMouseOver = function(event)

+{

+    if (event.target.tagName !== "A")

+        return;

+

+    const anchor = event.target;

+    if (!anchor.hasStyleClass("webkit-html-resource-link"))

+        return;

+    if (WebInspector.canShowSourceLine(anchor.href, anchor.lineNumber, anchor.preferredPanel) || WebInspector.ProfileType.URLRegExp.exec(anchor.href)) {

+        if (event.target.originalTitle)

+            event.target.title = event.target.originalTitle;

+        return;

+    }

+

+    if (!event.target.originalTitle)

+        event.target.originalTitle = event.target.title;

+    event.target.title = WebInspector.UIString("Cannot open this link. Make sure that resource tracking is enabled in the Resources panel.");

+}

+

+WebInspector.documentClick = function(event)

+{

+    var anchor = event.target.enclosingNodeOrSelfWithNodeName("a");

+    if (!anchor)

+        return;

+

+    // Prevent the link from navigating, since we don't do any navigation by following links normally.

+    event.preventDefault();

+

+    function followLink()

+    {

+        // FIXME: support webkit-html-external-link links here.

+        if (WebInspector.canShowSourceLine(anchor.href, anchor.lineNumber, anchor.preferredPanel)) {

+            if (anchor.hasStyleClass("webkit-html-external-link")) {

+                anchor.removeStyleClass("webkit-html-external-link");

+                anchor.addStyleClass("webkit-html-resource-link");

+            }

+

+            WebInspector.showSourceLine(anchor.href, anchor.lineNumber, anchor.preferredPanel);

+            return;

+        }

+

+        const profileMatch = WebInspector.ProfileType.URLRegExp.exec(anchor.href);

+        if (profileMatch) {

+            WebInspector.showProfileForURL(anchor.href);

+            return;

+        }

+

+        const urlMatch = WebInspector.GenericURLRegExp.exec(anchor.href);

+        if (urlMatch && urlMatch[1] === "webkit-link-action") {

+            if (urlMatch[2] === "show-panel") {

+                const panel = urlMatch[4].substring(1);

+                if (WebInspector.panels[panel])

+                    WebInspector.currentPanel = WebInspector.panels[panel];

+            }

+            return;

+        }

+    }

+

+    if (WebInspector.followLinkTimeout)

+        clearTimeout(WebInspector.followLinkTimeout);

+

+    if (anchor.preventFollowOnDoubleClick) {

+        // Start a timeout if this is the first click, if the timeout is canceled

+        // before it fires, then a double clicked happened or another link was clicked.

+        if (event.detail === 1)

+            WebInspector.followLinkTimeout = setTimeout(followLink, 333);

+        return;

+    }

+

+    followLink();

+}

+

+WebInspector.documentKeyDown = function(event)

+{

+    if (this.currentFocusElement && this.currentFocusElement.handleKeyEvent) {

+        this.currentFocusElement.handleKeyEvent(event);

+        if (event.handled) {

+            event.preventDefault();

+            return;

+        }

+    }

+

+    if (this.currentPanel && this.currentPanel.handleShortcut) {

+        this.currentPanel.handleShortcut(event);

+        if (event.handled) {

+            event.preventDefault();

+            return;

+        }

+    }

+

+    var isMac = WebInspector.isMac();

+

+    switch (event.keyIdentifier) {

+        case "U+001B": // Escape key

+            event.preventDefault();

+            if (this.drawer.fullPanel)

+                return;

+

+            this.drawer.visible = !this.drawer.visible;

+            break;

+

+        case "U+0046": // F key

+            if (isMac)

+                var isFindKey = event.metaKey && !event.ctrlKey && !event.altKey && !event.shiftKey;

+            else

+                var isFindKey = event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey;

+

+            if (isFindKey) {

+                WebInspector.focusSearchField();

+                event.preventDefault();

+            }

+            break;

+

+        case "F3":

+            if (!isMac) {

+                WebInspector.focusSearchField();

+                event.preventDefault();

+            }

+            break;

+

+        case "U+0047": // G key

+            if (isMac)

+                var isFindAgainKey = event.metaKey && !event.ctrlKey && !event.altKey;

+            else

+                var isFindAgainKey = event.ctrlKey && !event.metaKey && !event.altKey;

+

+            if (isFindAgainKey) {

+                if (event.shiftKey) {

+                    if (this.currentPanel.jumpToPreviousSearchResult)

+                        this.currentPanel.jumpToPreviousSearchResult();

+                } else if (this.currentPanel.jumpToNextSearchResult)

+                    this.currentPanel.jumpToNextSearchResult();

+                event.preventDefault();

+            }

+

+            break;

+

+        // Windows and Mac have two different definitions of [, so accept both.

+        case "U+005B":

+        case "U+00DB": // [ key

+            if (isMac)

+                var isRotateLeft = event.metaKey && !event.shiftKey && !event.ctrlKey && !event.altKey;

+            else

+                var isRotateLeft = event.ctrlKey && !event.shiftKey && !event.metaKey && !event.altKey;

+

+            if (isRotateLeft) {

+                var index = this.panelOrder.indexOf(this.currentPanel);

+                index = (index === 0) ? this.panelOrder.length - 1 : index - 1;

+                this.panelOrder[index].toolbarItem.click();

+                event.preventDefault();

+            }

+

+            break;

+

+        // Windows and Mac have two different definitions of ], so accept both.

+        case "U+005D":

+        case "U+00DD":  // ] key

+            if (isMac)

+                var isRotateRight = event.metaKey && !event.shiftKey && !event.ctrlKey && !event.altKey;

+            else

+                var isRotateRight = event.ctrlKey && !event.shiftKey && !event.metaKey && !event.altKey;

+

+            if (isRotateRight) {

+                var index = this.panelOrder.indexOf(this.currentPanel);

+                index = (index + 1) % this.panelOrder.length;

+                this.panelOrder[index].toolbarItem.click();

+                event.preventDefault();

+            }

+

+            break;

+

+        case "U+0052": // R key

+            if ((event.metaKey && isMac) || (event.ctrlKey && !isMac))

+                InspectorBackend.reloadPage();

+            break;

+        case "F5":

+            if (!isMac)

+                InspectorBackend.reloadPage();

+            break;

+    }

+}

+

+WebInspector.documentCanCopy = function(event)

+{

+    if (this.currentPanel && this.currentPanel.handleCopyEvent)

+        event.preventDefault();

+}

+

+WebInspector.documentCopy = function(event)

+{

+    if (this.currentPanel && this.currentPanel.handleCopyEvent)

+        this.currentPanel.handleCopyEvent(event);

+}

+

+WebInspector.contextMenuEventFired = function(event)

+{

+    if (event.handled || event.target.hasStyleClass("popup-glasspane"))

+        event.preventDefault();

+}

+

+WebInspector.animateStyle = function(animations, duration, callback)

+{

+    var interval;

+    var complete = 0;

+

+    const intervalDuration = (1000 / 30); // 30 frames per second.

+    const animationsLength = animations.length;

+    const propertyUnit = {opacity: ""};

+    const defaultUnit = "px";

+

+    function cubicInOut(t, b, c, d)

+    {

+        if ((t/=d/2) < 1) return c/2*t*t*t + b;

+        return c/2*((t-=2)*t*t + 2) + b;

+    }

+

+    // Pre-process animations.

+    for (var i = 0; i < animationsLength; ++i) {

+        var animation = animations[i];

+        var element = null, start = null, end = null, key = null;

+        for (key in animation) {

+            if (key === "element")

+                element = animation[key];

+            else if (key === "start")

+                start = animation[key];

+            else if (key === "end")

+                end = animation[key];

+        }

+

+        if (!element || !end)

+            continue;

+

+        if (!start) {

+            var computedStyle = element.ownerDocument.defaultView.getComputedStyle(element);

+            start = {};

+            for (key in end)

+                start[key] = parseInt(computedStyle.getPropertyValue(key));

+            animation.start = start;

+        } else

+            for (key in start)

+                element.style.setProperty(key, start[key] + (key in propertyUnit ? propertyUnit[key] : defaultUnit));

+    }

+

+    function animateLoop()

+    {

+        // Advance forward.

+        complete += intervalDuration;

+        var next = complete + intervalDuration;

+

+        // Make style changes.

+        for (var i = 0; i < animationsLength; ++i) {

+            var animation = animations[i];

+            var element = animation.element;

+            var start = animation.start;

+            var end = animation.end;

+            if (!element || !end)

+                continue;

+

+            var style = element.style;

+            for (key in end) {

+                var endValue = end[key];

+                if (next < duration) {

+                    var startValue = start[key];

+                    var newValue = cubicInOut(complete, startValue, endValue - startValue, duration);

+                    style.setProperty(key, newValue + (key in propertyUnit ? propertyUnit[key] : defaultUnit));

+                } else

+                    style.setProperty(key, endValue + (key in propertyUnit ? propertyUnit[key] : defaultUnit));

+            }

+        }

+

+        // End condition.

+        if (complete >= duration) {

+            clearInterval(interval);

+            if (callback)

+                callback();

+        }

+    }

+

+    interval = setInterval(animateLoop, intervalDuration);

+    return interval;

+}

+

+WebInspector.updateSearchLabel = function()

+{

+    if (!this.currentPanel)

+        return;

+

+    var newLabel = WebInspector.UIString("Search %s", this.currentPanel.toolbarItemLabel);

+    if (this.attached)

+        document.getElementById("search").setAttribute("placeholder", newLabel);

+    else {

+        document.getElementById("search").removeAttribute("placeholder");

+        document.getElementById("search-toolbar-label").textContent = newLabel;

+    }

+}

+

+WebInspector.focusSearchField = function()

+{

+    var searchField = document.getElementById("search");

+    searchField.focus();

+    searchField.select();

+}

+

+WebInspector.toggleAttach = function()

+{

+    if (!this.attached && !InspectorFrontendHost.canAttachWindow())

+        return;

+

+    this.attached = !this.attached;

+    this.drawer.resize();

+}

+

+WebInspector.toolbarDragStart = function(event)

+{

+    if ((!WebInspector.attached && WebInspector.platformFlavor !== WebInspector.PlatformFlavor.MacLeopard && WebInspector.platformFlavor !== WebInspector.PlatformFlavor.MacSnowLeopard) || WebInspector.port == "qt")

+        return;

+

+    var target = event.target;

+    if (target.hasStyleClass("toolbar-item") && target.hasStyleClass("toggleable"))

+        return;

+

+    var toolbar = document.getElementById("toolbar");

+    if (target !== toolbar && !target.hasStyleClass("toolbar-item"))

+        return;

+

+    toolbar.lastScreenX = event.screenX;

+    toolbar.lastScreenY = event.screenY;

+

+    WebInspector.elementDragStart(toolbar, WebInspector.toolbarDrag, WebInspector.toolbarDragEnd, event, (WebInspector.attached ? "row-resize" : "default"));

+}

+

+WebInspector.toolbarDragEnd = function(event)

+{

+    var toolbar = document.getElementById("toolbar");

+

+    WebInspector.elementDragEnd(event);

+

+    delete toolbar.lastScreenX;

+    delete toolbar.lastScreenY;

+}

+

+WebInspector.toolbarDrag = function(event)

+{

+    var toolbar = document.getElementById("toolbar");

+

+    if (WebInspector.attached) {

+        var height = window.innerHeight - (event.screenY - toolbar.lastScreenY);

+

+        InspectorFrontendHost.setAttachedWindowHeight(height);

+    } else {

+        var x = event.screenX - toolbar.lastScreenX;

+        var y = event.screenY - toolbar.lastScreenY;

+

+        // We cannot call window.moveBy here because it restricts the movement

+        // of the window at the edges.

+        InspectorFrontendHost.moveWindowBy(x, y);

+    }

+

+    toolbar.lastScreenX = event.screenX;

+    toolbar.lastScreenY = event.screenY;

+

+    event.preventDefault();

+}

+

+WebInspector.elementDragStart = function(element, dividerDrag, elementDragEnd, event, cursor)

+{

+    if (this._elementDraggingEventListener || this._elementEndDraggingEventListener)

+        this.elementDragEnd(event);

+

+    this._elementDraggingEventListener = dividerDrag;

+    this._elementEndDraggingEventListener = elementDragEnd;

+

+    document.addEventListener("mousemove", dividerDrag, true);

+    document.addEventListener("mouseup", elementDragEnd, true);

+

+    document.body.style.cursor = cursor;

+

+    event.preventDefault();

+}

+

+WebInspector.elementDragEnd = function(event)

+{

+    document.removeEventListener("mousemove", this._elementDraggingEventListener, true);

+    document.removeEventListener("mouseup", this._elementEndDraggingEventListener, true);

+

+    document.body.style.removeProperty("cursor");

+

+    delete this._elementDraggingEventListener;

+    delete this._elementEndDraggingEventListener;

+

+    event.preventDefault();

+}

+

+WebInspector.showConsole = function()

+{

+    this.drawer.showView(this.console);

+}

+

+WebInspector.showChanges = function()

+{

+    this.drawer.showView(this.changes);

+}

+

+WebInspector.showElementsPanel = function()

+{

+    this.currentPanel = this.panels.elements;

+}

+

+WebInspector.showResourcesPanel = function()

+{

+    this.currentPanel = this.panels.resources;

+}

+

+WebInspector.showScriptsPanel = function()

+{

+    this.currentPanel = this.panels.scripts;

+}

+

+WebInspector.showTimelinePanel = function()

+{

+    this.currentPanel = this.panels.timeline;

+}

+

+WebInspector.showProfilesPanel = function()

+{

+    this.currentPanel = this.panels.profiles;

+}

+

+WebInspector.showStoragePanel = function()

+{

+    this.currentPanel = this.panels.storage;

+}

+

+WebInspector.showConsolePanel = function()

+{

+    this.currentPanel = this.panels.console;

+}

+

+WebInspector.clearConsoleMessages = function()

+{

+    WebInspector.console.clearMessages();

+}

+

+WebInspector.selectDatabase = function(o)

+{

+    WebInspector.showStoragePanel();

+    WebInspector.panels.storage.selectDatabase(o);

+}

+

+WebInspector.selectDOMStorage = function(o)

+{

+    WebInspector.showStoragePanel();

+    WebInspector.panels.storage.selectDOMStorage(o);

+}

+

+WebInspector.updateResource = function(identifier, payload)

+{

+    var resource = this.resources[identifier];

+    if (!resource) {

+        resource = new WebInspector.Resource(identifier, payload.url);

+        this.resources[identifier] = resource;

+        this.resourceURLMap[resource.url] = resource;

+        if (this.panels.resources)

+            this.panels.resources.addResource(resource);

+    }

+

+    if (payload.didRequestChange) {

+        resource.domain = payload.host;

+        resource.path = payload.path;

+        resource.lastPathComponent = payload.lastPathComponent;

+        resource.requestHeaders = payload.requestHeaders;

+        resource.mainResource = payload.mainResource;

+        resource.requestMethod = payload.requestMethod;

+        resource.requestFormData = payload.requestFormData;

+        resource.cached = payload.cached;

+        resource.documentURL = payload.documentURL;

+

+        if (resource.mainResource)

+            this.mainResource = resource;

+

+        var match = payload.documentURL.match(WebInspector.URLRegExp);

+        if (match) {

+            var protocol = match[1].toLowerCase();

+            if (protocol.indexOf("http") === 0 || protocol === "file")

+                this._addCookieDomain(protocol === "file" ? "" : match[2]);

+        }

+    }

+

+    if (payload.didResponseChange) {

+        resource.mimeType = payload.mimeType;

+        resource.suggestedFilename = payload.suggestedFilename;

+        resource.expectedContentLength = payload.expectedContentLength;

+        resource.statusCode = payload.statusCode;

+        resource.suggestedFilename = payload.suggestedFilename;

+        resource.responseHeaders = payload.responseHeaders;

+    }

+

+    if (payload.didTypeChange) {

+        resource.type = payload.type;

+    }

+

+    if (payload.didLengthChange) {

+        resource.resourceSize = payload.resourceSize;

+    }

+

+    if (payload.didCompletionChange) {

+        resource.failed = payload.failed;

+        resource.finished = payload.finished;

+    }

+

+    if (payload.didTimingChange) {

+        if (payload.startTime)

+            resource.startTime = payload.startTime;

+        if (payload.responseReceivedTime)

+            resource.responseReceivedTime = payload.responseReceivedTime;

+        if (payload.endTime)

+            resource.endTime = payload.endTime;

+

+        if (payload.loadEventTime) {

+            // This loadEventTime is for the main resource, and we want to show it

+            // for all resources on this page. This means we want to set it as a member

+            // of the resources panel instead of the individual resource.

+            if (this.panels.resources)

+                this.panels.resources.mainResourceLoadTime = payload.loadEventTime;

+            if (this.panels.audits)

+                this.panels.audits.mainResourceLoadTime = payload.loadEventTime;

+        }

+

+        if (payload.domContentEventTime) {

+            // This domContentEventTime is for the main resource, so it should go in

+            // the resources panel for the same reasons as above.

+            if (this.panels.resources)

+                this.panels.resources.mainResourceDOMContentTime = payload.domContentEventTime;

+            if (this.panels.audits)

+                this.panels.audits.mainResourceDOMContentTime = payload.domContentEventTime;

+        }

+    }

+}

+

+WebInspector.removeResource = function(identifier)

+{

+    var resource = this.resources[identifier];

+    if (!resource)

+        return;

+

+    resource.category.removeResource(resource);

+    delete this.resourceURLMap[resource.url];

+    delete this.resources[identifier];

+

+    if (this.panels.resources)

+        this.panels.resources.removeResource(resource);

+}

+

+WebInspector.addDatabase = function(payload)

+{

+    if (!this.panels.storage)

+        return;

+    var database = new WebInspector.Database(

+        payload.id,

+        payload.domain,

+        payload.name,

+        payload.version);

+    this.panels.storage.addDatabase(database);

+}

+

+WebInspector._addCookieDomain = function(domain)

+{

+    // Eliminate duplicate domains from the list.

+    if (domain in this.cookieDomains)

+        return;

+    this.cookieDomains[domain] = true;

+

+    if (!this.panels.storage)

+        return;

+    this.panels.storage.addCookieDomain(domain);

+}

+

+WebInspector.addDOMStorage = function(payload)

+{

+    if (!this.panels.storage)

+        return;

+    var domStorage = new WebInspector.DOMStorage(

+        payload.id,

+        payload.host,

+        payload.isLocalStorage);

+    this.panels.storage.addDOMStorage(domStorage);

+}

+

+WebInspector.updateDOMStorage = function(storageId)

+{

+    if (!this.panels.storage)

+        return;

+    this.panels.storage.updateDOMStorage(storageId);

+}

+

+WebInspector.resourceTrackingWasEnabled = function()

+{

+    this.panels.resources.resourceTrackingWasEnabled();

+}

+

+WebInspector.resourceTrackingWasDisabled = function()

+{

+    this.panels.resources.resourceTrackingWasDisabled();

+}

+

+

+WebInspector.searchingForNodeWasEnabled = function()

+{

+    this.panels.elements.searchingForNodeWasEnabled();

+}

+

+WebInspector.searchingForNodeWasDisabled = function()

+{

+    this.panels.elements.searchingForNodeWasDisabled();

+}

+

+WebInspector.attachDebuggerWhenShown = function()

+{

+    this.panels.scripts.attachDebuggerWhenShown();

+}

+

+WebInspector.debuggerWasEnabled = function()

+{

+    this.panels.scripts.debuggerWasEnabled();

+}

+

+WebInspector.updatePauseOnExceptionsState = function(pauseOnExceptionsState)

+{

+    this.panels.scripts.updatePauseOnExceptionsState(pauseOnExceptionsState);

+}

+

+WebInspector.debuggerWasDisabled = function()

+{

+    this.panels.scripts.debuggerWasDisabled();

+}

+

+WebInspector.profilerWasEnabled = function()

+{

+    this.panels.profiles.profilerWasEnabled();

+}

+

+WebInspector.profilerWasDisabled = function()

+{

+    this.panels.profiles.profilerWasDisabled();

+}

+

+WebInspector.parsedScriptSource = function(sourceID, sourceURL, source, startingLine)

+{

+    this.panels.scripts.addScript(sourceID, sourceURL, source, startingLine);

+}

+

+WebInspector.restoredBreakpoint = function(sourceID, sourceURL, line, enabled, condition)

+{

+    var breakpoint = new WebInspector.Breakpoint(sourceURL, line, sourceID, condition);

+    breakpoint.enabled = enabled;

+    this.panels.scripts.addBreakpoint(breakpoint);

+}

+

+WebInspector.failedToParseScriptSource = function(sourceURL, source, startingLine, errorLine, errorMessage)

+{

+    this.panels.scripts.addScript(null, sourceURL, source, startingLine, errorLine, errorMessage);

+}

+

+WebInspector.pausedScript = function(callFrames)

+{

+    this.panels.scripts.debuggerPaused(callFrames);

+}

+

+WebInspector.resumedScript = function()

+{

+    this.panels.scripts.debuggerResumed();

+}

+

+WebInspector.populateInterface = function()

+{

+    for (var panelName in this.panels) {

+        var panel = this.panels[panelName];

+        if ("populateInterface" in panel)

+            panel.populateInterface();

+    }

+}

+

+WebInspector.reset = function()

+{

+    for (var panelName in this.panels) {

+        var panel = this.panels[panelName];

+        if ("reset" in panel)

+            panel.reset();

+    }

+

+    for (var category in this.resourceCategories)

+        this.resourceCategories[category].removeAllResources();

+

+    this.resources = {};

+    this.resourceURLMap = {};

+    this.cookieDomains = {};

+    this.hoveredDOMNode = null;

+

+    delete this.mainResource;

+

+    this.console.clearMessages();

+}

+

+WebInspector.resourceURLChanged = function(resource, oldURL)

+{

+    delete this.resourceURLMap[oldURL];

+    this.resourceURLMap[resource.url] = resource;

+}

+

+WebInspector.didCommitLoad = function()

+{

+    // Cleanup elements panel early on inspected page refresh.

+    WebInspector.setDocument(null);

+}

+

+WebInspector.updateConsoleMessageExpiredCount = function(count)

+{

+    var message = String.sprintf(WebInspector.UIString("%d console messages are not shown."), count);

+    WebInspector.console.addMessage(new WebInspector.ConsoleTextMessage(message, WebInspector.ConsoleMessage.MessageLevel.Warning));

+}

+

+WebInspector.addConsoleMessage = function(payload, opt_args)

+{

+    var consoleMessage = new WebInspector.ConsoleMessage(

+        payload.source,

+        payload.type,

+        payload.level,

+        payload.line,

+        payload.url,

+        payload.groupLevel,

+        payload.repeatCount);

+    consoleMessage.setMessageBody(Array.prototype.slice.call(arguments, 1));

+    this.console.addMessage(consoleMessage);

+}

+

+WebInspector.updateConsoleMessageRepeatCount = function(count)

+{

+    this.console.updateMessageRepeatCount(count);

+}

+

+WebInspector.log = function(message)

+{

+    // remember 'this' for setInterval() callback

+    var self = this;

+

+    // return indication if we can actually log a message

+    function isLogAvailable()

+    {

+        return WebInspector.ConsoleMessage && WebInspector.ObjectProxy && self.console;

+    }

+

+    // flush the queue of pending messages

+    function flushQueue()

+    {

+        var queued = WebInspector.log.queued;

+        if (!queued)

+            return;

+

+        for (var i = 0; i < queued.length; ++i)

+            logMessage(queued[i]);

+

+        delete WebInspector.log.queued;

+    }

+

+    // flush the queue if it console is available

+    // - this function is run on an interval

+    function flushQueueIfAvailable()

+    {

+        if (!isLogAvailable())

+            return;

+

+        clearInterval(WebInspector.log.interval);

+        delete WebInspector.log.interval;

+

+        flushQueue();

+    }

+

+    // actually log the message

+    function logMessage(message)

+    {

+        var repeatCount = 1;

+        if (message == WebInspector.log.lastMessage)

+            repeatCount = WebInspector.log.repeatCount + 1;

+

+        WebInspector.log.lastMessage = message;

+        WebInspector.log.repeatCount = repeatCount;

+

+        // ConsoleMessage expects a proxy object

+        message = new WebInspector.ObjectProxy(null, null, [], message, false);

+

+        // post the message

+        var msg = new WebInspector.ConsoleMessage(

+            WebInspector.ConsoleMessage.MessageSource.Other,

+            WebInspector.ConsoleMessage.MessageType.Log,

+            WebInspector.ConsoleMessage.MessageLevel.Debug,

+            -1,

+            null,

+            null,

+            repeatCount,

+            message);

+

+        self.console.addMessage(msg);

+    }

+

+    // if we can't log the message, queue it

+    if (!isLogAvailable()) {

+        if (!WebInspector.log.queued)

+            WebInspector.log.queued = [];

+

+        WebInspector.log.queued.push(message);

+

+        if (!WebInspector.log.interval)

+            WebInspector.log.interval = setInterval(flushQueueIfAvailable, 1000);

+

+        return;

+    }

+

+    // flush the pending queue if any

+    flushQueue();

+

+    // log the message

+    logMessage(message);

+}

+

+WebInspector.addProfileHeader = function(profile)

+{

+    this.panels.profiles.addProfileHeader(profile);

+}

+

+WebInspector.setRecordingProfile = function(isProfiling)

+{

+    this.panels.profiles.getProfileType(WebInspector.CPUProfileType.TypeId).setRecordingProfile(isProfiling);

+    this.panels.profiles.updateProfileTypeButtons();

+}

+

+WebInspector.drawLoadingPieChart = function(canvas, percent) {

+    var g = canvas.getContext("2d");

+    var darkColor = "rgb(122, 168, 218)";

+    var lightColor = "rgb(228, 241, 251)";

+    var cx = 8;

+    var cy = 8;

+    var r = 7;

+

+    g.beginPath();

+    g.arc(cx, cy, r, 0, Math.PI * 2, false);

+    g.closePath();

+

+    g.lineWidth = 1;

+    g.strokeStyle = darkColor;

+    g.fillStyle = lightColor;

+    g.fill();

+    g.stroke();

+

+    var startangle = -Math.PI / 2;

+    var endangle = startangle + (percent * Math.PI * 2);

+

+    g.beginPath();

+    g.moveTo(cx, cy);

+    g.arc(cx, cy, r, startangle, endangle, false);

+    g.closePath();

+

+    g.fillStyle = darkColor;

+    g.fill();

+}

+

+WebInspector.updateFocusedNode = function(nodeId)

+{

+    var node = WebInspector.domAgent.nodeForId(nodeId);

+    if (!node)

+        // FIXME: Should we deselect if null is passed in?

+        return;

+

+    this.currentPanel = this.panels.elements;

+    this.panels.elements.focusedDOMNode = node;

+}

+

+WebInspector.displayNameForURL = function(url)

+{